<commit_before>(function (w, d) {

  //I'm gona use this collection.
  var tasks = new Backbone.Collection();
  tasks.add([
    {
      id: 1,
      title: 'Try Backbone',
      completed: false
    },
    {
      id: 2,
      title: 'Go to buy some clothes',
      completed: false
    },
    {
      id: 3,
      title: 'Learn English',
      completed: false
    }
  ]);

  //foreach is for iterate over collections.

  //It should log a list of al my tasks!!
  tasks.forEach(function(model) {
    console.log('Task title: ' + model.get('title'));
  });

  //sortBy(): Sort a collection on a attribute.

  var sortedAlphabetically = tasks.sortBy(function(todo) {
    return todo.get("title").toLowerCase();
  });

  console.log("------ Collection should be sorted by alphabet now. ----");

  sortedAlphabetically.forEach(function(model) {
    console.log(model.get('title'));
  });

  //map: Iterates over a collection, and maps each value through a transformation function.
  var count = 1;
  console.log(tasks.map(function(model){
    return count++ + ". " + model.get('title');
  }));

  //min / max : Gets the item with min or max value for a property of the model.
  var lastItem = tasks.max(function(model) {
    return model.id
  }).id;
  var firstItem = tasks.min(function(model) {
    return model.id
  }).id;

  console.log('Max: ' + lastItem);
  console.log('Min: ' + firstItem);

  //Pluck: Returns an array with a specific property in all the arrays
  console.log(tasks.pluck('title'));

})(window, document);
<commit_msg>Im wont try all the Underscore methods<commit_after>(function (w, d) {

  var TasksList = Backbone.Collection.extend({
    filterById: function(ids){
      return this.filter(
        function(c) {
          return _.contains(ids, c.id);
        })
    }
  });

  //I'm gona use this collection.
  var tasks = new TasksList();
  tasks.add([
    {
      id: 1,
      title: 'Try Backbone',
      completed: false
    },
    {
      id: 2,
      title: 'Go to buy some clothes',
      completed: false
    },
    {
      id: 3,
      title: 'Learn English',
      completed: false
    }
  ]);

  //foreach is for iterate over collections.

  //It should log a list of al my tasks!!
  tasks.forEach(function(model) {
    console.log('Task title: ' + model.get('title'));
  });

  //sortBy(): Sort a collection on a attribute.

  var sortedAlphabetically = tasks.sortBy(function(todo) {
    return todo.get("title").toLowerCase();
  });

  console.log("------ Collection should be sorted by alphabet now. ----");

  sortedAlphabetically.forEach(function(model) {
    console.log(model.get('title'));
  });

  //map: Iterates over a collection, and maps each value through a transformation function.
  var count = 1;
  console.log(tasks.map(function(model){
    return count++ + ". " + model.get('title');
  }));

  //min / max : Gets the item with min or max value for a property of the model.
  var lastItem = tasks.max(function(model) {
    return model.id
  }).id;
  var firstItem = tasks.min(function(model) {
    return model.id
  }).id;

  console.log('Max: ' + lastItem);
  console.log('Min: ' + firstItem);

  //Pluck: Returns an array with a specific property in all the arrays
  console.log(tasks.pluck('title'));

  //Filter(): Must to take another look at how it works!!
  debugger;
  console.log(tasks.filterById());

})(window, document);
<|endoftext|>


<commit_before>/* eslint-disable import/prefer-default-export */
/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';

import { LANGUAGE_CODES } from '../localization/index';

import { KiribatiFlag, EnglishFlag, LaosFlag, TetumFlag, FrenchFlag } from './images';

const LANGUAGE_TO_FLAG = {
  [LANGUAGE_CODES.FRENCH]: FrenchFlag,
  [LANGUAGE_CODES.TETUM]: TetumFlag,
  [LANGUAGE_CODES.ENGLISH]: EnglishFlag,
  [LANGUAGE_CODES.KIRIBATI]: KiribatiFlag,
  [LANGUAGE_CODES.LAOS]: LaosFlag,
};

export const Flag = ({ style, flag }) => {
  const FlagImage = LANGUAGE_TO_FLAG[flag];
  return <FlagImage style={style} />;
};

Flag.defaultProps = { style: { width: 55, height: 33 } };
Flag.propTypes = { style: PropTypes.object, flag: PropTypes.string.isRequired };
<commit_msg>Add Flag doc string<commit_after>/* eslint-disable import/prefer-default-export */
/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';

import { LANGUAGE_CODES } from '../localization/index';

import { KiribatiFlag, EnglishFlag, LaosFlag, TetumFlag, FrenchFlag } from './images';

const LANGUAGE_TO_FLAG = {
  [LANGUAGE_CODES.FRENCH]: FrenchFlag,
  [LANGUAGE_CODES.TETUM]: TetumFlag,
  [LANGUAGE_CODES.ENGLISH]: EnglishFlag,
  [LANGUAGE_CODES.KIRIBATI]: KiribatiFlag,
  [LANGUAGE_CODES.LAOS]: LaosFlag,
};

/**
 * Simple component rendering a flag image given the country code.
 * See localization/index - LANGUAGE_CODES
 *
 * @param {Object} Style       Style object for the flag Image component
 * @param {String} countryCode The country code whose flag should be used.
 */
export const Flag = ({ style, countryCode }) => {
  const FlagImage = LANGUAGE_TO_FLAG[countryCode];
  return <FlagImage style={style} />;
};

Flag.defaultProps = { style: { width: 55, height: 33 } };
Flag.propTypes = { style: PropTypes.object, countryCode: PropTypes.string.isRequired };
<|endoftext|>


<commit_before>/* jshint devel:true */
  var containerTop = [];
  var mainHeight = [];
  var sideHeight = [];
  var bodyHeight;
  var gNavOffsetY;
  var gNavHeight = 44;
  var defaultPadding = 30;
  var hasSideWidth = 690;
  var sectionsWithSide = document.querySelectorAll('.block-container.has-side');
  var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  var delegate;
  var htmlClass = document.documentElement.className;
  var sectionsWithSideLength = sectionsWithSide.length;
  var sectionClassName = [];
  var sectionClassNameNew = [];
  var minHeight = [];
  var maxHeight = [];
  var isRetinaDevice = (window.devicePixelRatio > 1);
  var scrollTop = window.scrollY || document.documentElement.scrollTop;
  var ticking = false;

  function findTop(obj) {
    var curtop = 0;
    if (obj.offsetParent) {
      do {
        curtop += obj.offsetTop;
      } while ((obj = obj.offsetParent));
      return curtop;
    }
  }

  function getBodyHeight() {
    var w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    y = w.innerHeight|| e.clientHeight|| g.clientHeight;
    return y;
  }

  function stickyAdsPrepare() {
    if (typeof stickyAds === 'object' && stickyAds.length>0) {
      for(var i=0; i<stickyAds.length; i++) {
        var thePlaceHolder = document.getElementById(stickyAds[i].BannerId).parentNode.parentNode.parentNode.parentNode;
        var theContainer = document.getElementById(stickyAds[i].BannerId).parentNode.parentNode.parentNode;
        stickyAds[i].oTop = findTop(thePlaceHolder);
        stickyAds[i].currentClass = theContainer.className;
      }
      //console.log (stickyAds);
    }
  }

  // {
  //       'BannerId': parentId,
  //       'stickyHeight': stickyHeight
  //   }

  function stickyBottomPrepare() {
    gNavOffsetY = findTop(document.getElementById('nav-place-holder'));
    bodyHeight = getBodyHeight();
    w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    if (sectionsWithSide.length > 0) {
      for (var i=0; i<sectionsWithSide.length; i++) {
        containerTop[i] = findTop(sectionsWithSide[i]);
        mainHeight[i] = sectionsWithSide[i].querySelector('.content-inner').offsetHeight;
        sideHeight[i] = sectionsWithSide[i].querySelector('.side-inner').offsetHeight + defaultPadding;
        sectionClassName[i] = sectionsWithSide[i].className;
        minHeight[i] = Math.min(mainHeight[i], sideHeight[i]);
        maxHeight[i] = Math.max(mainHeight[i], sideHeight[i]);
        //sectionsWithSide[i].querySelector('.side-inner').style.backgroundColor = 'grey';
      }
    }
  }

  function stickyBottomUpdate() {
    requestAnimationFrame(stickyBottomUpdate);
    if (scrollTop >= gNavOffsetY) {
      if (htmlClass.indexOf(' is-sticky')<0) {
        htmlClass += ' is-sticky';
        document.documentElement.className = htmlClass;
      }
    } else {
      if (htmlClass.indexOf(' is-sticky')>=0) {
        htmlClass = htmlClass.replace(/ is-sticky/g, '');
        document.documentElement.className = htmlClass;
      }
    }
    if (sectionsWithSideLength > 0 && w > hasSideWidth) {
      for (var i=0; i<sectionsWithSideLength; i++) {
        sectionClassNameNew[i] = sectionClassName[i].replace(/fixmain|fixside|bottommain|bottomside/g,'');
        var maxScroll = containerTop[i] + maxHeight[i] - bodyHeight - scrollTop;
        var minScroll = containerTop[i] + minHeight[i] - bodyHeight - scrollTop;
        //console.log (i + ': ' + maxScroll + '/' + minScroll);
        if (minHeight[i] < bodyHeight || maxHeight[i] - minHeight[i] < 100) {
          // do nothing
        } else if (mainHeight[i]>sideHeight[i]) {
          if (maxScroll<=0) {
            sectionClassNameNew[i] += ' bottomside';
          } else if (minScroll<=0 ) {
            sectionClassNameNew[i] += ' fixside';
          }
        } else if (mainHeight[i]<sideHeight[i]) {
          if (maxScroll<30) {
            sectionClassNameNew[i] += ' bottommain';
          } else if (minScroll<0){
            sectionClassNameNew[i] += ' fixmain';
          }
        }
        sectionClassNameNew[i] = sectionClassNameNew[i].replace(/[\s]+/g,' ');
        if (sectionClassNameNew[i] !== sectionClassName[i]) {
          sectionClassName[i] = sectionClassNameNew[i];
          sectionsWithSide[i].className = sectionClassNameNew[i];
          //console.log (sectionClassName[i]);
        }
      }
    }
    if (typeof stickyAds === 'object' && stickyAds.length >0) {
      for (var j=0; j<stickyAds.length; j++) {
        var oTop = stickyAds[j].oTop - scrollTop - gNavHeight;
        var oTop2 = oTop + stickyAds[j].stickyHeight;
        var newClass = '';
        if (oTop <= 0 && oTop2 >0) {
          newClass = ' is-fix';
        } else {
          newClass = '';
        }
        newClass = 'banner-container' + newClass;
        //console.log (newClass + '/' + stickyAds[i].currentClass + '/' + document.getElementById(stickyAds[i].BannerId).parentNode.parentNode.className);

        if (newClass !== stickyAds[j].currentClass) {
          stickyAds[j].currentClass = newClass;
          document.getElementById(stickyAds[j].BannerId).parentNode.parentNode.parentNode.className = newClass;
        }

      }

    }
  }

  function requestTick() {
    if(!ticking) {
      requestAnimationFrame(stickyBottomUpdate);
    }
    ticking = true;
  }

  function stickyBottom() {
    scrollTop = window.scrollY || document.documentElement.scrollTop;
    requestTick();
  }

  try {
    delegate = new Delegate(document.body);
  } catch (ignore) {

  }

  // listent to scrolling events
  gNavOffsetY = findTop(document.getElementById('nav-place-holder'));
  if (gNavOffsetY > 30 && w > 490) {
    try {
      stickyBottomPrepare();
      stickyAdsPrepare();
      var addEvent =  window.attachEvent||window.addEventListener;
      var eventScroll = window.attachEvent ? 'onscroll' : 'scroll';
      var eventResize = window.attachEvent ? 'onresize' : 'resize';
      addEvent(eventScroll, function(){
          stickyBottom();
      });
      addEvent(eventResize, function(){
          stickyBottomPrepare();
          stickyAdsPrepare();
      });
      setInterval(function(){
          stickyBottomPrepare();
          stickyAdsPrepare();
      }, 10000);
    } catch (ignore) {

    }
  }

  // check svg support
  // SVG is default, no-svg is exception
  if (typeof SVGRect === 'undefined') {
    document.documentElement.className += ' no-svg';
  }

  // load responsive images
  var figures = document.querySelectorAll('figure.loading');
  for (var i=0; i<figures.length; i++) {
    var thisFigure = figures[i];
    var imageWidth = thisFigure.offsetWidth;
    var imageHeight = thisFigure.offsetHeight;
    var imageUrl = thisFigure.getAttribute('data-url');
    var figureClass = thisFigure.className || '';
    var fitType = 'cover';
    var figureParentClass = thisFigure.parentNode.className || '';
    if (isRetinaDevice === true) {
      imageWidth = imageWidth * 2;
      imageHeight = imageHeight * 2;
    }
    if (/brand/.test(figureParentClass)) {
      fitType = 'contain';
    }
    if (/sponsor/.test(figureClass)) {
      imageUrl = imageUrl.replace('i.ftimg.net', 'i.ftmailbox.com');
      imageUrl = encodeURIComponent(imageUrl);
      imageUrl = 'https://image.webservices.ft.com/v1/images/raw/' + imageUrl + '?source=ftchinese&height=' + imageHeight + '&fit=' + fitType;
      thisFigure.innerHTML = '';
      thisFigure.className = '';
    } else if (imageWidth > 0 && imageHeight > 0) {
      imageUrl = imageUrl.replace('i.ftimg.net', 'i.ftmailbox.com');
      imageUrl = encodeURIComponent(imageUrl);
      imageUrl = 'https://image.webservices.ft.com/v1/images/raw/' + imageUrl + '?source=ftchinese&width=' + imageWidth + '&height=' + imageHeight + '&fit=' + fitType;
      thisFigure.innerHTML = '';
      thisFigure.className = '';
    }
  }

  // load responsive videos
  var videos = document.querySelectorAll('figure.loading-video');
  var hostForVideo = '';
  if (window.location.hostname === 'localhost' || window.location.hostname.indexOf('192.168') === 0 || window.location.hostname.indexOf('10.113') === 0 || window.location.hostname.indexOf('127.0') === 0) {
    hostForVideo = 'http://www.ftchinese.com';
  }
  for (var i=0; i<videos.length; i++) {
    var thisVideo = videos[i];
    var videoWidth = thisVideo.offsetWidth;
    var videoHeight = thisVideo.offsetHeight;
    var videoId = thisVideo.getAttribute('data-vid');
    if (videoWidth > 0 && videoHeight > 0) {
      //console.log (videoId + ' Height: ' + videoHeight + ' Width: ' + videoWidth);
      thisVideo.innerHTML = '';
      thisFigure.className = '';
    }
  }

  //A cool trick to handle images that fail to load:
  try {
    delegate.on('error', 'img', function(){
      this.style.display = 'none';
    });
  } catch (ignore) {

  }

  // click events
  try {
    delegate.on('click', '.video-package .XL2 a.image', function(){
      var link = hostForVideo + this.getAttribute('href');
      var videoPackage = this.parentNode.parentNode.parentNode;
      var videoEle = videoPackage.querySelector('#video-package-play');
      var videoWidth = videoEle.offsetWidth;
      var videoHeight = videoEle.offsetHeight;
      var thisItemEle = this.parentNode.parentNode;
      var thisHeadline = thisItemEle.querySelector('.item-headline a').innerHTML;
      var allVideos = this.parentNode.parentNode.parentNode.querySelectorAll('.video-package .XL2');
      for (var i=0; i<allVideos.length; i++) {
        var thisClassName = allVideos[i].className;
        if (thisClassName.indexOf(' on')>=0) {
          thisClassName = thisClassName.replace(' on', '');
          allVideos[i].className = thisClassName;
        }
      }
      this.parentNode.parentNode.className += ' on';
      videoEle.querySelector('iframe').src = link  +'?i=2&k=1&w='+videoWidth+'&h='+videoHeight+'&autostart=true';
      videoPackage.querySelector('.video-package-title a').innerHTML = thisHeadline;
      videoPackage.querySelector('.video-package-title a').href = link;
      return false;
    });
  } catch (ignore) {

  }

/* jshint devel:true */
/****dolphin广告****/
//参数依次为
//位置ID
//频道ID
//DOM节点ID(script选填，script方式不需要NodeID，采用document.write)
//iframe宽高（选填，不传这两个参数将添加script广告）
/*
function dolphinAD(pID,cID,NodeID,w,h){
    var adCode;
    if(!pID){
        return "positionID missing";
    }
    if(!cID){
        return "channelID missing";
    }
    if(w&&h){//iframe方式
        if(!w){
            return "width missing";
        }
        if(!h){
            return "height missing";
        }
        //adCode = '';
        adCode = '';
        if (document.getElementById(NodeID)){
            document.getElementById(NodeID).innerHTML=adCode;
            return adCode;
        }
        return "node missing";
    }
    //script 方式
    try {
        adCode = '<scr'+'ipt type="text/javascript" src="http://dolphin.ftimg.net/s?z=ft&c='+cID+pID+slotStr+adReachability()+'" charset="gbk" ></scr'+'ipt>';
        document.write(adCode);
    } catch (err) {
        var k=err.toString();
        ga('send','event', 'CatchError', 'AD', pId + '' + cID + ':' + k, {'nonInteraction':1});
    }
    return adCode;
}

function setDolphinSlot(key){
  //定义slot随机数实现联动互斥功能
  var rString = window.dolRand?"&slot="+window.dolRand:"",
      cString = GetCookie(key),
      x;
  if(!cString){return rString;}
  window.cArray = cString.split(";");
  for(x in window.cArray){
      if (window.cArray.hasOwnProperty(x)) {
          window.cArray[x]=window.cArray[x].replace("|","=");
          rString += "&_"+window.cArray[x];
      }
  }
  return rString;
}
*/<commit_msg>fall back to scroll when requestAnimationFrame is not supported<commit_after>/* jshint devel:true */
  var containerTop = [];
  var mainHeight = [];
  var sideHeight = [];
  var bodyHeight;
  var gNavOffsetY;
  var gNavHeight = 44;
  var defaultPadding = 30;
  var hasSideWidth = 690;
  var sectionsWithSide = document.querySelectorAll('.block-container.has-side');
  var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  var delegate;
  var htmlClass = document.documentElement.className;
  var sectionsWithSideLength = sectionsWithSide.length;
  var sectionClassName = [];
  var sectionClassNameNew = [];
  var minHeight = [];
  var maxHeight = [];
  var isRetinaDevice = (window.devicePixelRatio > 1);
  var scrollTop = window.scrollY || document.documentElement.scrollTop;
  var ticking = false;

  function findTop(obj) {
    var curtop = 0;
    if (obj.offsetParent) {
      do {
        curtop += obj.offsetTop;
      } while ((obj = obj.offsetParent));
      return curtop;
    }
  }

  function getBodyHeight() {
    var w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    y = w.innerHeight|| e.clientHeight|| g.clientHeight;
    return y;
  }

  function stickyAdsPrepare() {
    if (typeof stickyAds === 'object' && stickyAds.length>0) {
      for(var i=0; i<stickyAds.length; i++) {
        var thePlaceHolder = document.getElementById(stickyAds[i].BannerId).parentNode.parentNode.parentNode.parentNode;
        var theContainer = document.getElementById(stickyAds[i].BannerId).parentNode.parentNode.parentNode;
        stickyAds[i].oTop = findTop(thePlaceHolder);
        stickyAds[i].currentClass = theContainer.className;
      }
      //console.log (stickyAds);
    }
  }

  // {
  //       'BannerId': parentId,
  //       'stickyHeight': stickyHeight
  //   }

  function stickyBottomPrepare() {
    gNavOffsetY = findTop(document.getElementById('nav-place-holder'));
    bodyHeight = getBodyHeight();
    w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    if (sectionsWithSide.length > 0) {
      for (var i=0; i<sectionsWithSide.length; i++) {
        containerTop[i] = findTop(sectionsWithSide[i]);
        mainHeight[i] = sectionsWithSide[i].querySelector('.content-inner').offsetHeight;
        sideHeight[i] = sectionsWithSide[i].querySelector('.side-inner').offsetHeight + defaultPadding;
        sectionClassName[i] = sectionsWithSide[i].className;
        minHeight[i] = Math.min(mainHeight[i], sideHeight[i]);
        maxHeight[i] = Math.max(mainHeight[i], sideHeight[i]);
        //sectionsWithSide[i].querySelector('.side-inner').style.backgroundColor = 'grey';
      }
    }
  }

  function stickyBottomUpdate() {
    if (typeof requestAnimationFrame === 'function') {
      requestAnimationFrame(stickyBottomUpdate);
    }
    if (scrollTop >= gNavOffsetY) {
      if (htmlClass.indexOf(' is-sticky')<0) {
        htmlClass += ' is-sticky';
        document.documentElement.className = htmlClass;
      }
    } else {
      if (htmlClass.indexOf(' is-sticky')>=0) {
        htmlClass = htmlClass.replace(/ is-sticky/g, '');
        document.documentElement.className = htmlClass;
      }
    }
    if (sectionsWithSideLength > 0 && w > hasSideWidth) {
      for (var i=0; i<sectionsWithSideLength; i++) {
        sectionClassNameNew[i] = sectionClassName[i].replace(/fixmain|fixside|bottommain|bottomside/g,'');
        var maxScroll = containerTop[i] + maxHeight[i] - bodyHeight - scrollTop;
        var minScroll = containerTop[i] + minHeight[i] - bodyHeight - scrollTop;
        //console.log (i + ': ' + maxScroll + '/' + minScroll);
        if (minHeight[i] < bodyHeight || maxHeight[i] - minHeight[i] < 100) {
          // do nothing
        } else if (mainHeight[i]>sideHeight[i]) {
          if (maxScroll<=0) {
            sectionClassNameNew[i] += ' bottomside';
          } else if (minScroll<=0 ) {
            sectionClassNameNew[i] += ' fixside';
          }
        } else if (mainHeight[i]<sideHeight[i]) {
          if (maxScroll<30) {
            sectionClassNameNew[i] += ' bottommain';
          } else if (minScroll<0){
            sectionClassNameNew[i] += ' fixmain';
          }
        }
        sectionClassNameNew[i] = sectionClassNameNew[i].replace(/[\s]+/g,' ');
        if (sectionClassNameNew[i] !== sectionClassName[i]) {
          sectionClassName[i] = sectionClassNameNew[i];
          sectionsWithSide[i].className = sectionClassNameNew[i];
          //console.log (sectionClassName[i]);
        }
      }
    }
    if (typeof stickyAds === 'object' && stickyAds.length >0) {
      for (var j=0; j<stickyAds.length; j++) {
        var oTop = stickyAds[j].oTop - scrollTop - gNavHeight;
        var oTop2 = oTop + stickyAds[j].stickyHeight;
        var newClass = '';
        if (oTop <= 0 && oTop2 >0) {
          newClass = ' is-fix';
        } else {
          newClass = '';
        }
        newClass = 'banner-container' + newClass;
        //console.log (newClass + '/' + stickyAds[i].currentClass + '/' + document.getElementById(stickyAds[i].BannerId).parentNode.parentNode.className);

        if (newClass !== stickyAds[j].currentClass) {
          stickyAds[j].currentClass = newClass;
          document.getElementById(stickyAds[j].BannerId).parentNode.parentNode.parentNode.className = newClass;
        }

      }

    }
  }

  function requestTick() {
    if(!ticking) {
      requestAnimationFrame(stickyBottomUpdate);
    }
    ticking = true;
  }

  function stickyBottom() {
    scrollTop = window.scrollY || document.documentElement.scrollTop;
    if (typeof requestAnimationFrame === 'function') {
      requestTick();
    } else {
      stickyBottomUpdate();
    }
  }

  try {
    delegate = new Delegate(document.body);
  } catch (ignore) {

  }

  // listent to scrolling events
  gNavOffsetY = findTop(document.getElementById('nav-place-holder'));
  if (gNavOffsetY > 30 && w > 490) {
    try {
      stickyBottomPrepare();
      stickyAdsPrepare();
      var addEvent =  window.attachEvent||window.addEventListener;
      var eventScroll = window.attachEvent ? 'onscroll' : 'scroll';
      var eventResize = window.attachEvent ? 'onresize' : 'resize';
      addEvent(eventScroll, function(){
          stickyBottom();
      });
      addEvent(eventResize, function(){
          stickyBottomPrepare();
          stickyAdsPrepare();
      });
      setInterval(function(){
          stickyBottomPrepare();
          stickyAdsPrepare();
      }, 10000);
    } catch (ignore) {

    }
  }

  // check svg support
  // SVG is default, no-svg is exception
  if (typeof SVGRect === 'undefined') {
    document.documentElement.className += ' no-svg';
  }

  // load responsive images
  var figures = document.querySelectorAll('figure.loading');
  for (var i=0; i<figures.length; i++) {
    var thisFigure = figures[i];
    var imageWidth = thisFigure.offsetWidth;
    var imageHeight = thisFigure.offsetHeight;
    var imageUrl = thisFigure.getAttribute('data-url');
    var figureClass = thisFigure.className || '';
    var fitType = 'cover';
    var figureParentClass = thisFigure.parentNode.className || '';
    if (isRetinaDevice === true) {
      imageWidth = imageWidth * 2;
      imageHeight = imageHeight * 2;
    }
    if (/brand/.test(figureParentClass)) {
      fitType = 'contain';
    }
    if (/sponsor/.test(figureClass)) {
      imageUrl = imageUrl.replace('i.ftimg.net', 'i.ftmailbox.com');
      imageUrl = encodeURIComponent(imageUrl);
      imageUrl = 'https://image.webservices.ft.com/v1/images/raw/' + imageUrl + '?source=ftchinese&height=' + imageHeight + '&fit=' + fitType;
      thisFigure.innerHTML = '';
      thisFigure.className = '';
    } else if (imageWidth > 0 && imageHeight > 0) {
      imageUrl = imageUrl.replace('i.ftimg.net', 'i.ftmailbox.com');
      imageUrl = encodeURIComponent(imageUrl);
      imageUrl = 'https://image.webservices.ft.com/v1/images/raw/' + imageUrl + '?source=ftchinese&width=' + imageWidth + '&height=' + imageHeight + '&fit=' + fitType;
      thisFigure.innerHTML = '';
      thisFigure.className = '';
    }
  }

  // load responsive videos
  var videos = document.querySelectorAll('figure.loading-video');
  var hostForVideo = '';
  if (window.location.hostname === 'localhost' || window.location.hostname.indexOf('192.168') === 0 || window.location.hostname.indexOf('10.113') === 0 || window.location.hostname.indexOf('127.0') === 0) {
    hostForVideo = 'http://www.ftchinese.com';
  }
  for (var i=0; i<videos.length; i++) {
    var thisVideo = videos[i];
    var videoWidth = thisVideo.offsetWidth;
    var videoHeight = thisVideo.offsetHeight;
    var videoId = thisVideo.getAttribute('data-vid');
    if (videoWidth > 0 && videoHeight > 0) {
      //console.log (videoId + ' Height: ' + videoHeight + ' Width: ' + videoWidth);
      thisVideo.innerHTML = '';
      thisFigure.className = '';
    }
  }

  //A cool trick to handle images that fail to load:
  try {
    delegate.on('error', 'img', function(){
      this.style.display = 'none';
    });
  } catch (ignore) {

  }

  // click events
  try {
    delegate.on('click', '.video-package .XL2 a.image', function(){
      var link = hostForVideo + this.getAttribute('href');
      var videoPackage = this.parentNode.parentNode.parentNode;
      var videoEle = videoPackage.querySelector('#video-package-play');
      var videoWidth = videoEle.offsetWidth;
      var videoHeight = videoEle.offsetHeight;
      var thisItemEle = this.parentNode.parentNode;
      var thisHeadline = thisItemEle.querySelector('.item-headline a').innerHTML;
      var allVideos = this.parentNode.parentNode.parentNode.querySelectorAll('.video-package .XL2');
      for (var i=0; i<allVideos.length; i++) {
        var thisClassName = allVideos[i].className;
        if (thisClassName.indexOf(' on')>=0) {
          thisClassName = thisClassName.replace(' on', '');
          allVideos[i].className = thisClassName;
        }
      }
      this.parentNode.parentNode.className += ' on';
      videoEle.querySelector('iframe').src = link  +'?i=2&k=1&w='+videoWidth+'&h='+videoHeight+'&autostart=true';
      videoPackage.querySelector('.video-package-title a').innerHTML = thisHeadline;
      videoPackage.querySelector('.video-package-title a').href = link;
      return false;
    });
  } catch (ignore) {

  }

/* jshint devel:true */
/****dolphin广告****/
//参数依次为
//位置ID
//频道ID
//DOM节点ID(script选填，script方式不需要NodeID，采用document.write)
//iframe宽高（选填，不传这两个参数将添加script广告）
/*
function dolphinAD(pID,cID,NodeID,w,h){
    var adCode;
    if(!pID){
        return "positionID missing";
    }
    if(!cID){
        return "channelID missing";
    }
    if(w&&h){//iframe方式
        if(!w){
            return "width missing";
        }
        if(!h){
            return "height missing";
        }
        //adCode = '';
        adCode = '';
        if (document.getElementById(NodeID)){
            document.getElementById(NodeID).innerHTML=adCode;
            return adCode;
        }
        return "node missing";
    }
    //script 方式
    try {
        adCode = '<scr'+'ipt type="text/javascript" src="http://dolphin.ftimg.net/s?z=ft&c='+cID+pID+slotStr+adReachability()+'" charset="gbk" ></scr'+'ipt>';
        document.write(adCode);
    } catch (err) {
        var k=err.toString();
        ga('send','event', 'CatchError', 'AD', pId + '' + cID + ':' + k, {'nonInteraction':1});
    }
    return adCode;
}

function setDolphinSlot(key){
  //定义slot随机数实现联动互斥功能
  var rString = window.dolRand?"&slot="+window.dolRand:"",
      cString = GetCookie(key),
      x;
  if(!cString){return rString;}
  window.cArray = cString.split(";");
  for(x in window.cArray){
      if (window.cArray.hasOwnProperty(x)) {
          window.cArray[x]=window.cArray[x].replace("|","=");
          rString += "&_"+window.cArray[x];
      }
  }
  return rString;
}
*/<|endoftext|>


<commit_before>// ---------------------------------------------------------------------------
// Usage: npm run transpile
// ---------------------------------------------------------------------------

"use strict";

const fs = require ('fs')
    , log = require ('ololog')
    , ansi = require ('ansicolor').nice
    , { unCamelCase, precisionConstants, safeString, unique } = require ('../js/base/functions.js')
    , {
        createFolderRecursively,
        overwriteFile,
        replaceInFile,
    } = require ('./fs.js')
    , errors = require ('../js/base/errors.js')
    , Transpiler = require ('./transpile.js')
    , Exchange = require ('../js/ws/base/Exchange.js')
    , tsFilename = './ccxt.pro.d.ts'

// ============================================================================

class CCXTProTranspiler extends Transpiler {

    getBaseClass () {
        return new Exchange ()
    }

    getPHPPreamble () {
        return [
            "<?php",
            "namespace ccxtpro;",
            "include_once __DIR__ . '/../../vendor/autoload.php';",
            "// ----------------------------------------------------------------------------",
            "",
            "// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:",
            "// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code",
            "",
            "// -----------------------------------------------------------------------------",
            "",
        ].join ("\n")
    }

    createPythonClassDeclaration (className, baseClass) {
        const baseClasses = (baseClass.indexOf ('ccxt.') === 0) ?
            [ 'Exchange', baseClass ] :
            [ baseClass ]
        return 'class ' + className + '(' + baseClasses.join (', ') + '):'
    }

    createPythonClassImports (baseClass, async = false) {

        const baseClasses = {
            'Exchange': 'base.exchange',
        }

        async = (async ? '.async_support' : '')

        if (baseClass.indexOf ('ccxt.') === 0) {
            return [
                'from ccxtpro.base.exchange import Exchange',
                'import ccxt' + async + ' as ccxt'
            ]
        } else {
            return [
                'from ccxtpro.' + safeString (baseClasses, baseClass, baseClass) + ' import ' + baseClass
            ]
        }
        // return [
        //     (baseClass.indexOf ('ccxt.') === 0) ?
        //         ('import ccxt' + async + ' as ccxt') :
        //         ('from ccxtpro.' + safeString (baseClasses, baseClass, baseClass) + ' import ' + baseClass)
        // ]
    }

    createPythonClassHeader (ccxtImports, bodyAsString) {
        const imports = [
            ... ccxtImports,
        ]
        const arrayCacheClasses = bodyAsString.match (/\bArrayCache(?:[A-Z][A-Za-z]+)?\b/g)
        if (arrayCacheClasses) {
            const uniqueArrayCacheClasses = unique (arrayCacheClasses).sort ()
            const arrayCacheImport = 'from ccxtpro.base.cache import ' + uniqueArrayCacheClasses.join (', ')
            imports.push (arrayCacheImport)
        }
        return [
            "# -*- coding: utf-8 -*-",
            "",
            "# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:",
            "# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code",
            "",
            ... imports,
        ]
    }

    createPHPClassDeclaration (className, baseClass) {
        let lines = [
            'class ' + className + ' extends ' + baseClass.replace ('ccxt.', '\\ccxt\\async\\') + ' {',
        ]
        if (baseClass.indexOf ('ccxt.') === 0) {
            lines = lines.concat ([
                '',
                '    use ClientTrait;'
            ])
        }
        return lines.join ("\n")
    }

    createPHPClassHeader (className, baseClass, bodyAsString) {
        return [
            "<?php",
            "",
            "namespace ccxtpro;",
            "",
            "// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:",
            "// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code",
            "",
            "use Exception; // a common import",
        ]
    }

    sortExchangeCapabilities (code) {
        return false
    }

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

    transpileOrderBookTest () {
        const jsFile = './js/test/base/test.OrderBook.js'
        const pyFile = './python/ccxtpro/test/test_order_book.py'
        const phpFile = './php/test/OrderBook.php'
        const pyImports = [
            '',
            'from ccxtpro.base.order_book import OrderBook, IndexedOrderBook, CountedOrderBook  # noqa: F402',
            '',
        ].join ('\n')
        this.transpileTest (jsFile, pyFile, phpFile, pyImports)
    }

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

    transpileCacheTest () {
        const jsFile = './js/test/base/test.Cache.js'
        const pyFile = './python/ccxtpro/test/test_cache.py'
        const phpFile = './php/test/Cache.php'
        const pyImports = [
            '',
            'from ccxtpro.base.cache import ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById  # noqa: F402',
            '',
        ].join ('\n')
        this.transpileTest (jsFile, pyFile, phpFile, pyImports)
    }

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

    transpileTest (jsFile, pyFile, phpFile, pyImports) {

        log.magenta ('Transpiling from', jsFile.yellow)

        let js = fs.readFileSync (jsFile).toString ()

        js = this.regexAll (js, [
            [ /\'use strict\';?\s+/g, '' ],
            [ /[^\n]+require[^\n]+\n/g, '' ],
            [ /function equals \([\S\s]+?return true;\n}\n/g, '' ],
        ])

        const options = { js, removeEmptyLines: false }
        const transpiled = this.transpileJavaScriptToPythonAndPHP (options)
        const { python3Body, python2Body, phpBody } = transpiled
        const pythonHeader = [
            '',
            '',
            'def equals(a, b):',
            '    return a == b',
            '',
        ].join ('\n')

        const phpHeader = [
            '',
            'function equals($a, $b) {',
            '    return json_encode($a) === json_encode($b);',
            '}',
        ].join ('\n')

        const python = this.getPythonPreamble () + pyImports + pythonHeader + python2Body
        const php = this.getPHPPreamble () + phpHeader + phpBody

        log.magenta ('→', pyFile.yellow)
        log.magenta ('→', phpFile.yellow)

        overwriteFile (pyFile, python)
        overwriteFile (phpFile, php)
    }

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

    transpileEverything (force = false) {

        // default pattern is '.js'
        const [ /* node */, /* script */, pattern ] = process.argv.filter (x => !x.startsWith ('--'))
            // , python2Folder = './python/ccxtpro/', // CCXT Pro does not support Python 2
            , python3Folder = './python/ccxt/ws'
            , phpAsyncFolder     = './php/ws'
            , options = { /* python2Folder, */ python3Folder, phpAsyncFolder }

        // createFolderRecursively (python2Folder)
        createFolderRecursively (python3Folder)
        createFolderRecursively (phpAsyncFolder)

        this.transpileCacheTest ()
        this.transpileOrderBookTest ()
        const classes = this.transpileDerivedExchangeFiles ('./js/ws/', options, pattern, force)

        if (classes === null) {
            log.bright.yellow ('0 files transpiled.')
            return;
        }

        // HINT: if we're going to support specific class definitions
        // this process won't work anymore as it will override the definitions
        this.exportTypeScriptDeclarations (tsFilename, classes)

        //*/

        this.transpileErrorHierarchy ({ tsFilename })

        // transpilePrecisionTests ()
        // transpileDateTimeTests ()
        // transpileCryptoTests ()

        log.bright.green ('Transpiled successfully.')
    }
}

// ============================================================================
// main entry point

if (require.main === module) {

    // if called directly like `node module`

    const transpiler = new CCXTProTranspiler ()
    const force = process.argv.includes ('--force')
    log.bright.green ({ force })
    transpiler.transpileEverything (force)

} else {

    // do nothing if required as a module
}

// ============================================================================

module.exports = CCXTProTranspiler
<commit_msg>adapt WS transpiler<commit_after>// ---------------------------------------------------------------------------
// Usage: npm run transpile
// ---------------------------------------------------------------------------

"use strict";

const fs = require ('fs')
    , log = require ('ololog')
    , ansi = require ('ansicolor').nice
    , { unCamelCase, precisionConstants, safeString, unique } = require ('../js/base/functions.js')
    , {
        createFolderRecursively,
        overwriteFile,
        replaceInFile,
    } = require ('./fs.js')
    , errors = require ('../js/base/errors.js')
    , Transpiler = require ('./transpile.js')
    , Exchange = require ('../js/ws/base/Exchange.js')
    , tsFilename = './ccxt.pro.d.ts'

// ============================================================================

class CCXTProTranspiler extends Transpiler {

    getBaseClass () {
        return new Exchange ()
    }

    getPHPPreamble () {
        return [
            "<?php",
            "namespace ccxtpro;",
            "include_once __DIR__ . '/../../vendor/autoload.php';",
            "// ----------------------------------------------------------------------------",
            "",
            "// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:",
            "// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code",
            "",
            "// -----------------------------------------------------------------------------",
            "",
        ].join ("\n")
    }

    createPythonClassDeclaration (className, baseClass) {
        const baseClasses = (baseClass.indexOf ('ccxt.') === 0) ?
            [ 'Exchange', baseClass ] :
            [ baseClass ]
        return 'class ' + className + '(' + baseClasses.join (', ') + '):'
    }

    createPythonClassImports (baseClass, async = false) {

        const baseClasses = {
            'Exchange': 'base.exchange',
        }

        async = (async ? '.async_support' : '')

        if (baseClass.indexOf ('ccxt.') === 0) {
            return [
                'from ccxtpro.base.exchange import Exchange',
                'import ccxt' + async + ' as ccxt'
            ]
        } else {
            return [
                'from ccxtpro.' + safeString (baseClasses, baseClass, baseClass) + ' import ' + baseClass
            ]
        }
        // return [
        //     (baseClass.indexOf ('ccxt.') === 0) ?
        //         ('import ccxt' + async + ' as ccxt') :
        //         ('from ccxtpro.' + safeString (baseClasses, baseClass, baseClass) + ' import ' + baseClass)
        // ]
    }

    createPythonClassHeader (ccxtImports, bodyAsString) {
        const imports = [
            ... ccxtImports,
        ]
        const arrayCacheClasses = bodyAsString.match (/\bArrayCache(?:[A-Z][A-Za-z]+)?\b/g)
        if (arrayCacheClasses) {
            const uniqueArrayCacheClasses = unique (arrayCacheClasses).sort ()
            const arrayCacheImport = 'from ccxtpro.base.cache import ' + uniqueArrayCacheClasses.join (', ')
            imports.push (arrayCacheImport)
        }
        return [
            "# -*- coding: utf-8 -*-",
            "",
            "# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:",
            "# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code",
            "",
            ... imports,
        ]
    }

    createPHPClassDeclaration (className, baseClass) {
        let lines = [
            'class ' + className + ' extends ' + baseClass.replace ('ccxt.', '\\ccxt\\async\\') + ' {',
        ]
        if (baseClass.indexOf ('ccxt.') === 0) {
            lines = lines.concat ([
                '',
                '    use ClientTrait;'
            ])
        }
        return lines.join ("\n")
    }

    createPHPClassHeader (className, baseClass, bodyAsString) {
        return [
            "<?php",
            "",
            "namespace ccxtpro;",
            "",
            "// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:",
            "// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code",
            "",
            "use Exception; // a common import",
        ]
    }

    sortExchangeCapabilities (code) {
        return false
    }

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

    transpileOrderBookTest () {
        const jsFile = './js/test/base/test.OrderBook.js'
        const pyFile = './python/ccxtpro/test/test_order_book.py'
        const phpFile = './php/test/OrderBook.php'
        const pyImports = [
            '',
            'from ccxtpro.base.order_book import OrderBook, IndexedOrderBook, CountedOrderBook  # noqa: F402',
            '',
        ].join ('\n')
        this.transpileTest (jsFile, pyFile, phpFile, pyImports)
    }

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

    transpileCacheTest () {
        const jsFile = './js/ws/test/base/test.Cache.js'
        const pyFile = './python/ccxt/ws/test/test_cache.py'
        const phpFile = './php/ws/test/Cache.php'
        const pyImports = [
            '',
            'from ccxtpro.base.cache import ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById  # noqa: F402',
            '',
        ].join ('\n')
        this.transpileTest (jsFile, pyFile, phpFile, pyImports)
    }

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

    transpileTest (jsFile, pyFile, phpFile, pyImports) {

        log.magenta ('Transpiling from', jsFile.yellow)

        let js = fs.readFileSync (jsFile).toString ()

        js = this.regexAll (js, [
            [ /\'use strict\';?\s+/g, '' ],
            [ /[^\n]+require[^\n]+\n/g, '' ],
            [ /function equals \([\S\s]+?return true;\n}\n/g, '' ],
        ])

        const options = { js, removeEmptyLines: false }
        const transpiled = this.transpileJavaScriptToPythonAndPHP (options)
        const { python3Body, python2Body, phpBody } = transpiled
        const pythonHeader = [
            '',
            '',
            'def equals(a, b):',
            '    return a == b',
            '',
        ].join ('\n')

        const phpHeader = [
            '',
            'function equals($a, $b) {',
            '    return json_encode($a) === json_encode($b);',
            '}',
        ].join ('\n')

        const python = this.getPythonPreamble () + pyImports + pythonHeader + python2Body
        const php = this.getPHPPreamble () + phpHeader + phpBody

        log.magenta ('→', pyFile.yellow)
        log.magenta ('→', phpFile.yellow)

        overwriteFile (pyFile, python)
        overwriteFile (phpFile, php)
    }

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

    transpileEverything (force = false) {

        // default pattern is '.js'
        const [ /* node */, /* script */, pattern ] = process.argv.filter (x => !x.startsWith ('--'))
            // , python2Folder = './python/ccxtpro/', // CCXT Pro does not support Python 2
            , python3Folder = './python/ccxt/ws'
            , phpAsyncFolder     = './php/ws'
            , options = { /* python2Folder, */ python3Folder, phpAsyncFolder }

        // createFolderRecursively (python2Folder)
        createFolderRecursively (python3Folder)
        createFolderRecursively (phpAsyncFolder)

        this.transpileCacheTest ()
        this.transpileOrderBookTest ()
        const classes = this.transpileDerivedExchangeFiles ('./js/ws/', options, pattern, force)

        if (classes === null) {
            log.bright.yellow ('0 files transpiled.')
            return;
        }

        // HINT: if we're going to support specific class definitions
        // this process won't work anymore as it will override the definitions
        this.exportTypeScriptDeclarations (tsFilename, classes)

        //*/

        this.transpileErrorHierarchy ({ tsFilename })

        // transpilePrecisionTests ()
        // transpileDateTimeTests ()
        // transpileCryptoTests ()

        log.bright.green ('Transpiled successfully.')
    }
}

// ============================================================================
// main entry point

if (require.main === module) {

    // if called directly like `node module`

    const transpiler = new CCXTProTranspiler ()
    const force = process.argv.includes ('--force')
    log.bright.green ({ force })
    transpiler.transpileEverything (force)

} else {

    // do nothing if required as a module
}

// ============================================================================

module.exports = CCXTProTranspiler
<|endoftext|>


<commit_before>/**
 * The main map.
 */
var map = null;

/**
 * Tile API path.
 */
var tilePath = 'http://{s}.tile.cloudmade.com/' +
  '64933b0e195f401bb1de7230d381bf66/997/256/{z}/{x}/{y}.png';

/**
 * Currently shown regions.
 */
var bubbles = [];

/**
 * Currently shown routes.
 */
var routes = [];

/**
 * Colours from which we randomly select line/circle/marker colours.
 */
var colours = [
  'red', 'purple', 'green', 'blue',
  'orange', 'pink', 'yellow', 'grey'
];

/**
 * Array pointer for colours.
 */
var _colourMarker = 0;

/**
 * Generate a random colour.
 */
function colour()
{
  var colour = colours[_colourMarker];

  _colourMarker = (_colourMarker + 1) % colours.length;
  return colour;
}

/**
 * Check whether a circle contains part of a line.
 */
function contains(circle, line) {
  var points = line.getLatLngs();

  for (var n = 0; n < points.length; n++) {
    if (circle.getBounds().contains(points[n])) {
      return true;
    }
  }
}

/**
 * Make a configuration bubble.
 */
function bubbleConfiguration(bubble)
{
  var path = '/tpl/bubble.ejs';
  var coordinates = bubble.getLatLng();
  var count = 0;

  for (var i = 0; i < coordinates.length; i++) {
    if (contains(bubble, coordinates[i])) {
      count++;
    }
  }

  var data = {
    id: bubbles.length,
    lat: coordinates.lat,
    lng: coordinates.lng,
    count: count
  };

  bubbles.push(bubble);
  var form = $(new EJS({ url: path }).render(data));

  $(' input[name=radius]', form).change(function () {
    bubble.setRadius(this.value);
    count = 0;

    for (var i = 0; i < coordinates.length; i++) {
      if (contains(bubble, coordinates[i])) {
        count++;
      }
    }

    $(' .route_count', form).text(count);
  });

  $(' input[name=delete]', form).click(function () {
    map.removeLayer(bubble);
  });

  $(' .colours span', form).on('click', function () {
    bubble.setStyle({ color: this.className });
  });

  return form[0];
}

/**
 * Make a configuration bubble.
 */
function routeConfiguration(name, route)
{
  var path = '/tpl/route.ejs';

  var data = {
    name: name
  };

  routes.push(route);
  var form = $(new EJS({ url: path }).render(data));

  $(' input[name=follow]', form).click(function () {
    follow(route.getLatLngs());
  });

  return form[0];

  // bubbles.push(bubble);
  // var form = $(new EJS({ url: path }).render(data));

  // $(' input[name=radius]', form).change(function () {
  //   bubble.setRadius(this.value);
  //   count = 0;

  //   for (var i = 0; i < lines.length; i++) {
  //     if (contains(bubble, lines[i])) {
  //       count++;
  //     }
  //   }

  //   $(' .route_count', form).text(count);
  // });

  // $(' input[name=delete]', form).click(function () {
  //   map.removeLayer(bubble);
  // });

  // $(' .colours span', form).on('click', function () {
  //   bubble.setStyle({ color: this.className });
  // });
}

$(function () {
  map = L.map('map').setView([51.383198, -2.359123], 15);

  map.on('click', function (e) {
    var bubble = L.circle(e.latlng, 100, { color: 'red' }).addTo(map);
    var gui = bubbleConfiguration(bubble);

    bubble.bindPopup(gui, {
      minWidth: 400
    });
  });

  L.tileLayer(tilePath, {
    attribution: 'OpenStreetMap | CloudeMade',
    maxZoom: 18
  }).addTo(map);

  $.getJSON('/api/paths', function (paths) {
    for (i = 0; i < paths.length; i++) {
      var route = [];

      var name = paths[i].name;
      var coordinates = paths[i].coordinates;

      for (n = 0; n < coordinates.length; n++) {
        route.push([coordinates[n].pos_x, coordinates[n].pos_y]);
      }

      var line = L.polyline(route, {color: colour()}).addTo(map);

      line.bindPopup(name);
      var gui = routeConfiguration(name, line);

      line.bindPopup(gui, { minWidth: 400 });
    }
  });
});

function follow(route) {
  route = route.slice(0);

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

  var center = map.getCenter();
  var zoom = map.getZoom();

  map.setZoom(17);

  var interval = setInterval(function () {
    if (route.length == 0) {
      map.setZoom(zoom);
      map.panTo(center);

      clearInterval(interval);
    }

    map.panTo(route.shift());
  }, 500);
}
<commit_msg>Bug-fixing<commit_after>/**
 * The main map.
 */
var map = null;

/**
 * Tile API path.
 */
var tilePath = 'http://{s}.tile.cloudmade.com/' +
  '64933b0e195f401bb1de7230d381bf66/997/256/{z}/{x}/{y}.png';

/**
 * Currently shown regions.
 */
var bubbles = [];

/**
 * Currently shown routes.
 */
var routes = [];

/**
 * Colours from which we randomly select line/circle/marker colours.
 */
var colours = [
  'red', 'purple', 'green', 'blue',
  'orange', 'pink', 'yellow', 'grey'
];

/**
 * Array pointer for colours.
 */
var _colourMarker = 0;

/**
 * Generate a random colour.
 */
function colour()
{
  var colour = colours[_colourMarker];

  _colourMarker = (_colourMarker + 1) % colours.length;
  return colour;
}

/**
 * Check whether a circle contains part of a line.
 */
function contains(circle, line) {
  var points = line.getLatLngs();

  for (var n = 0; n < points.length; n++) {
    if (circle.getBounds().contains(points[n])) {
      return true;
    }
  }
}

/**
 * Make a configuration bubble.
 */
function bubbleConfiguration(bubble)
{
  var path = '/tpl/bubble.ejs';
  var coordinates = bubble.getLatLng();
  var count = 0;

  for (var i = 0; i < routes.length; i++) {
    if (contains(bubble, routes[i])) {
      count++;
    }
  }

  var data = {
    id: bubbles.length,
    lat: coordinates.lat,
    lng: coordinates.lng,
    count: count
  };

  bubbles.push(bubble);
  var form = $(new EJS({ url: path }).render(data));

  $(' input[name=radius]', form).change(function () {
    bubble.setRadius(this.value);
    count = 0;

    for (var i = 0; i < routes.length; i++) {
      if (contains(bubble, routes[i])) {
        count++;
      }
    }

    $(' .route_count', form).text(count);
  });

  $(' input[name=delete]', form).click(function () {
    map.removeLayer(bubble);
  });

  $(' .colours span', form).on('click', function () {
    bubble.setStyle({ color: this.className });
  });

  return form[0];
}

/**
 * Make a configuration bubble.
 */
function routeConfiguration(name, route)
{
  var path = '/tpl/route.ejs';

  var data = {
    name: name
  };

  routes.push(route);
  var form = $(new EJS({ url: path }).render(data));

  $(' input[name=follow]', form).click(function () {
    follow(route);
  });

  $(' .colours span', form).on('click', function () {
    route.setStyle({ color: this.className });
  });

  return form[0];
}

$(function () {
  map = L.map('map').setView([51.383198, -2.359123], 15);

  map.on('click', function (e) {
    var bubble = L.circle(e.latlng, 100, { color: 'red' }).addTo(map);
    var gui = bubbleConfiguration(bubble);

    bubble.bindPopup(gui, {
      minWidth: 400
    });
  });

  L.tileLayer(tilePath, {
    attribution: 'OpenStreetMap | CloudeMade',
    maxZoom: 18
  }).addTo(map);

  $.getJSON('/api/paths', function (paths) {
    for (i = 0; i < paths.length; i++) {
      var route = [];

      var name = paths[i].name;
      var coordinates = paths[i].coordinates;

      for (n = 0; n < coordinates.length; n++) {
        route.push([coordinates[n].pos_x, coordinates[n].pos_y]);
      }

      var line = L.polyline(route, {color: colour()}).addTo(map);

      line.bindPopup(name);
      var gui = routeConfiguration(name, line);

      line.bindPopup(gui, { minWidth: 400 });
    }
  });
});

function follow(line) {
  route = line.getLatLngs().slice(0);

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

  var center = map.getCenter();
  var zoom = map.getZoom();

  line.closePopup();
  map.setZoom(17);

  var interval = setInterval(function () {
    if (route.length == 0) {
      map.setZoom(zoom);
      clearInterval(interval);

      return;
    }

    map.panTo(route.shift());
  }, 500);
}
<|endoftext|>


<commit_before>//Build the Model
var Recipe = Backbone.Model.extend ({
  defaults: {
    recipeName: '',
    smallImgUrls: '',
    rating: ''
  },
});

//Instantiate the Model
var recipe = new Recipe();

var RecipeCollection = Backbone.Collection.extend ({
  model: Recipe,
  sync: function(method, model, options) {
        var params = _.extend({
            type: 'GET',
            dataType: 'jsonp',
            url: 'http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup',
            processData: false
        }, options);

        return $.ajax(params);
    },

  // url: 'http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup',
  // sync: function(method, model, options) {
  //     options.timeout = 10000;
  //     options.dataType = "jsonp";
  //     options.jsonp = "JSONPcallback";
  //     return Backbone.sync(method, model, options);

});

//Instantiate the Collection
var recipeCollection = new RecipeCollection();

//View for our recipe collection
var RecipeListView = Backbone.View.extend ({

    initialize:function(){
       this.collection.fetch();
       console.log('Did I make it past fetch?');
       this.render();
    },

    render: function () {
        var source = $('#recipe-list-template').html();
        var template = Handlebars.compile(source);
        console.log('Did I make it to render?');
        var recipesJSON = $.ajax('http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup',{
            'async': false,
            'global': false,
            'dataType': "jsonp",
            complete: function(data){
                json = data;
            }
      })
      // var rendered = template({recipeCollection: this.collection.toJSON()});
      var rendered = template({recipeCollection: data.matches});
      // this.$el.html(rendered);
      $('.container').html(rendered);
      return this;

}
});

//Instantiate the Recipe List view
var recipeListView = new RecipeListView ({
  collection: recipeCollection
});

//View for the recipe that you've chosen
var RecipeView = Backbone.View.extend ({
});

// $(function () {
// 	'use strict';
// 	// populate our default list view
// 	$('.container').append(recipeListView.render().$el);
// });

function myGetJSON () {
    var json = null;
    $.ajax({
        'async': false,
        'global': false,
        'url': "http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup",
        'dataType': "jsonp"

    }).done(function(data) {
json = data
    console.log('About to return Json data: ' + json);
    console.log(json);
    return json;
  });
    // console.log(json);
    // return json;
};

//
// var j = myGetJSON();
// console.log(j);
<commit_msg>Various attempts to get fetch to accept JSONP to get around no-access-controll-allow-origin error<commit_after>//Build the Model
var Recipe = Backbone.Model.extend ({
  defaults: {
    recipeName: '',
    smallImgUrls: '',
    rating: ''
  },
});

//Instantiate the Model
var recipe = new Recipe();

var RecipeCollection = Backbone.Collection.extend ({
  model: Recipe,
  url: 'http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup&callback=myGetJSON'

  // url: 'http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup',
  // sync: function(method, model, options) {
  //     options.timeout = 10000;
  //     options.dataType = "jsonp";
  //     options.jsonp = "JSONPcallback";
  //     return Backbone.sync(method, model, options);

});

//Instantiate the Collection
var recipeCollection = new RecipeCollection({

});

//View for our recipe collection
var RecipeListView = Backbone.View.extend ({

    initialize:function(){
       this.collection.fetch({
       success: function(){
            {dataType: "jsonp"}
        }
      })
       console.log('Did I make it past fetch?');
       this.render();
    },

    render: function () {
        var source = $('#recipe-list-template').html();
        var template = Handlebars.compile(source);
        console.log('Did I make it to render?');
      //   var recipesJSON = $.ajax('http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup',{
      //       'async': false,
      //       'global': false,
      //       'dataType': "jsonp",
      //       complete: function(data){
      //           json = data;
      //       }
      // })
      var rendered = template({recipeCollection: this.collection.toJSON()});
      // var rendered = template({recipeCollection: data.matches});
      // this.$el.html(rendered);
      $('.container').html(rendered);
      return this;

}
});

//Instantiate the Recipe List view
var recipeListView = new RecipeListView ({
  collection: recipeCollection
});

//View for the recipe that you've chosen
var RecipeView = Backbone.View.extend ({
});

// $(function () {
// 	'use strict';
// 	// populate our default list view
// 	$('.container').append(recipeListView.render().$el);
// });

function myGetJSON (url) {
    var json = null;
    $.ajax({
        'async': false,
        'global': false,
        'url': "http://api.yummly.com/v1/api/recipes?_app_id=2aacde19&_app_key=e8bce795e7a1dc7c96574390c998df81&q=%20chicken+soup",
        'dataType': "jsonp"

    }).done(function(data) {
json = data
    console.log('About to return Json data: ' + json);
    console.log(json);
    return json;
  });
    // console.log(json);
    // return json;
};

//
// var j = myGetJSON();
// console.log(j);
<|endoftext|>


<commit_before>// Copyright 2014 CloudFounders NV
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*global define */
define([
    'knockout', 'jquery',
    'ovs/generic'
], function(ko, $, generic) {
    "use strict";
    return function() {
        var self = this;

        // Variables
        self.text          = undefined;
        self.unique        = generic.getTimestamp().toString();

        // Observables
        self.key           = ko.observable();
        self.keyIsFunction = ko.observable(false);
        self.small         = ko.observable(false);
        self.multi         = ko.observable(false);
        self.free          = ko.observable(false);
        self.items         = ko.observableArray([]);
        self.target        = ko.observableArray([]);
        self._freeValue    = ko.observable();
        self.useFree       = ko.observable(false);

        // Computed
        self.selected  = ko.computed(function() {
            var items = [], i;
            for (i = 0; i < self.items().length; i += 1) {
                if (self.contains(self.items()[i])) {
                    items.push(self.items()[i]);
                }
            }
            return items;
        });
        self.freeValue = ko.computed({
            read: function() {
                return self._freeValue();
            },
            write: function(newValue) {
                self.target(newValue);
                self._freeValue(newValue);
            }
        });

        // Functions
        self.set = function(item) {
            if (self.multi()) {
                if (self.contains(item)) {
                    self.target.remove(item);
                } else {
                    self.target.push(item);
                }
            } else {
                self.target(item);
                if (self.free() && $.inArray(self.target(), self.items()) === -1 && self.useFree()) {
                    self._freeValue(item);
                }
            }
        };
        self.contains = function(item) {
            return $.inArray(item, self.target()) !== -1;
        };
        self.translate = function() {
            $('html').i18n();
        };

        // Durandal
        self.activate = function(settings) {
            if (!settings.hasOwnProperty('items')) {
                throw 'Items should be specified';
            }
            if (!settings.hasOwnProperty('target')) {
                throw 'Target should be specified';
            }
            self.items = settings.items;
            self.target = settings.target;
            self.key(generic.tryGet(settings, 'key', undefined));
            self.small(generic.tryGet(settings, 'small', false));
            self.keyIsFunction(generic.tryGet(settings, 'keyisfunction', false));
            self.free(generic.tryGet(settings, 'free', false));
            if (self.free()) {
                if (!settings.hasOwnProperty('defaultfree')) {
                    throw 'If free values are allowed, a default should be provided';
                }
                if (self.target() !== undefined) {
                    self._freeValue(self.target());
                } else {
                    self._freeValue(settings.defaultfree);
                }
            }
            self.text = generic.tryGet(settings, 'text', function(item) { return item; });
            if (self.target.isObservableArray) {
                self.multi(true);
            } else if (self.target() === undefined && self.items().length > 0) {
                var foundDefault = false;
                $.each(self.items(), function(index, item) {
                    if (settings.hasOwnProperty('defaultRegex')) {
                        if (self.text(item).match(settings.defaultRegex) !== null) {
                            self.target(item);
                            foundDefault = true;
                            return false;
                        }
                        return true;
                    }
                    if (item === undefined) {
                        foundDefault = true;
                    }
                });
                if (!foundDefault) {
                    self.target(self.items()[0]);
                }
            }
            if (self.free() && self.multi()) {
                throw 'A dropdown cannot be a multiselect and allow free values at the same time.';
            }
            self.useFree(false);

            if (!ko.isComputed(self.target)) {
                self.target.valueHasMutated();
            }
        };
    };
});
<commit_msg>OVS-1444 - Sometimes the callback was executed slightly too fast.<commit_after>// Copyright 2014 CloudFounders NV
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*global define, window */
define([
    'knockout', 'jquery',
    'ovs/generic'
], function(ko, $, generic) {
    "use strict";
    return function() {
        var self = this;

        // Variables
        self.text          = undefined;
        self.unique        = generic.getTimestamp().toString();

        // Observables
        self.key           = ko.observable();
        self.keyIsFunction = ko.observable(false);
        self.small         = ko.observable(false);
        self.multi         = ko.observable(false);
        self.free          = ko.observable(false);
        self.items         = ko.observableArray([]);
        self.target        = ko.observableArray([]);
        self._freeValue    = ko.observable();
        self.useFree       = ko.observable(false);

        // Computed
        self.selected  = ko.computed(function() {
            var items = [], i;
            for (i = 0; i < self.items().length; i += 1) {
                if (self.contains(self.items()[i])) {
                    items.push(self.items()[i]);
                }
            }
            return items;
        });
        self.freeValue = ko.computed({
            read: function() {
                return self._freeValue();
            },
            write: function(newValue) {
                self.target(newValue);
                self._freeValue(newValue);
            }
        });

        // Functions
        self.set = function(item) {
            if (self.multi()) {
                if (self.contains(item)) {
                    self.target.remove(item);
                } else {
                    self.target.push(item);
                }
            } else {
                self.target(item);
                if (self.free() && $.inArray(self.target(), self.items()) === -1 && self.useFree()) {
                    self._freeValue(item);
                }
            }
        };
        self.contains = function(item) {
            return $.inArray(item, self.target()) !== -1;
        };
        self.translate = function() {
            window.setTimeout(function() { $('html').i18n(); }, 250);
        };

        // Durandal
        self.activate = function(settings) {
            if (!settings.hasOwnProperty('items')) {
                throw 'Items should be specified';
            }
            if (!settings.hasOwnProperty('target')) {
                throw 'Target should be specified';
            }
            self.items = settings.items;
            self.target = settings.target;
            self.key(generic.tryGet(settings, 'key', undefined));
            self.small(generic.tryGet(settings, 'small', false));
            self.keyIsFunction(generic.tryGet(settings, 'keyisfunction', false));
            self.free(generic.tryGet(settings, 'free', false));
            if (self.free()) {
                if (!settings.hasOwnProperty('defaultfree')) {
                    throw 'If free values are allowed, a default should be provided';
                }
                if (self.target() !== undefined) {
                    self._freeValue(self.target());
                } else {
                    self._freeValue(settings.defaultfree);
                }
            }
            self.text = generic.tryGet(settings, 'text', function(item) { return item; });
            if (self.target.isObservableArray) {
                self.multi(true);
            } else if (self.target() === undefined && self.items().length > 0) {
                var foundDefault = false;
                $.each(self.items(), function(index, item) {
                    if (settings.hasOwnProperty('defaultRegex')) {
                        if (self.text(item).match(settings.defaultRegex) !== null) {
                            self.target(item);
                            foundDefault = true;
                            return false;
                        }
                        return true;
                    }
                    if (item === undefined) {
                        foundDefault = true;
                    }
                });
                if (!foundDefault) {
                    self.target(self.items()[0]);
                }
            }
            if (self.free() && self.multi()) {
                throw 'A dropdown cannot be a multiselect and allow free values at the same time.';
            }
            self.useFree(false);

            if (!ko.isComputed(self.target)) {
                self.target.valueHasMutated();
            }
        };
    };
});
<|endoftext|>


<commit_before>/** @format */
import statemachine from "@/statemachine"
import { setDefaultConfigValues } from "./settings"

const korpFailImg = require("../img/korp_fail.svg")
const deparam = require("jquery-deparam")

import jStorage from "../lib/jstorage"

window.authenticationProxy = new model.AuthenticationProxy()
window.timeProxy = new model.TimeProxy()

const creds = jStorage.get("creds")
if (creds) {
    authenticationProxy.loginObj = creds
    statemachine.send("USER_FOUND", creds)
} else {
    statemachine.send("USER_NOT_FOUND")
}

// rewriting old url format to the angular one
if (location.hash.length && location.hash[1] !== "?") {
    location.hash = `#?${_.trimStart(location.hash, "#")}`
}

$.ajaxSetup({
    dataType: "json",
    traditional: true,
})

$.ajaxPrefilter("json", function (options) {
    if (options.crossDomain && !$.support.cors) {
        return "jsonp"
    }
})

const loc_dfd = window.initLocales()
$(document).keyup(function (event) {
    if (event.keyCode === 27) {
        if (kwicResults) {
            kwicResults.abort()
        }
        if ("lemgramResults" in window) {
            lemgramResults.abort()
        }
        if (statsResults) {
            statsResults.abort()
        }
    }
})

const corpusSettingsPromise = new Promise((resolve, reject) => {
    const createSplashScreen = () => {
        const korpLogo = require("../img/korplogo_block.svg")
        const splash = document.getElementById("preload")
        splash.innerHTML = `<img class="splash" height="300" width="300" src="${korpLogo}" />`
    }

    const createErrorScreen = () => {
        const korpFail = require("../img/korp_fail.svg")
        const elem = document.getElementById("preload")
        elem.innerHTML = `

                Sorry, Korp doesn't seem to work right now

        `
    }

    createSplashScreen()

    const labParam = window.isLab ? "&include_lab" : ""
    fetch(`${settings["korp_backend_url"]}/corpus_config?mode=${window.currentMode}${labParam}`)
        .then((response) => {
            if (!response.ok) {
                console.error("Something wrong with corpus config", response.statusText)
                createErrorScreen()
            }

            response.json().then((modeSettings) => {
                function rename(obj, from, to) {
                    if (obj[from]) {
                        obj[to] = obj[from]
                        delete obj[from]
                    }
                }

                rename(modeSettings["attributes"], "pos_attributes", "attributes")

                // take the backend configuration format for attributes and expand it
                // TODO the internal representation should be changed to a new, more compact one.
                for (const corpusId in modeSettings["corpora"]) {
                    const corpus = modeSettings["corpora"][corpusId]

                    rename(corpus, "pos_attributes", "attributes")
                    for (const attrType of ["attributes", "struct_attributes", "custom_attributes"]) {
                        const attrList = corpus[attrType]
                        const attrs = {}
                        for (const attrIdx in attrList) {
                            const attr = modeSettings["attributes"][attrType][attrList[attrIdx]]
                            attrs[attr.name] = attr
                        }
                        // attrs is an object of attribute settings
                        corpus[attrType] = attrs
                        // attrList is an ordered list of the preferred order of attributes
                        corpus[`_${attrType}_order`] = attrList
                    }
                    // TODO use the new format instead
                    // remake the new format of witihns and contex to the old
                    const sortingArr = ["sentence", "paragraph", "text", "1 sentence", "1 paragraph", "1 text"]
                    function contextWithinFix(list) {
                        // sort the list so that sentence is before paragraph
                        list.sort((a, b) => sortingArr.indexOf(a.value) - sortingArr.indexOf(b.value))
                        const res = {}
                        for (const elem of list) {
                            res[elem.value] = elem.value
                        }
                        return res
                    }
                    corpus["within"] = contextWithinFix(corpus["within"])
                    corpus["context"] = contextWithinFix(corpus["context"])
                }

                delete modeSettings["attributes"]

                if (!modeSettings["folders"]) {
                    modeSettings["folders"] = {}
                }
                resolve(modeSettings)
                document.getElementById("preload").remove()
            })
        })
        .catch(() => createErrorScreen())
})

Promise.all([loc_dfd, corpusSettingsPromise]).then(([locData, modeSettings]) => {
    _.assign(window.settings, modeSettings)

    setDefaultConfigValues()

    const corpora = settings.corpora

    if (!window.currentModeParallel) {
        settings.corpusListing = new CorpusListing(corpora)
    } else {
        settings.corpusListing = new ParallelCorpusListing(corpora)
    }

    // rewriting old language codes to new ones
    if (location.hash.includes("lang=")) {
        const match = /lang\=(.*?)(&|$)/.exec(location.hash)
        if (match) {
            const lang = match[1]
            if (settings.isoLanguages[lang]) {
                location.hash = location.hash.replace(`lang=${lang}`, `lang=${settings.isoLanguages[lang]}`)
            }
        }
    }

    try {
        angular.bootstrap(document, ["korpApp"])
    } catch (error) {
        c.error(error)
    }

    try {
        const corpus = locationSearch()["corpus"]
        if (corpus) {
            settings.corpusListing.select(corpus.split(","))
        }
        view.updateSearchHistory()
    } catch (error1) {
        c.error("ERROR setting corpora from location", error1)
    }

    if (isLab) {
        $("body").addClass("lab")
    }

    $("body").addClass(`mode-${window.currentMode}`)
    util.browserWarn()

    $("#search_history").change(function (event) {
        const target = $(this).find(":selected")
        if (_.includes(["http://", "https:/"], target.val().slice(0, 7))) {
            location.href = target.val()
        } else if (target.is(".clear")) {
            jStorage.set("searches", [])
            view.updateSearchHistory()
        }
    })

    let prevFragment = {}
    // Note that this is _not_ window.onhashchange (lowercase only) and is not called by the browser
    window.onHashChange = function (event, isInit) {
        const hasChanged = (key) => prevFragment[key] !== locationSearch()[key]
        if (hasChanged("lang")) {
            const newLang = locationSearch().lang || settings["default_language"]
            $("body").scope().lang = newLang
            window.lang = newLang
            util.localize()

            $("#languages").radioList("select", newLang)
        }

        if (isInit) {
            util.localize()
        }

        prevFragment = _.extend({}, locationSearch())
    }

    $("#languages").radioList({
        change() {
            const currentLang = $(this).radioList("getSelected").data("mode")
            locationSearch({
                lang: currentLang !== settings["default_language"] ? currentLang : null,
            })
        },
        // TODO: this does nothing?
        selected: settings["default_language"],
    })

    setTimeout(() => window.onHashChange(null, true), 0)
    $("#main").animate({ opacity: 1 }, function () {
        $(this).css("opacity", "")
    })
})
<commit_msg>fix parallel mode<commit_after>/** @format */
import statemachine from "@/statemachine"
import { setDefaultConfigValues } from "./settings"

const korpFailImg = require("../img/korp_fail.svg")
const deparam = require("jquery-deparam")

import jStorage from "../lib/jstorage"

window.authenticationProxy = new model.AuthenticationProxy()
window.timeProxy = new model.TimeProxy()

const creds = jStorage.get("creds")
if (creds) {
    authenticationProxy.loginObj = creds
    statemachine.send("USER_FOUND", creds)
} else {
    statemachine.send("USER_NOT_FOUND")
}

// rewriting old url format to the angular one
if (location.hash.length && location.hash[1] !== "?") {
    location.hash = `#?${_.trimStart(location.hash, "#")}`
}

$.ajaxSetup({
    dataType: "json",
    traditional: true,
})

$.ajaxPrefilter("json", function (options) {
    if (options.crossDomain && !$.support.cors) {
        return "jsonp"
    }
})

const loc_dfd = window.initLocales()
$(document).keyup(function (event) {
    if (event.keyCode === 27) {
        if (kwicResults) {
            kwicResults.abort()
        }
        if ("lemgramResults" in window) {
            lemgramResults.abort()
        }
        if (statsResults) {
            statsResults.abort()
        }
    }
})

const corpusSettingsPromise = new Promise((resolve, reject) => {
    const createSplashScreen = () => {
        const korpLogo = require("../img/korplogo_block.svg")
        const splash = document.getElementById("preload")
        splash.innerHTML = `<img class="splash" height="300" width="300" src="${korpLogo}" />`
    }

    const createErrorScreen = () => {
        const korpFail = require("../img/korp_fail.svg")
        const elem = document.getElementById("preload")
        elem.innerHTML = `

                Sorry, Korp doesn't seem to work right now

        `
    }

    createSplashScreen()

    const labParam = window.isLab ? "&include_lab" : ""
    fetch(`${settings["korp_backend_url"]}/corpus_config?mode=${window.currentMode}${labParam}`)
        .then((response) => {
            if (!response.ok) {
                console.error("Something wrong with corpus config", response.statusText)
                createErrorScreen()
            }

            response.json().then((modeSettings) => {
                window.currentModeParallel = modeSettings.parallel
                // only if the current mode is parallel, we load the special code required
                if (window.currentModeParallel) {
                    require("./parallel/corpus_listing.js")
                    require("./parallel/parallel_search.js")
                    require("./parallel/kwic_results.js")
                    require("./parallel/stats_proxy.js")
                }

                function rename(obj, from, to) {
                    if (obj[from]) {
                        obj[to] = obj[from]
                        delete obj[from]
                    }
                }

                rename(modeSettings["attributes"], "pos_attributes", "attributes")

                // take the backend configuration format for attributes and expand it
                // TODO the internal representation should be changed to a new, more compact one.
                for (const corpusId in modeSettings["corpora"]) {
                    const corpus = modeSettings["corpora"][corpusId]

                    rename(corpus, "pos_attributes", "attributes")
                    for (const attrType of ["attributes", "struct_attributes", "custom_attributes"]) {
                        const attrList = corpus[attrType]
                        const attrs = {}
                        for (const attrIdx in attrList) {
                            const attr = modeSettings["attributes"][attrType][attrList[attrIdx]]
                            attrs[attr.name] = attr
                        }
                        // attrs is an object of attribute settings
                        corpus[attrType] = attrs
                        // attrList is an ordered list of the preferred order of attributes
                        corpus[`_${attrType}_order`] = attrList
                    }
                    // TODO use the new format instead
                    // remake the new format of witihns and contex to the old
                    const sortingArr = ["sentence", "paragraph", "text", "1 sentence", "1 paragraph", "1 text"]
                    function contextWithinFix(list) {
                        // sort the list so that sentence is before paragraph
                        list.sort((a, b) => sortingArr.indexOf(a.value) - sortingArr.indexOf(b.value))
                        const res = {}
                        for (const elem of list) {
                            res[elem.value] = elem.value
                        }
                        return res
                    }
                    corpus["within"] = contextWithinFix(corpus["within"])
                    corpus["context"] = contextWithinFix(corpus["context"])
                }

                delete modeSettings["attributes"]

                if (!modeSettings["folders"]) {
                    modeSettings["folders"] = {}
                }
                resolve(modeSettings)
                document.getElementById("preload").remove()
            })
        })
        .catch(() => createErrorScreen())
})

Promise.all([loc_dfd, corpusSettingsPromise]).then(([locData, modeSettings]) => {
    _.assign(window.settings, modeSettings)

    setDefaultConfigValues()

    const corpora = settings.corpora

    if (!window.currentModeParallel) {
        settings.corpusListing = new CorpusListing(corpora)
    } else {
        settings.corpusListing = new ParallelCorpusListing(corpora)
    }

    // rewriting old language codes to new ones
    if (location.hash.includes("lang=")) {
        const match = /lang\=(.*?)(&|$)/.exec(location.hash)
        if (match) {
            const lang = match[1]
            if (settings.isoLanguages[lang]) {
                location.hash = location.hash.replace(`lang=${lang}`, `lang=${settings.isoLanguages[lang]}`)
            }
        }
    }

    try {
        angular.bootstrap(document, ["korpApp"])
    } catch (error) {
        c.error(error)
    }

    try {
        const corpus = locationSearch()["corpus"]
        if (corpus) {
            settings.corpusListing.select(corpus.split(","))
        }
        view.updateSearchHistory()
    } catch (error1) {
        c.error("ERROR setting corpora from location", error1)
    }

    if (isLab) {
        $("body").addClass("lab")
    }

    $("body").addClass(`mode-${window.currentMode}`)
    util.browserWarn()

    $("#search_history").change(function (event) {
        const target = $(this).find(":selected")
        if (_.includes(["http://", "https:/"], target.val().slice(0, 7))) {
            location.href = target.val()
        } else if (target.is(".clear")) {
            jStorage.set("searches", [])
            view.updateSearchHistory()
        }
    })

    let prevFragment = {}
    // Note that this is _not_ window.onhashchange (lowercase only) and is not called by the browser
    window.onHashChange = function (event, isInit) {
        const hasChanged = (key) => prevFragment[key] !== locationSearch()[key]
        if (hasChanged("lang")) {
            const newLang = locationSearch().lang || settings["default_language"]
            $("body").scope().lang = newLang
            window.lang = newLang
            util.localize()

            $("#languages").radioList("select", newLang)
        }

        if (isInit) {
            util.localize()
        }

        prevFragment = _.extend({}, locationSearch())
    }

    $("#languages").radioList({
        change() {
            const currentLang = $(this).radioList("getSelected").data("mode")
            locationSearch({
                lang: currentLang !== settings["default_language"] ? currentLang : null,
            })
        },
        // TODO: this does nothing?
        selected: settings["default_language"],
    })

    setTimeout(() => window.onHashChange(null, true), 0)
    $("#main").animate({ opacity: 1 }, function () {
        $(this).css("opacity", "")
    })
})
<|endoftext|>