<commit_before>var h = require('hyperscript');
var Hash = require('./hash');

// XXX require('global/mumble')
var window = global.window;
var document = global.document;

document.title = 'Flash Phrases';
document.head.appendChild(
    h('link', {
        rel: 'stylesheet',
        type: 'text/css',
        href: 'ui/style.css'
    }));

var style = Hash.get('style') || 'light';
var styleLink = document.head.appendChild(
    h('link', {
        rel: 'stylesheet',
        type: 'text/css',
        href: 'ui/style-' + style + '.css'
    }));

function changeStyle(name) {
    styleLink.href = 'ui/style-' + name + '.css';
    Hash.set('style', name);
    style = name;
}

////

var Engine = require('../lib/engine');
var Input = require('./input');
var Mode = require('./mode');
var PhraseData = require('./data');
var Timeout = require('./timeout');

var eng = new Engine({
    sessionCookie: 'session-key',
    base: 10,
    perLevel: 10,
    complexity: {
        initial: [2, 10],
        step: [1, 5],
        lo: [2, 10],
        hi: [10, 50]
    },
    maxErrorRate: 0.3
});

var input = new Input();

var mode = new Mode({
    initial: 'loading',
    modes: {
        error: h('div.error', ''),
        loading: h('div.loading', 'Loading...'),
        pause: h('div.pause', 'press <enter> to start'),
        display: h('div.display'),
        input: h('div.input', input.element)
    }
});
document.body.appendChild(mode.element);

var repromptDelay = 200;

var record = null;
function newRecord() {
    record = {
        displayedAt: NaN,
        inputShownAt: NaN,
        doneAt: NaN,
        elapsed: {
            display: NaN,
            input: NaN,
        },
        timeout: {
            display: NaN,
            input: NaN,
        },
        expected: null,
        got: null
    };
}
newRecord();

var displayTime = 1500;
var inputTime = 5000;
var timeout = new Timeout();

function evaluate(force) {
    eng.scoreResult(record, force);
    var done = force || record.finished;
    if (done) {
        timeout.clear();
        if (mode.mode === 'input') input.element.disabled = true;
        eng.onResult(record);
        newRecord();
        if (mode.mode !== 'pause') setTimeout(mode.setMode.bind(mode, 'display'), repromptDelay);
    }
    return done;
}

var lightsOut = document.body.appendChild(h(
    'div.lightsOut', {
        onclick: function() {
            changeStyle(style === 'light' ? 'dark' : 'light');
            lightsOut.innerHTML = style === 'light' ? 'Lights Out' : 'Lights On';
        }
    }, style === 'light' ? 'Lights Out' : 'Lights On'
));

input.on('data', function(got, force) {
    record.got = got;
    evaluate(force);
});

input.on('stop', function(event) {
    if (event.keyCode === 0x1b) {
        mode.setMode('pause', ['display', 'input']);
    }
});

mode.on('change', function(mode) {
    switch(mode) {
        case 'display':
            lightsOut.style.display = 'none';
            doDisplay();
            break;
        case 'input':
            showInput();
            break;
        case 'pause':
            lightsOut.style.display = '';
            if (record.expected !== null) evaluate(true);
            break;
    }
});

function doDisplay() {
    if (record.expected !== null) {
        console.error('throwing away previous record', record);
        newRecord();
    }
    record.expected = PhraseData.generatePhrase.apply(null, eng.complexity.value);
    record.got = '';
    record.displayedAt = Date.now();
    mode.panes.display.innerHTML = record.expected;
    record.timeout.display = displayTime;
    if (!evaluate()) timeout.set(mode.setMode.bind(mode, 'input'), displayTime);
}

function showInput() {
    input.element.value = '';
    input.element.size = record.expected.length + 2;
    input.element.disabled = false;
    input.element.focus();
    record.inputShownAt = Date.now();
    record.timeout.input = inputTime;
    timeout.set(evaluate.bind(null, true), inputTime);
}

window.addEventListener('keydown', function(event) {
    if (event.keyCode === 0x1b) { // <esc>
        event.preventDefault();
        event.stopPropagation();
        mode.setMode('pause', ['display', 'input']);
    }
});

window.addEventListener('keypress', function(event) {
    switch(event.charCode) {
        case 0x0a: // nl
        case 0x0d: // cr
        case 0x20: // <space>
            mode.setMode('display', 'pause');
            break;
        default:
            if (mode.mode === 'display') {
                var char = String.fromCharCode(event.charCode);
                if (char !== record.expected[0]) return;
                event.stopPropagation();
                event.preventDefault();
                mode.setMode('input');
                input.element.value = char;
                input.update();
            }
    }
});

window.addEventListener('blur', function() {
    mode.setMode('pause', ['display', 'input']);
});

eng.on('ready', function() {
    mode.setMode('pause', 'loading');
});
eng.on('error', function(err) {
    mode.setMode('error');
    mode.panes.error.innerHTML = String(err);
    console.error(err);
});
eng.on('idle', mode.setMode.bind(mode, 'pause', ['display', 'input']));
eng.on('setTimeout', function(kind, val) {
    switch (kind) {
        case 'display':
            displayTime = val;
            break;
        case 'input':
            inputTime = val;
            break;
    }
});
<commit_msg>Refactor reprompt state change pattern<commit_after>var h = require('hyperscript');
var Hash = require('./hash');

// XXX require('global/mumble')
var window = global.window;
var document = global.document;

document.title = 'Flash Phrases';
document.head.appendChild(
    h('link', {
        rel: 'stylesheet',
        type: 'text/css',
        href: 'ui/style.css'
    }));

var style = Hash.get('style') || 'light';
var styleLink = document.head.appendChild(
    h('link', {
        rel: 'stylesheet',
        type: 'text/css',
        href: 'ui/style-' + style + '.css'
    }));

function changeStyle(name) {
    styleLink.href = 'ui/style-' + name + '.css';
    Hash.set('style', name);
    style = name;
}

////

var Engine = require('../lib/engine');
var Input = require('./input');
var Mode = require('./mode');
var PhraseData = require('./data');
var Timeout = require('./timeout');

var eng = new Engine({
    sessionCookie: 'session-key',
    base: 10,
    perLevel: 10,
    complexity: {
        initial: [2, 10],
        step: [1, 5],
        lo: [2, 10],
        hi: [10, 50]
    },
    maxErrorRate: 0.3
});

var input = new Input();

var mode = new Mode({
    initial: 'loading',
    modes: {
        error: h('div.error', ''),
        loading: h('div.loading', 'Loading...'),
        pause: h('div.pause', 'press <enter> to start'),
        display: h('div.display'),
        input: h('div.input', input.element)
    }
});
document.body.appendChild(mode.element);

var repromptDelay = 200;

var record = null;
function newRecord() {
    record = {
        displayedAt: NaN,
        inputShownAt: NaN,
        doneAt: NaN,
        elapsed: {
            display: NaN,
            input: NaN,
        },
        timeout: {
            display: NaN,
            input: NaN,
        },
        expected: null,
        got: null
    };
}
newRecord();

var displayTime = 1500;
var inputTime = 5000;
var timeout = new Timeout();

function evaluate(force) {
    eng.scoreResult(record, force);
    var done = force || record.finished;
    if (done) {
        timeout.clear();
        eng.onResult(record);
        newRecord();
        if (mode.mode === 'input') {
            input.element.disabled = true;
            setTimeout(mode.setMode.bind(mode, 'display', 'input'), repromptDelay);
        }
    }
    return done;
}

var lightsOut = document.body.appendChild(h(
    'div.lightsOut', {
        onclick: function() {
            changeStyle(style === 'light' ? 'dark' : 'light');
            lightsOut.innerHTML = style === 'light' ? 'Lights Out' : 'Lights On';
        }
    }, style === 'light' ? 'Lights Out' : 'Lights On'
));

input.on('data', function(got, force) {
    record.got = got;
    evaluate(force);
});

input.on('stop', function(event) {
    if (event.keyCode === 0x1b) {
        mode.setMode('pause', ['display', 'input']);
    }
});

mode.on('change', function(mode) {
    switch(mode) {
        case 'display':
            lightsOut.style.display = 'none';
            doDisplay();
            break;
        case 'input':
            showInput();
            break;
        case 'pause':
            lightsOut.style.display = '';
            if (record.expected !== null) evaluate(true);
            break;
    }
});

function doDisplay() {
    if (record.expected !== null) {
        console.error('throwing away previous record', record);
        newRecord();
    }
    record.expected = PhraseData.generatePhrase.apply(null, eng.complexity.value);
    record.got = '';
    record.displayedAt = Date.now();
    mode.panes.display.innerHTML = record.expected;
    record.timeout.display = displayTime;
    if (!evaluate()) timeout.set(mode.setMode.bind(mode, 'input'), displayTime);
}

function showInput() {
    input.element.value = '';
    input.element.size = record.expected.length + 2;
    input.element.disabled = false;
    input.element.focus();
    record.inputShownAt = Date.now();
    record.timeout.input = inputTime;
    timeout.set(evaluate.bind(null, true), inputTime);
}

window.addEventListener('keydown', function(event) {
    if (event.keyCode === 0x1b) { // <esc>
        event.preventDefault();
        event.stopPropagation();
        mode.setMode('pause', ['display', 'input']);
    }
});

window.addEventListener('keypress', function(event) {
    switch(event.charCode) {
        case 0x0a: // nl
        case 0x0d: // cr
        case 0x20: // <space>
            mode.setMode('display', 'pause');
            break;
        default:
            if (mode.mode === 'display') {
                var char = String.fromCharCode(event.charCode);
                if (char !== record.expected[0]) return;
                event.stopPropagation();
                event.preventDefault();
                mode.setMode('input');
                input.element.value = char;
                input.update();
            }
    }
});

window.addEventListener('blur', function() {
    mode.setMode('pause', ['display', 'input']);
});

eng.on('ready', function() {
    mode.setMode('pause', 'loading');
});
eng.on('error', function(err) {
    mode.setMode('error');
    mode.panes.error.innerHTML = String(err);
    console.error(err);
});
eng.on('idle', mode.setMode.bind(mode, 'pause', ['display', 'input']));
eng.on('setTimeout', function(kind, val) {
    switch (kind) {
        case 'display':
            displayTime = val;
            break;
        case 'input':
            inputTime = val;
            break;
    }
});
<|endoftext|>


<commit_before>
uiModule.gis = function() {
  if (!(this instanceof uiModule.gis)) {
    return new uiModule.gis();
  }

  return this;
};

/**
 * Create a placeholder to display current layers
 *
 * @param rootId
 * @param heading
 */
uiModule.gis.createGisLayerList = function(rootId, heading) {
  var listRoot = document.getElementById(rootId);
  var itemRoot = document.createElement("div");
  itemRoot.setAttribute("class", "accordion-group");
  listRoot.appendChild(itemRoot);

  var itemHeading = document.createElement("div");
  itemHeading.setAttribute("class", "accordion-heading");
  itemRoot.appendChild(itemHeading);

  var itemCollection = document.createElement("a");
  itemCollection.setAttribute("class", "accordion-toggle");
  itemCollection.setAttribute("data-toggle", "collapse");
  itemCollection.setAttribute("data-parent", "#"+rootId);
  itemCollection.setAttribute("href", "#collapse-"+rootId);
  itemCollection.appendChild(document.createTextNode(heading));
  itemHeading.appendChild(itemCollection);

  var subItemsRoot = document.createElement("div");
  subItemsRoot.setAttribute("class", "accordion-body collapse in");
  subItemsRoot.setAttribute("id", "collapse-"+rootId);
  itemRoot.appendChild(subItemsRoot);
  var subItemsList = document.createElement("div");
  subItemsList.setAttribute("class", "accordion-inner");
  subItemsRoot.appendChild(subItemsList);

  var tableRoot = document.createElement("table");
  tableRoot.setAttribute("id", rootId + '-table');
  subItemsList.appendChild(tableRoot);

  var tbody = document.createElement("tbody");
  tableRoot.appendChild(tbody);
};

/**
 * Create a list of documents that could be added as a layer
 *
 * @param rootId
 * @param heading
 * @param layersRootId
 * @param data
 */
uiModule.gis.createGisDataList = function(rootId, heading, layersRootId, data, callback) {
  var listRoot = document.getElementById(rootId);
  var itemRoot = document.createElement("div");
  itemRoot.setAttribute("class", "accordion-group");
  listRoot.appendChild(itemRoot);

  var itemHeading = document.createElement("div");
  itemHeading.setAttribute("class", "accordion-heading");
  itemRoot.appendChild(itemHeading);

  var itemCollection = document.createElement("a");
  itemCollection.setAttribute("class", "accordion-toggle");
  itemCollection.setAttribute("data-toggle", "collapse");
  itemCollection.setAttribute("data-parent", "#"+rootId);
  itemCollection.setAttribute("href", "#collapse-"+rootId);
  itemCollection.appendChild(document.createTextNode(heading));
  itemHeading.appendChild(itemCollection);

  var subItemsRoot = document.createElement("div");
  subItemsRoot.setAttribute("class", "accordion-body collapse in");
  subItemsRoot.setAttribute("id", "collapse-"+rootId);
  itemRoot.appendChild(subItemsRoot);
  var subItemsList = document.createElement("div");
  subItemsList.setAttribute("class", "accordion-inner");
  subItemsRoot.appendChild(subItemsList);
  var tableRoot = document.createElement("table");
  tableRoot.setAttribute('class', 'table-striped table-hover');
  subItemsList.appendChild(tableRoot);

  $.each(data, function(i, item) {
    var row = document.createElement("tr");
    row.setAttribute("class", "success");
    tableRoot.appendChild(row);
    var col = document.createElement("td");
    var he = document.createElement("h4");
    he.innerHTML = item.basename;
    col.appendChild(he);
    row.appendChild(col);

    // Add drop-down so that users can select a variable
    col = document.createElement("td");
    var select = document.createElement('select');
    select.setAttribute('class', 'combobox');
    col.appendChild(select);
    for (var k = 0; k < item.variables.length; ++k) {
      var varname = item.variables[k].name;
      var option= document.createElement('option');
      option.setAttribute('value', varname);
      option.innerHTML = varname;
      select.appendChild(option);
    }
    row.appendChild(col);

    // Add 'add' button
    col = document.createElement("td");
    var button = document.createElement("button");
    button.setAttribute("type", "button");
    button.setAttribute("class", "btn btn-primary");
    button.setAttribute("id", "btn-add-" + item.name);
    button.setAttribute("_id", item._id);
    button.setAttribute("name", item.name);
    button.setAttribute("basename", item.basename);
    button.setAttribute("data-toggle", "button");
    button.appendChild(document.createTextNode("Add"));
    col.appendChild(button);
    row.appendChild(col);

    if (callback != undefined) {
      $(button).on("click", callback);
      /*$(button).on("click", function() {
        geoModule.addLayer(layersRootId, this);
        $(button).attr("disabled", "disabled");
      });*/
    }
  });

  $('.combobox').select2();
};

/**
 * Add a document as a layer to the list
 *
 * @todo Actually load a layer
 *
 * @param layersRootId
 * @param elem
 */
uiModule.gis.addLayer = function(object, layersRootId, elem, togglefunc, removefunc, callback) {
  var rootId = "#" + layersRootId;
  var _id = $(elem).attr("_id");
  if (_id !== null) {
    var tbody = $(rootId).find('tbody');
    var basename = $(elem).attr("name");
    $(elem).removeClass("btn-primary");
    $(elem).addClass("btn-success");
    $(elem).addClass("disabled");
    var layerId = basename;
    $(tbody).append("
");
    $(rootId + " tr:last").append("
" + basename + "
	")
    $(rootId + " tr:last").append("<button class='btn-layer btn btn-warning disabled' disabled='disabled' onclick="+togglefunc+"('"+basename+"')> Toggle </button>	")
    $(rootId + " tr:last").append("<button class='btn-layer btn btn-danger disabled' disabled='disabled' onclick="+removefunc+"('"+basename+"')> Remove </button>	")
    layerId = '#'+layerId;

    $('.btn-layer').width(Math.max.apply(Math,
                                            $('.btn-layer').map(function(){
                                              return $(this).outerWidth();}).get()));
    }
    // @todo Just calling fadeIn does not work. It has to be set invisible
    // and then only it works. We need to check if this is expected.
    $(layerId).fadeOut(0);
    $(layerId).fadeIn('slow', callback);
};

/**
 * Remove a layer from the list
 *
 * @param elem
 * @returns {Boolean}
 */
uiModule.gis.removeLayer = function(layerId) {
  var buttonId = $('#btn-add-'+layerId);
  var button = $(buttonId);

  if (button !== null || button !== undefined) {
    button.removeClass('disabled');
    button.removeClass('btn-success');
    button.removeClass('active');
    button.addClass('btn-primary');

    $('#' + layerId).fadeOut(function() {
      $('#' + layerId).remove();
    });

    return true;
  }

  return false;
};

uiModule.gis.toggleLayer = function(layerId) {

}
<commit_msg>Put toggle and remove button next to each other<commit_after>
uiModule.gis = function() {
  if (!(this instanceof uiModule.gis)) {
    return new uiModule.gis();
  }

  return this;
};

/**
 * Create a placeholder to display current layers
 *
 * @param rootId
 * @param heading
 */
uiModule.gis.createGisLayerList = function(rootId, heading) {
  var listRoot = document.getElementById(rootId);
  var itemRoot = document.createElement("div");
  itemRoot.setAttribute("class", "accordion-group");
  listRoot.appendChild(itemRoot);

  var itemHeading = document.createElement("div");
  itemHeading.setAttribute("class", "accordion-heading");
  itemRoot.appendChild(itemHeading);

  var itemCollection = document.createElement("a");
  itemCollection.setAttribute("class", "accordion-toggle");
  itemCollection.setAttribute("data-toggle", "collapse");
  itemCollection.setAttribute("data-parent", "#"+rootId);
  itemCollection.setAttribute("href", "#collapse-"+rootId);
  itemCollection.appendChild(document.createTextNode(heading));
  itemHeading.appendChild(itemCollection);

  var subItemsRoot = document.createElement("div");
  subItemsRoot.setAttribute("class", "accordion-body collapse in");
  subItemsRoot.setAttribute("id", "collapse-"+rootId);
  itemRoot.appendChild(subItemsRoot);
  var subItemsList = document.createElement("div");
  subItemsList.setAttribute("class", "accordion-inner");
  subItemsRoot.appendChild(subItemsList);

  var tableRoot = document.createElement("table");
  tableRoot.setAttribute("id", rootId + '-table');
  subItemsList.appendChild(tableRoot);

  var tbody = document.createElement("tbody");
  tableRoot.appendChild(tbody);
};

/**
 * Create a list of documents that could be added as a layer
 *
 * @param rootId
 * @param heading
 * @param layersRootId
 * @param data
 */
uiModule.gis.createGisDataList = function(rootId, heading, layersRootId, data, callback) {
  var listRoot = document.getElementById(rootId);
  var itemRoot = document.createElement("div");
  itemRoot.setAttribute("class", "accordion-group");
  listRoot.appendChild(itemRoot);

  var itemHeading = document.createElement("div");
  itemHeading.setAttribute("class", "accordion-heading");
  itemRoot.appendChild(itemHeading);

  var itemCollection = document.createElement("a");
  itemCollection.setAttribute("class", "accordion-toggle");
  itemCollection.setAttribute("data-toggle", "collapse");
  itemCollection.setAttribute("data-parent", "#"+rootId);
  itemCollection.setAttribute("href", "#collapse-"+rootId);
  itemCollection.appendChild(document.createTextNode(heading));
  itemHeading.appendChild(itemCollection);

  var subItemsRoot = document.createElement("div");
  subItemsRoot.setAttribute("class", "accordion-body collapse in");
  subItemsRoot.setAttribute("id", "collapse-"+rootId);
  itemRoot.appendChild(subItemsRoot);
  var subItemsList = document.createElement("div");
  subItemsList.setAttribute("class", "accordion-inner");
  subItemsRoot.appendChild(subItemsList);
  var tableRoot = document.createElement("table");
  tableRoot.setAttribute('class', 'table-striped table-hover');
  subItemsList.appendChild(tableRoot);

  $.each(data, function(i, item) {
    var row = document.createElement("tr");
    row.setAttribute("class", "success");
    tableRoot.appendChild(row);
    var col = document.createElement("td");
    var he = document.createElement("h4");
    he.innerHTML = item.basename;
    col.appendChild(he);
    row.appendChild(col);

    // Add drop-down so that users can select a variable
    col = document.createElement("td");
    var select = document.createElement('select');
    select.setAttribute('class', 'combobox');
    col.appendChild(select);
    for (var k = 0; k < item.variables.length; ++k) {
      var varname = item.variables[k].name;
      var option= document.createElement('option');
      option.setAttribute('value', varname);
      option.innerHTML = varname;
      select.appendChild(option);
    }
    row.appendChild(col);

    // Add 'add' button
    col = document.createElement("td");
    var button = document.createElement("button");
    button.setAttribute("type", "button");
    button.setAttribute("class", "btn btn-primary");
    button.setAttribute("id", "btn-add-" + item.name);
    button.setAttribute("_id", item._id);
    button.setAttribute("name", item.name);
    button.setAttribute("basename", item.basename);
    button.setAttribute("data-toggle", "button");
    button.appendChild(document.createTextNode("Add"));
    col.appendChild(button);
    row.appendChild(col);

    if (callback != undefined) {
      $(button).on("click", callback);
      /*$(button).on("click", function() {
        geoModule.addLayer(layersRootId, this);
        $(button).attr("disabled", "disabled");
      });*/
    }
  });

  $('.combobox').select2();
};

/**
 * Add a document as a layer to the list
 *
 * @todo Actually load a layer
 *
 * @param layersRootId
 * @param elem
 */
uiModule.gis.addLayer = function(object, layersRootId, elem, togglefunc, removefunc, callback) {
  var rootId = "#" + layersRootId;
  var _id = $(elem).attr("_id");
  if (_id !== null) {
    var tbody = $(rootId).find('tbody');
    var basename = $(elem).attr("name");
    $(elem).removeClass("btn-primary");
    $(elem).addClass("btn-success");
    $(elem).addClass("disabled");
    var layerId = basename;
    $(tbody).append("
");
    $(rootId + " tr:last").append("
" + basename + "
	")
    $(rootId + " tr:last").append("<button class='btn-layer btn btn-warning disabled' disabled='disabled' onclick="+togglefunc+"('"+basename+"')> Toggle </button>")
    $(rootId + " td:last").append("<button class='btn-layer btn btn-danger disabled' disabled='disabled' onclick="+removefunc+"('"+basename+"')> Remove </button>	")
    layerId = '#'+layerId;

    $('.btn-layer').width(Math.max.apply(Math,
                                            $('.btn-layer').map(function(){
                                              return $(this).outerWidth();}).get()));
    }
    // @todo Just calling fadeIn does not work. It has to be set invisible
    // and then only it works. We need to check if this is expected.
    $(layerId).fadeOut(0);
    $(layerId).fadeIn('slow', callback);
};

/**
 * Remove a layer from the list
 *
 * @param elem
 * @returns {Boolean}
 */
uiModule.gis.removeLayer = function(layerId) {
  var buttonId = $('#btn-add-'+layerId);
  var button = $(buttonId);

  if (button !== null || button !== undefined) {
    button.removeClass('disabled');
    button.removeClass('btn-success');
    button.removeClass('active');
    button.addClass('btn-primary');

    $('#' + layerId).fadeOut(function() {
      $('#' + layerId).remove();
    });

    return true;
  }

  return false;
};

uiModule.gis.toggleLayer = function(layerId) {

}
<|endoftext|>


<commit_before>var $slider;
$(function() {
  var appendSlider = function() {
    var html = _.template($('#slides-template').html());
    $('#qunit-fixture').html(html);
  };
  appendSlider();
  $slider = $('#slides').superslides();

  test('It initializes', function() {
    ok($slider.data('superslides'));
  });

  module('API');
  test('.size()', function() {
    size = $slider.superslides('size');
    equal(size, 1, 'should be 1');
  });

});<commit_msg>Add tests for play, stop<commit_after>var $slider;
$(function() {
  var appendSlider = function() {
    var html = _.template($('#slides-template').html());
    $('#qunit-fixture').html(html);
  };
  appendSlider();
  $slider = $('#slides').superslides({
    play: true
  });

  test('It initializes', function() {
    ok($slider.data('superslides'));
  });

  module('API');
  test('.size()', function() {
    size = $slider.superslides('size');
    equal(size, 1, 'should be 1');
  });

  test('.play()', function() {
    $slider.superslides('play');
    ok($slider.data('superslides').play_id);
  });

  test('.stop()', function() {
    $slider.superslides('stop');
    ok(!$slider.data('superslides').play_id);
  });
});<|endoftext|>


<commit_before>/*
//taking too long! need to rewrite. the time complexity is n^2,
var largestPrimeFactor = function(num){
  var largestPrime = 1;
  if (num <= 2) {return num;}
  var primeList = [2];

  for (var i = 2; i < num; i ++) {
    for (var j = 0; j < primeList.length; j ++) {
      if (i % primeList[j] === 0) {
        break;
      }
    }
    if (j === primeList.length) {
      primeList.push(i);
      if (num % i === 0 && i > largestPrime) {
        largestPrime = i;
      }
    }
  }
  return largestPrime;
};
//even the linear time is not satisfying.
// this following function will cause the repl.it to break
//aim for log(n)
var largestPrimeFactor = function(num) {
  var result = [];
  var prevFactor = [];
  var max = 0;
  //O(n) to get the common factor
  for (var i = 2; i < num; i ++) {
    if (num % i === 0 && i > max) {
      // for(var j = 0; j < prevFactor.length; j ++) {
      //   if (i % j === 0) {
      //     break;
      //   }
      // }
      // if (j === prevFactor.length) {
        // result.push(i);
      // }
      max = i;
    }
  }
  // for (var k = result.length; k >=0; k--) {
  //   if (isPrime(k)){
  //     return k;
  //   }
  // }
  // return result[result.length -1];
  return max;
};
*/

// optimization
var largestPrimeFactor = function(num) {
  for (var i = 0; i < num; i ++) {
    while (num % i === 0) {
      num = num / i;
    }
  }

  return num;
};

largestPrimeFactor(600851475143);<commit_msg>remove the inefficient solution<commit_after>

// optimization
var largestPrimeFactor = function(num) {
  for (var i = 2; i < num; i ++) {
    while (num % i === 0) {
      num = num / i;
    }
  }
  return num;
};

largestPrimeFactor(600851475143);<|endoftext|>


<commit_before>/*eslint no-console: ["error", { allow: ["log"] }] */

var assert = require('chai').assert;
var validate = require('../index.js');
var request = require('sync-request');
var fs = require('fs');
var AdmZip = require('adm-zip');
var path = require('path');
var Test = require("mocha/lib/test");
var test_version = "1.0.0-rc3u5";

function getDirectories(srcpath) {
    return fs.readdirSync(srcpath).filter(function(file) {
        return fs.statSync(path.join(srcpath, file)).isDirectory();
    });
}

var missing_session_files = ['7t_trt', 'ds006', 'ds007', 'ds008', 'ds051', 'ds052', 'ds105', 'ds108', 'ds109', 'ds113b'];

var suite = describe('BIDS example datasets ', function() {
    this.timeout(100000);

    before(function(done) {
        if (!fs.existsSync("tests/data/BIDS-examples-" + test_version + "/")) {
            console.log('downloading test data');
            var response = request("GET", "http://github.com/INCF/BIDS-examples/archive/" + test_version + ".zip");
            if (!fs.existsSync("tests/data")) {
                fs.mkdirSync("tests/data");
            }
            fs.writeFileSync("tests/data/examples.zip", response.body);
            var zip = new AdmZip("tests/data/examples.zip");
            console.log('unzipping test data');
            zip.extractAllTo("tests/data/", true);
        }

        var datasetDirectories = getDirectories("tests/data/BIDS-examples-" + test_version + "/");

        datasetDirectories.forEach(function testDataset(path){
            suite.addTest(new Test(path, function (isdone){
                var options = {ignoreNiftiHeaders: true};
                validate.BIDS("tests/data/BIDS-examples-" + test_version + "/" + path + "/", options, function (errors, warnings) {
                    assert.deepEqual(errors, []);
                    var session_flag = false;
                    for (var warning in warnings) {
                        if (warnings[warning]['code'] === '38') {
                            session_flag = true;
                            break;
                        }
                    }
                    if (missing_session_files.indexOf(path) === -1) {
                        assert.deepEqual(session_flag, false);
                    } else {
                        assert.deepEqual(session_flag, true);
                    }
                    isdone();
                });
            }));
        });
        done();
    });

    // we need to have at least one non-dynamic test
    it('validates path without trailing backslash', function(isdone) {
        var options = {ignoreNiftiHeaders: true};
        validate.BIDS("tests/data/BIDS-examples-" + test_version + "/ds001", options, function (errors, warnings, summary) {
            assert(summary.sessions.length === 0);
            assert(summary.subjects.length === 16);
            assert.deepEqual(summary.tasks, ['balloon analog risk task']);
            assert.deepEqual(summary.modalities, ['T1w', 'inplaneT2', 'bold']);
            assert(summary.totalFiles === 133);
            assert(summary.size === 803546);
            assert.deepEqual(errors, []);
            isdone();
        });
    });

    // we need to have at least one non-dynamic test
    it('validates dataset with valid nifti headers', function(isdone) {
        var options = {ignoreNiftiHeaders: false};
        validate.BIDS("tests/data/valid_headers", options, function (errors, warnings, summary) {
            assert(summary.sessions.length === 0);
            assert(summary.subjects.length === 1);
            assert.deepEqual(summary.tasks, ['rhyme judgment']);
            assert.deepEqual(summary.modalities, ['T1w', 'bold']);
            assert(summary.totalFiles === 8);
            assert(summary.size === 481765);
            assert.deepEqual(errors, []);
            isdone();
        });
    });
});
<commit_msg>Add warning assertions<commit_after>/*eslint no-console: ["error", { allow: ["log"] }] */

var assert = require('chai').assert;
var validate = require('../index.js');
var request = require('sync-request');
var fs = require('fs');
var AdmZip = require('adm-zip');
var path = require('path');
var Test = require("mocha/lib/test");
var test_version = "1.0.0-rc3u5";

function getDirectories(srcpath) {
    return fs.readdirSync(srcpath).filter(function(file) {
        return fs.statSync(path.join(srcpath, file)).isDirectory();
    });
}

var missing_session_files = ['7t_trt', 'ds006', 'ds007', 'ds008', 'ds051', 'ds052', 'ds105', 'ds108', 'ds109', 'ds113b'];

var suite = describe('BIDS example datasets ', function() {
    this.timeout(100000);

    before(function(done) {
        if (!fs.existsSync("tests/data/BIDS-examples-" + test_version + "/")) {
            console.log('downloading test data');
            var response = request("GET", "http://github.com/INCF/BIDS-examples/archive/" + test_version + ".zip");
            if (!fs.existsSync("tests/data")) {
                fs.mkdirSync("tests/data");
            }
            fs.writeFileSync("tests/data/examples.zip", response.body);
            var zip = new AdmZip("tests/data/examples.zip");
            console.log('unzipping test data');
            zip.extractAllTo("tests/data/", true);
        }

        var datasetDirectories = getDirectories("tests/data/BIDS-examples-" + test_version + "/");

        datasetDirectories.forEach(function testDataset(path){
            suite.addTest(new Test(path, function (isdone){
                var options = {ignoreNiftiHeaders: true};
                validate.BIDS("tests/data/BIDS-examples-" + test_version + "/" + path + "/", options, function (errors, warnings) {
                    assert.deepEqual(errors, []);
                    var session_flag = false;
                    for (var warning in warnings) {
                        if (warnings[warning]['code'] === '38') {
                            session_flag = true;
                            break;
                        }
                    }
                    if (missing_session_files.indexOf(path) === -1) {
                        assert.deepEqual(session_flag, false);
                    } else {
                        assert.deepEqual(session_flag, true);
                    }
                    isdone();
                });
            }));
        });
        done();
    });

    // we need to have at least one non-dynamic test
    it('validates path without trailing backslash', function(isdone) {
        var options = {ignoreNiftiHeaders: true};
        validate.BIDS("tests/data/BIDS-examples-" + test_version + "/ds001", options, function (errors, warnings, summary) {
            assert(summary.sessions.length === 0);
            assert(summary.subjects.length === 16);
            assert.deepEqual(summary.tasks, ['balloon analog risk task']);
            assert.deepEqual(summary.modalities, ['T1w', 'inplaneT2', 'bold']);
            assert(summary.totalFiles === 133);
            assert(summary.size === 803546);
            assert.deepEqual(errors, []);
            assert(warnings.length === 1 && warnings[0].code === '13');
            isdone();
        });
    });

    // we need to have at least one non-dynamic test
    it('validates dataset with valid nifti headers', function(isdone) {
        var options = {ignoreNiftiHeaders: false};
        validate.BIDS("tests/data/valid_headers", options, function (errors, warnings, summary) {
            assert(summary.sessions.length === 0);
            assert(summary.subjects.length === 1);
            assert.deepEqual(summary.tasks, ['rhyme judgment']);
            assert.deepEqual(summary.modalities, ['T1w', 'bold']);
            assert(summary.totalFiles === 8);
            assert(summary.size === 481765);
            assert.deepEqual(errors, []);
            assert(warnings.length === 1 && warnings[0].code === '13');
            isdone();
        });
    });
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
"use strict";

const source = "https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.csv";
const got = require("got");
const csvParse = require("csv-parse");
const fs = require("fs");

got(source).catch(console.error).then(res => {
  csvParse(res.body, {}, (err, data) => {
    if (err) return exit(err);
    parsePorts(data, err => {
      if (err) return exit(err);
      parseServices(data, err => {
        if (err) return exit(err);
        process.exit(0);
      });
    });
  });
});

function exit(err) {
  console.error(err);
  process.exit(1);
}

function parsePorts(data, cb) {
  const output = {};
  data.forEach(entry => {
    if (entry[1] && entry[2] && !output[entry[1] + "/" + entry[2]] && !isNaN(Number(entry[1]))) {
      output[entry[1] + "/" + entry[2]] = {
        name: entry[0],
        description: cleanupDescription(entry[3]),
      };
    }
  });
  fs.writeFile("./ports.json", JSON.stringify(output, null, 2), cb);
}

function parseServices(data, cb) {
  const output = {};
  data.forEach(entry => {
    if (!output[entry[0]] && entry[1] && entry[2] && typeof entry[0] === "string" &&
      entry[0].length && !isNaN(Number(entry[1]))) {
      output[entry[0]] = {
        ports: [Number(entry[1]) + "/" + entry[2]],
        description: cleanupDescription(entry[3]),
      };
    } else if (output[entry[0]] && entry[1] && entry[2] && typeof entry[0] === "string" &&
           entry[0].length && !isNaN(Number(entry[1])) &&
           output[entry[0]].ports.indexOf(Number(entry[1]) + "/" + entry[2]) === -1) {
      output[entry[0]].ports.push(entry[1] + "/" + entry[2]);
    }
  });
  fs.writeFile("./services.json", JSON.stringify(output, null, 2), cb);
}

function cleanupDescription(str) {
  if (!str) return undefined;

  // remove historical descriptions
  str = str.replace(/\nIANA assigned this.*/gm, "");

  // force description to be single-line
  str = str.replace(/[\s\n]+/g, " ");

  return str;
}
<commit_msg>trim description<commit_after>#!/usr/bin/env node
#!/usr/bin/env node
"use strict";

const source = "https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.csv";
const got = require("got");
const csvParse = require("csv-parse");
const fs = require("fs");

got(source).catch(console.error).then(res => {
  csvParse(res.body, {}, (err, data) => {
    if (err) return exit(err);
    parsePorts(data, err => {
      if (err) return exit(err);
      parseServices(data, err => {
        if (err) return exit(err);
        process.exit(0);
      });
    });
  });
});

function exit(err) {
  console.error(err);
  process.exit(1);
}

function parsePorts(data, cb) {
  const output = {};
  data.forEach(entry => {
    if (entry[1] && entry[2] && !output[entry[1] + "/" + entry[2]] && !isNaN(Number(entry[1]))) {
      output[entry[1] + "/" + entry[2]] = {
        name: entry[0],
        description: cleanupDescription(entry[3]),
      };
    }
  });
  fs.writeFile("./ports.json", JSON.stringify(output, null, 2), cb);
}

function parseServices(data, cb) {
  const output = {};
  data.forEach(entry => {
    if (!output[entry[0]] && entry[1] && entry[2] && typeof entry[0] === "string" &&
      entry[0].length && !isNaN(Number(entry[1]))) {
      output[entry[0]] = {
        ports: [Number(entry[1]) + "/" + entry[2]],
        description: cleanupDescription(entry[3]),
      };
    } else if (output[entry[0]] && entry[1] && entry[2] && typeof entry[0] === "string" &&
           entry[0].length && !isNaN(Number(entry[1])) &&
           output[entry[0]].ports.indexOf(Number(entry[1]) + "/" + entry[2]) === -1) {
      output[entry[0]].ports.push(entry[1] + "/" + entry[2]);
    }
  });
  fs.writeFile("./services.json", JSON.stringify(output, null, 2), cb);
}

function cleanupDescription(str) {
  if (!str) return undefined;

  // remove historical descriptions
  str = str.replace(/\nIANA assigned this.*/gm, "");

  // force description to be single-line
  str = str.replace(/[\s\n]+/g, " ");

  return (str || "").trim();
}
<|endoftext|>


<commit_before>(function () {
  "use strict";

  var app = angular.module('viewCustom', ['angularLoad']);

  app.run(['$rootScope', '$location', '$window', function ($rootScope, $location, $window) {
    //record GA page view event to new primo tracker GA ID
    $rootScope.$on('$locationChangeSuccess', function (event) {
      //temporarily create a tracker specifically to new Primo
      if ($window.ga) {
        $window.ga(function () {
          $window.ga('create', 'UA-4365437-14', 'search.library.uq.edu.au', 'NewPrimoTracker');
        });
        $window.ga('NewPrimoTracker.send', 'pageview', { location: $location.url() });
      }
    });

  }]);

  app.component('prmTopBarBefore', {
    template: '
<uqlibrary-alerts></uqlibrary-alerts>
' +
      '
<uq-minimal-header show-login-button="false"></uq-minimal-header>
'
  });

  // based on https://knowledge.exlibrisgroup.com/Primo/Community_Knowledge/How_to_create_a_%E2%80%98Report_a_Problem%E2%80%99_button_below_the_ViewIt_iframe
  app.component('prmFullViewServiceContainerAfter', {
    bindings: {parentCtrl: '<'},
    controller: function($scope){
      var vm = this;

      vm.targeturl = '';

      var recordId = '';
      // no one knows what the TN actually means (per SVG), but in practice all the CDI records have it on their record id
      if (!!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.control && !!vm.parentCtrl.item.pnx.control.recordid &&
          vm.parentCtrl.item.pnx.control.recordid[0] && vm.parentCtrl.item.pnx.control.recordid[0].startsWith('TN')) {
        recordId = encodeURIComponent(vm.parentCtrl.item.pnx.control.recordid);
      }
      if (recordId === '') {
        if (!!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.search && !!vm.parentCtrl.item.pnx.search.recordid) {
          recordId = encodeURIComponent(vm.parentCtrl.item.pnx.search.recordid);
        }
      }
      if (recordId === '') {
        // from http://stackoverflow.com/questions/11582512/how-to-get-url-parameters-with-javascript/11582513#11582513
        var fieldname = 'docid';
        var temp = encodeURIComponent((new RegExp('[?|&]' + fieldname + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
        if (temp !== null) {
          recordId = temp;
        }
      }

      var recordTitle = '';
      if (recordId !== '' && !!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.search && !!vm.parentCtrl.item.pnx.search.title && !!vm.parentCtrl.item.pnx.search.title[0]) {
        recordTitle = encodeURIComponent(vm.parentCtrl.item.pnx.search.title[0]);
      }
      if (recordTitle === '' && recordId !== '' && !!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.display && !!vm.parentCtrl.item.pnx.display.title && !!vm.parentCtrl.item.pnx.display.title[0]) {
        recordTitle = encodeURIComponent(vm.parentCtrl.item.pnx.display.title[0]);
      }
      if (recordTitle !== '') {
        var maxNumberCharCRMCanAccept = 239;
        recordTitle = recordTitle.trim().substring(0, maxNumberCharCRMCanAccept);
      }

      var isIE11 = navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > -1;

      // if we are not IE11 and can get a docid and a title - add a button
      if (!isIE11 && recordId !== '' && recordTitle !== '') {
        var crmDomain = 'https://uqcurrent--tst1.custhelp.com'; // we can probably return the live url for all when this is in prod
        if (window.location.hostname === 'search.library.uq.edu.au') {
          crmDomain = 'https://support.my.uq.edu.au';
        }

        vm.targeturl = crmDomain + "/app/library/contact/report_problem/true/incidents.subject/" + recordTitle + "/incidents.c$summary/" + recordId;
      }
    },
    template : '
<getit-link-service>' +
        '<button class="help-button md-button md-primoExplore-theme md-ink-ripple" type="button" data-ng-click="buttonPressed($event)" aria-label="Report a Problem" aria-hidden="false">' +
        'Report a Problem' +
        '</button>' +
        '</getit-link-service>
'
  });

  /****************************************************************************************************/

  /*In case of CENTRAL_PACKAGE - comment out the below line to replace the other module definition*/

  /*var app = angular.module('centralCustom', ['angularLoad']);*/

  /****************************************************************************************************/

  // if the record is one of certain types, the 'Available Online' link should open View It, instead of jumping straight to the resource
  // (this is because there are usually multiple resources, and the default one may not be the best)
  app.controller('prmOpenSpecificTypesInFullController', [
    function () {
      var vm = this;
      vm.$onInit = function () {
        var resourceType = (!!vm.parentCtrl.result && !!vm.parentCtrl.result.pnx && !!vm.parentCtrl.result.pnx.display &&
            !!vm.parentCtrl.result.pnx.display.type && vm.parentCtrl.result.pnx.display.type.length > 0 &&
            vm.parentCtrl.result.pnx.display.type[0]) || '';
        if (resourceType === 'journal' || resourceType === 'newspaper') {
          vm.parentCtrl.isDirectLink = function () { return false; };
        }
      };
    }
  ]);
  app.component('prmOpenSpecificTypesInFull', {
    bindings: { parentCtrl: '<' },
    controller: 'prmOpenSpecificTypesInFullController'
  });
  app.component('prmSearchResultAvailabilityLineAfter', {
    bindings: { parentCtrl: '<' },
    template: '<prm-open-specific-types-in-full parent-ctrl="$ctrl.parentCtrl"></prm-open-specific-types-in-full>'
  });

  function insertScript(url) {
    var script = document.querySelector("script[src*='" + url + "']");
    if (!script) {
      var heads = document.getElementsByTagName("head");
      if (heads && heads.length) {
        var head = heads[0];
        if (head) {
          script = document.createElement('script');
          script.setAttribute('src', url);
          script.setAttribute('type', 'text/javascript');
          head.appendChild(script);
        }
      }
    }
  }

  function insertLink(link) {
    var linkTag = document.querySelector("link[href*='" + link.href + "']");
    if (!linkTag) {
      var heads = document.getElementsByTagName("head");
      if (heads && heads.length) {
        var head = heads[0];
        if (head) {
          linkTag = document.createElement('link');
          linkTag.setAttribute('href', link.href);
          linkTag.setAttribute('rel', link.rel);
          head.appendChild(linkTag);
        }
      }
    }
  }

  // this script should only be called on views that have UQ header showing
  var branchName = '/'; // default. Use for prod
  if (window.location.hostname === 'search.library.uq.edu.au') {
    if (/vid=61UQ_DEV/.test(window.location.href)) {
      branchName = '/primo-prod-dev/';
    }
  } else {
    if (/vid=61UQ_DEV/.test(window.location.href)) {
      branchName = '/primo-sand-box-dev/';
    } else if (/vid=61UQ/.test(window.location.href)) {
      branchName = '/primo-sand-box/';
    }
  }

  var links = [
    { rel: 'import', href: '//assets.library.uq.edu.au' + branchName + 'reusable-components/elements.vulcanized.html' },
    { rel: 'stylesheet', href: '//assets.library.uq.edu.au' + branchName + 'reusable-components/primo2/custom-styles.css' }
  ];
  insertLink(links[0]);
  insertLink(links[1]);

  var scripts = [
    '//assets.library.uq.edu.au' + branchName + 'reusable-components/webcomponentsjs/webcomponents-lite.min.js',
    '//assets.library.uq.edu.au' + branchName + 'reusable-components/resources/preloader.js',
    '//assets.library.uq.edu.au' + branchName + 'reusable-components/primo2/load.js',
  ];
  insertScript(scripts[0]);
  insertScript(scripts[1]);
  insertScript(scripts[2]);

  // Temporarily manually supply the style to hide all the Report A Problem button
  // because they get eleventy-three buttons if they dont have the latest style sheet (Chrome caches it horribly well)
  // This can probably be removed on our next load of work on Primo
  var css = 'div > getit-link-service { display: none; }',
      head = document.head || document.getElementsByTagName('head')[0],
      style = document.createElement('style');
  head.appendChild(style);
  style.setAttribute('type', 'text/css');
  style.appendChild(document.createTextNode(css));
})();
<commit_msg>remove temporary inline css [PT #168829407]<commit_after>(function () {
  "use strict";

  var app = angular.module('viewCustom', ['angularLoad']);

  app.run(['$rootScope', '$location', '$window', function ($rootScope, $location, $window) {
    //record GA page view event to new primo tracker GA ID
    $rootScope.$on('$locationChangeSuccess', function (event) {
      //temporarily create a tracker specifically to new Primo
      if ($window.ga) {
        $window.ga(function () {
          $window.ga('create', 'UA-4365437-14', 'search.library.uq.edu.au', 'NewPrimoTracker');
        });
        $window.ga('NewPrimoTracker.send', 'pageview', { location: $location.url() });
      }
    });

  }]);

  app.component('prmTopBarBefore', {
    template: '
<uqlibrary-alerts></uqlibrary-alerts>
' +
      '
<uq-minimal-header show-login-button="false"></uq-minimal-header>
'
  });

  // based on https://knowledge.exlibrisgroup.com/Primo/Community_Knowledge/How_to_create_a_%E2%80%98Report_a_Problem%E2%80%99_button_below_the_ViewIt_iframe
  app.component('prmFullViewServiceContainerAfter', {
    bindings: {parentCtrl: '<'},
    controller: function($scope){
      var vm = this;

      vm.targeturl = '';

      var recordId = '';
      // no one knows what the TN actually means (per SVG), but in practice all the CDI records have it on their record id
      if (!!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.control && !!vm.parentCtrl.item.pnx.control.recordid &&
          vm.parentCtrl.item.pnx.control.recordid[0] && vm.parentCtrl.item.pnx.control.recordid[0].startsWith('TN')) {
        recordId = encodeURIComponent(vm.parentCtrl.item.pnx.control.recordid);
      }
      if (recordId === '') {
        if (!!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.search && !!vm.parentCtrl.item.pnx.search.recordid) {
          recordId = encodeURIComponent(vm.parentCtrl.item.pnx.search.recordid);
        }
      }
      if (recordId === '') {
        // from http://stackoverflow.com/questions/11582512/how-to-get-url-parameters-with-javascript/11582513#11582513
        var fieldname = 'docid';
        var temp = encodeURIComponent((new RegExp('[?|&]' + fieldname + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
        if (temp !== null) {
          recordId = temp;
        }
      }

      var recordTitle = '';
      if (recordId !== '' && !!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.search && !!vm.parentCtrl.item.pnx.search.title && !!vm.parentCtrl.item.pnx.search.title[0]) {
        recordTitle = encodeURIComponent(vm.parentCtrl.item.pnx.search.title[0]);
      }
      if (recordTitle === '' && recordId !== '' && !!vm.parentCtrl.item.pnx && !!vm.parentCtrl.item.pnx.display && !!vm.parentCtrl.item.pnx.display.title && !!vm.parentCtrl.item.pnx.display.title[0]) {
        recordTitle = encodeURIComponent(vm.parentCtrl.item.pnx.display.title[0]);
      }
      if (recordTitle !== '') {
        var maxNumberCharCRMCanAccept = 239;
        recordTitle = recordTitle.trim().substring(0, maxNumberCharCRMCanAccept);
      }

      var isIE11 = navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > -1;

      // if we are not IE11 and can get a docid and a title - add a button
      if (!isIE11 && recordId !== '' && recordTitle !== '') {
        var crmDomain = 'https://uqcurrent--tst1.custhelp.com'; // we can probably return the live url for all when this is in prod
        if (window.location.hostname === 'search.library.uq.edu.au') {
          crmDomain = 'https://support.my.uq.edu.au';
        }

        vm.targeturl = crmDomain + "/app/library/contact/report_problem/true/incidents.subject/" + recordTitle + "/incidents.c$summary/" + recordId;
      }
    },
    template : '
<getit-link-service>' +
        '<button class="help-button md-button md-primoExplore-theme md-ink-ripple" type="button" data-ng-click="buttonPressed($event)" aria-label="Report a Problem" aria-hidden="false">' +
        'Report a Problem' +
        '</button>' +
        '</getit-link-service>
'
  });

  /****************************************************************************************************/

  /*In case of CENTRAL_PACKAGE - comment out the below line to replace the other module definition*/

  /*var app = angular.module('centralCustom', ['angularLoad']);*/

  /****************************************************************************************************/

  // if the record is one of certain types, the 'Available Online' link should open View It, instead of jumping straight to the resource
  // (this is because there are usually multiple resources, and the default one may not be the best)
  app.controller('prmOpenSpecificTypesInFullController', [
    function () {
      var vm = this;
      vm.$onInit = function () {
        var resourceType = (!!vm.parentCtrl.result && !!vm.parentCtrl.result.pnx && !!vm.parentCtrl.result.pnx.display &&
            !!vm.parentCtrl.result.pnx.display.type && vm.parentCtrl.result.pnx.display.type.length > 0 &&
            vm.parentCtrl.result.pnx.display.type[0]) || '';
        if (resourceType === 'journal' || resourceType === 'newspaper') {
          vm.parentCtrl.isDirectLink = function () { return false; };
        }
      };
    }
  ]);
  app.component('prmOpenSpecificTypesInFull', {
    bindings: { parentCtrl: '<' },
    controller: 'prmOpenSpecificTypesInFullController'
  });
  app.component('prmSearchResultAvailabilityLineAfter', {
    bindings: { parentCtrl: '<' },
    template: '<prm-open-specific-types-in-full parent-ctrl="$ctrl.parentCtrl"></prm-open-specific-types-in-full>'
  });

  function insertScript(url) {
    var script = document.querySelector("script[src*='" + url + "']");
    if (!script) {
      var heads = document.getElementsByTagName("head");
      if (heads && heads.length) {
        var head = heads[0];
        if (head) {
          script = document.createElement('script');
          script.setAttribute('src', url);
          script.setAttribute('type', 'text/javascript');
          head.appendChild(script);
        }
      }
    }
  }

  function insertLink(link) {
    var linkTag = document.querySelector("link[href*='" + link.href + "']");
    if (!linkTag) {
      var heads = document.getElementsByTagName("head");
      if (heads && heads.length) {
        var head = heads[0];
        if (head) {
          linkTag = document.createElement('link');
          linkTag.setAttribute('href', link.href);
          linkTag.setAttribute('rel', link.rel);
          head.appendChild(linkTag);
        }
      }
    }
  }

  // this script should only be called on views that have UQ header showing
  var branchName = '/'; // default. Use for prod
  if (window.location.hostname === 'search.library.uq.edu.au') {
    if (/vid=61UQ_DEV/.test(window.location.href)) {
      branchName = '/primo-prod-dev/';
    }
  } else {
    if (/vid=61UQ_DEV/.test(window.location.href)) {
      branchName = '/primo-sand-box-dev/';
    } else if (/vid=61UQ/.test(window.location.href)) {
      branchName = '/primo-sand-box/';
    }
  }

  var links = [
    { rel: 'import', href: '//assets.library.uq.edu.au' + branchName + 'reusable-components/elements.vulcanized.html' },
    { rel: 'stylesheet', href: '//assets.library.uq.edu.au' + branchName + 'reusable-components/primo2/custom-styles.css' }
  ];
  insertLink(links[0]);
  insertLink(links[1]);

  var scripts = [
    '//assets.library.uq.edu.au' + branchName + 'reusable-components/webcomponentsjs/webcomponents-lite.min.js',
    '//assets.library.uq.edu.au' + branchName + 'reusable-components/resources/preloader.js',
    '//assets.library.uq.edu.au' + branchName + 'reusable-components/primo2/load.js',
  ];
  insertScript(scripts[0]);
  insertScript(scripts[1]);
  insertScript(scripts[2]);
})();
<|endoftext|>


<commit_before>/**
 * Sitespeed.io - How speedy is your site? (http://www.sitespeed.io)
 * Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
var Aggregator = require('../../aggregator');

module.exports = new Aggregator('wpt.firstViewBytes',
  'Size First View',
  'The size in bytes for the first view', '', 0,
  function(pageData) {
    if (pageData.webpagetest) {
      var stats = this.stats;
      pageData.webpagetest.response.data.run.forEach(function(run) {
        stats.push(run.firstView.results.bytesIn);
      });
    }
  });<commit_msg>added missing unit (bytes)<commit_after>/**
 * Sitespeed.io - How speedy is your site? (http://www.sitespeed.io)
 * Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
var Aggregator = require('../../aggregator');

module.exports = new Aggregator('wpt.firstViewBytes',
  'Size First View',
  'The size in bytes for the first view', 'bytes', 0,
  function(pageData) {
    if (pageData.webpagetest) {
      var stats = this.stats;
      pageData.webpagetest.response.data.run.forEach(function(run) {
        stats.push(run.firstView.results.bytesIn);
      });
    }
  });<|endoftext|>


<commit_before>/**
 * Helper for implementing retries with backoff. Initial retry
 * delay is 1 second, increasing by 2x (+jitter) for subsequent retries
 *
 * @constructor
 */
var RetryHandler = function() {
  this.interval = 1000; // Start at one second
  this.maxInterval = 60 * 1000; // Don't wait longer than a minute
};

/**
 * Invoke the function after waiting
 *
 * @param {function} fn Function to invoke
 */
RetryHandler.prototype.retry = function(fn) {
  setTimeout(fn, this.interval);
  this.interval = this.nextInterval_();
};

/**
 * Reset the counter (e.g. after successful request.)
 */
RetryHandler.prototype.reset = function() {
  this.interval = 1000;
};

/**
 * Calculate the next wait time.
 * @return {number} Next wait interval, in milliseconds
 *
 * @private
 */
RetryHandler.prototype.nextInterval_ = function() {
  var interval = this.interval * 2 + this.getRandomInt_(0, 1000);
  return Math.min(interval, this.maxInterval);
};

/**
 * Get a random int in the range of min to max. Used to add jitter to wait times.
 *
 * @param {number} min Lower bounds
 * @param {number} max Upper bounds
 * @private
 */
RetryHandler.prototype.getRandomInt_ = function(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
};

/**
 * Helper class for resumable uploads using XHR/CORS. Can upload any Blob-like item, whether
 * files or in-memory constructs.
 *
 * @example
 * var content = new Blob(["Hello world"], {"type": "text/plain"});
 * var uploader = new MediaUploader({
 *   file: content,
 *   token: accessToken,
 *   onComplete: function(data) { ... }
 *   onError: function(data) { ... }
 * });
 * uploader.upload();
 *
 * @constructor
 * @param {object} options Hash of options
 * @param {string} options.token Access token
 * @param {blob} options.file Blob-like item to upload
 * @param {string} [options.fileId] ID of file if replacing
 * @param {object} [options.params] Additional query parameters
 * @param {string} [options.contentType] Content-type, if overriding the type of the blob.
 * @param {object} [options.metadata] File metadata
 * @param {function} [options.onComplete] Callback for when upload is complete
 * @param {function} [options.onError] Callback if upload fails
 */
var MediaUploader = function(options) {
  var noop = function() {};
  this.file = options.file;
  this.contentType = options.contentType || this.file.type || 'application/octet-stream';
  this.metadata = options.metadata || {
    'title': this.file.name,
    'mimeType': this.contentType
  };
  this.token = options.token;
  this.onComplete = options.onComplete || noop;
  this.onProgress = options.onProgress || noop;
  this.onError = options.onError || noop;
  this.offset = options.offset || 0;
  this.chunkSize = options.chunkSize || 0;
  this.retryHandler = new RetryHandler();

  this.url = options.url;
  if (!this.url) {
    var params = options.params || {};
    params.uploadType = 'resumable';
    this.url = this.buildUrl_(options.fileId, params, options.baseUrl);
  }
  this.httpMethod = options.fileId ? 'PUT' : 'POST';
};

/**
 * Initiate the upload.
 */
MediaUploader.prototype.upload = function() {
  var self = this;
  var xhr = new XMLHttpRequest();

  xhr.open(this.httpMethod, this.url, true);
  xhr.setRequestHeader('Authorization', 'Bearer ' + this.token);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.setRequestHeader('X-Upload-Content-Length', this.file.size);
  xhr.setRequestHeader('X-Upload-Content-Type', this.contentType);

  xhr.onload = function(e) {
    if (e.target.status < 400) {
      var location = e.target.getResponseHeader('Location');
      this.url = location;
      this.sendFile_();
    } else {
      this.onUploadError_(e);
    }
  }.bind(this);
  xhr.onerror = this.onUploadError_.bind(this);
  xhr.send(JSON.stringify(this.metadata));
};

/**
 * Send the actual file content.
 *
 * @private
 */
MediaUploader.prototype.sendFile_ = function() {
  var content = this.file;
  var end = this.file.size;

  if (this.offset || this.chunkSize) {
    // Only bother to slice the file if we're either resuming or uploading in chunks
    if (this.chunkSize) {
      end = Math.min(this.offset + this.chunkSize, this.file.size);
    }
    content = content.slice(this.offset, end);
  }

  var xhr = new XMLHttpRequest();
  xhr.open('PUT', this.url, true);
  xhr.setRequestHeader('Content-Type', this.contentType);
  xhr.setRequestHeader('Content-Range', "bytes " + this.offset + "-" + (end - 1) + "/" + this.file.size);
  xhr.setRequestHeader('X-Upload-Content-Type', this.file.type);
  if (xhr.upload) {
    xhr.upload.addEventListener('progress', this.onProgress);
  }
  xhr.onload = this.onContentUploadSuccess_.bind(this);
  xhr.onerror = this.onContentUploadError_.bind(this);
  xhr.send(content);
};

/**
 * Query for the state of the file for resumption.
 *
 * @private
 */
MediaUploader.prototype.resume_ = function() {
  var xhr = new XMLHttpRequest();
  xhr.open('PUT', this.url, true);
  xhr.setRequestHeader('Content-Range', "bytes */" + this.file.size);
  xhr.setRequestHeader('X-Upload-Content-Type', this.file.type);
  if (xhr.upload) {
    xhr.upload.addEventListener('progress', this.onProgress);
  }
  xhr.onload = this.onContentUploadSuccess_.bind(this);
  xhr.onerror = this.onContentUploadError_.bind(this);
  xhr.send();
};

/**
 * Extract the last saved range if available in the request.
 *
 * @param {XMLHttpRequest} xhr Request object
 */
MediaUploader.prototype.extractRange_ = function(xhr) {
  var range = xhr.getResponseHeader('Range');
  if (range) {
    this.offset = parseInt(range.match(/\d+/g).pop(), 10) + 1;
  }
};

/**
 * Handle successful responses for uploads. Depending on the context,
 * may continue with uploading the next chunk of the file or, if complete,
 * invokes the caller's callback.
 *
 * @private
 * @param {object} e XHR event
 */
MediaUploader.prototype.onContentUploadSuccess_ = function(e) {
  if (e.target.status == 200 || e.target.status == 201) {
    this.onComplete(e.target.response);
  } else if (e.target.status == 308) {
    this.extractRange_(e.target);
    this.retryHandler.reset();
    this.sendFile_();
  }
};

/**
 * Handles errors for uploads. Either retries or aborts depending
 * on the error.
 *
 * @private
 * @param {object} e XHR event
 */
MediaUploader.prototype.onContentUploadError_ = function(e) {
  if (e.target.status && e.target.status < 500) {
    this.onError(e.target.response);
  } else {
    this.retryHandler.retry(this.resume_.bind(this));
  }
};

/**
 * Handles errors for the initial request.
 *
 * @private
 * @param {object} e XHR event
 */
MediaUploader.prototype.onUploadError_ = function(e) {
  this.onError(e.target.response); // TODO - Retries for initial upload
};

/**
 * Construct a query string from a hash/object
 *
 * @private
 * @param {object} [params] Key/value pairs for query string
 * @return {string} query string
 */
MediaUploader.prototype.buildQuery_ = function(params) {
  params = params || {};
  return Object.keys(params).map(function(key) {
    return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
  }).join('&');
};

/**
 * Build the drive upload URL
 *
 * @private
 * @param {string} [id] File ID if replacing
 * @param {object} [params] Query parameters
 * @return {string} URL
 */
MediaUploader.prototype.buildUrl_ = function(id, params, baseUrl) {
  var url = baseUrl || 'https://www.googleapis.com/upload/drive/v2/files/';
  if (id) {
    url += id;
  }
  var query = this.buildQuery_(params);
  if (query) {
    url += '?' + query;
  }
  return url;
};

<commit_msg>Added corresponding JSDoc for the onProgress callback.<commit_after>/**
 * Helper for implementing retries with backoff. Initial retry
 * delay is 1 second, increasing by 2x (+jitter) for subsequent retries
 *
 * @constructor
 */
var RetryHandler = function() {
  this.interval = 1000; // Start at one second
  this.maxInterval = 60 * 1000; // Don't wait longer than a minute
};

/**
 * Invoke the function after waiting
 *
 * @param {function} fn Function to invoke
 */
RetryHandler.prototype.retry = function(fn) {
  setTimeout(fn, this.interval);
  this.interval = this.nextInterval_();
};

/**
 * Reset the counter (e.g. after successful request.)
 */
RetryHandler.prototype.reset = function() {
  this.interval = 1000;
};

/**
 * Calculate the next wait time.
 * @return {number} Next wait interval, in milliseconds
 *
 * @private
 */
RetryHandler.prototype.nextInterval_ = function() {
  var interval = this.interval * 2 + this.getRandomInt_(0, 1000);
  return Math.min(interval, this.maxInterval);
};

/**
 * Get a random int in the range of min to max. Used to add jitter to wait times.
 *
 * @param {number} min Lower bounds
 * @param {number} max Upper bounds
 * @private
 */
RetryHandler.prototype.getRandomInt_ = function(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
};

/**
 * Helper class for resumable uploads using XHR/CORS. Can upload any Blob-like item, whether
 * files or in-memory constructs.
 *
 * @example
 * var content = new Blob(["Hello world"], {"type": "text/plain"});
 * var uploader = new MediaUploader({
 *   file: content,
 *   token: accessToken,
 *   onComplete: function(data) { ... }
 *   onError: function(data) { ... }
 * });
 * uploader.upload();
 *
 * @constructor
 * @param {object} options Hash of options
 * @param {string} options.token Access token
 * @param {blob} options.file Blob-like item to upload
 * @param {string} [options.fileId] ID of file if replacing
 * @param {object} [options.params] Additional query parameters
 * @param {string} [options.contentType] Content-type, if overriding the type of the blob.
 * @param {object} [options.metadata] File metadata
 * @param {function} [options.onComplete] Callback for when upload is complete
 * @param {function} [options.onProgress] Callback for status for the in-progress upload
 * @param {function} [options.onError] Callback if upload fails
 */
var MediaUploader = function(options) {
  var noop = function() {};
  this.file = options.file;
  this.contentType = options.contentType || this.file.type || 'application/octet-stream';
  this.metadata = options.metadata || {
    'title': this.file.name,
    'mimeType': this.contentType
  };
  this.token = options.token;
  this.onComplete = options.onComplete || noop;
  this.onProgress = options.onProgress || noop;
  this.onError = options.onError || noop;
  this.offset = options.offset || 0;
  this.chunkSize = options.chunkSize || 0;
  this.retryHandler = new RetryHandler();

  this.url = options.url;
  if (!this.url) {
    var params = options.params || {};
    params.uploadType = 'resumable';
    this.url = this.buildUrl_(options.fileId, params, options.baseUrl);
  }
  this.httpMethod = options.fileId ? 'PUT' : 'POST';
};

/**
 * Initiate the upload.
 */
MediaUploader.prototype.upload = function() {
  var self = this;
  var xhr = new XMLHttpRequest();

  xhr.open(this.httpMethod, this.url, true);
  xhr.setRequestHeader('Authorization', 'Bearer ' + this.token);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.setRequestHeader('X-Upload-Content-Length', this.file.size);
  xhr.setRequestHeader('X-Upload-Content-Type', this.contentType);

  xhr.onload = function(e) {
    if (e.target.status < 400) {
      var location = e.target.getResponseHeader('Location');
      this.url = location;
      this.sendFile_();
    } else {
      this.onUploadError_(e);
    }
  }.bind(this);
  xhr.onerror = this.onUploadError_.bind(this);
  xhr.send(JSON.stringify(this.metadata));
};

/**
 * Send the actual file content.
 *
 * @private
 */
MediaUploader.prototype.sendFile_ = function() {
  var content = this.file;
  var end = this.file.size;

  if (this.offset || this.chunkSize) {
    // Only bother to slice the file if we're either resuming or uploading in chunks
    if (this.chunkSize) {
      end = Math.min(this.offset + this.chunkSize, this.file.size);
    }
    content = content.slice(this.offset, end);
  }

  var xhr = new XMLHttpRequest();
  xhr.open('PUT', this.url, true);
  xhr.setRequestHeader('Content-Type', this.contentType);
  xhr.setRequestHeader('Content-Range', "bytes " + this.offset + "-" + (end - 1) + "/" + this.file.size);
  xhr.setRequestHeader('X-Upload-Content-Type', this.file.type);
  if (xhr.upload) {
    xhr.upload.addEventListener('progress', this.onProgress);
  }
  xhr.onload = this.onContentUploadSuccess_.bind(this);
  xhr.onerror = this.onContentUploadError_.bind(this);
  xhr.send(content);
};

/**
 * Query for the state of the file for resumption.
 *
 * @private
 */
MediaUploader.prototype.resume_ = function() {
  var xhr = new XMLHttpRequest();
  xhr.open('PUT', this.url, true);
  xhr.setRequestHeader('Content-Range', "bytes */" + this.file.size);
  xhr.setRequestHeader('X-Upload-Content-Type', this.file.type);
  if (xhr.upload) {
    xhr.upload.addEventListener('progress', this.onProgress);
  }
  xhr.onload = this.onContentUploadSuccess_.bind(this);
  xhr.onerror = this.onContentUploadError_.bind(this);
  xhr.send();
};

/**
 * Extract the last saved range if available in the request.
 *
 * @param {XMLHttpRequest} xhr Request object
 */
MediaUploader.prototype.extractRange_ = function(xhr) {
  var range = xhr.getResponseHeader('Range');
  if (range) {
    this.offset = parseInt(range.match(/\d+/g).pop(), 10) + 1;
  }
};

/**
 * Handle successful responses for uploads. Depending on the context,
 * may continue with uploading the next chunk of the file or, if complete,
 * invokes the caller's callback.
 *
 * @private
 * @param {object} e XHR event
 */
MediaUploader.prototype.onContentUploadSuccess_ = function(e) {
  if (e.target.status == 200 || e.target.status == 201) {
    this.onComplete(e.target.response);
  } else if (e.target.status == 308) {
    this.extractRange_(e.target);
    this.retryHandler.reset();
    this.sendFile_();
  }
};

/**
 * Handles errors for uploads. Either retries or aborts depending
 * on the error.
 *
 * @private
 * @param {object} e XHR event
 */
MediaUploader.prototype.onContentUploadError_ = function(e) {
  if (e.target.status && e.target.status < 500) {
    this.onError(e.target.response);
  } else {
    this.retryHandler.retry(this.resume_.bind(this));
  }
};

/**
 * Handles errors for the initial request.
 *
 * @private
 * @param {object} e XHR event
 */
MediaUploader.prototype.onUploadError_ = function(e) {
  this.onError(e.target.response); // TODO - Retries for initial upload
};

/**
 * Construct a query string from a hash/object
 *
 * @private
 * @param {object} [params] Key/value pairs for query string
 * @return {string} query string
 */
MediaUploader.prototype.buildQuery_ = function(params) {
  params = params || {};
  return Object.keys(params).map(function(key) {
    return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
  }).join('&');
};

/**
 * Build the drive upload URL
 *
 * @private
 * @param {string} [id] File ID if replacing
 * @param {object} [params] Query parameters
 * @return {string} URL
 */
MediaUploader.prototype.buildUrl_ = function(id, params, baseUrl) {
  var url = baseUrl || 'https://www.googleapis.com/upload/drive/v2/files/';
  if (id) {
    url += id;
  }
  var query = this.buildQuery_(params);
  if (query) {
    url += '?' + query;
  }
  return url;
};

<|endoftext|>


<commit_before>/**
 *  entry point for table
 */

$(function() {

  var Table = cdb.core.View.extend({

    el: document.body,

    events: {
      'keypress': 'keyPress',
      'keyup': 'keyUp'
    },

    initialize: function() {
      this.user = new cdb.admin.User(this.options.user_data);

      this._initModels();
      this._initViews();

      // init data
      // table change will raise the map and columns fetch
      this.table.fetch();
      this.keyBind();
    },
    /**
    * Bind the keystrokes associated with menu actions
    * alt + <- : show right menu
    * alt + -> : hide right menu
    * alt + c : toggle carto
    * alt + s : toggle sql
    * @method keyBind
    */
    keyBind: function() {
      var self = this;
      $('body').bind('keydown', function(e) {
        if(e.altKey) {
          //37 39
          if(e.keyCode == 37) { // left arrow
            e.preventDefault();
            e.stopPropagation();
            self.menu.show()
            return false;
          }
          if(e.keyCode == 39) { // right arrow
            e.preventDefault();
            e.stopPropagation();
            self.menu.hide()
            return false;
          }
          if(e.keyCode == 67) { // c key
            e.preventDefault();
            e.stopPropagation();
            self.menu.getButtonByClass('carto_mod').click(e);
            return false;
          }
          if(e.keyCode == 83) { // s key
            e.preventDefault();
            e.stopPropagation();
            self.menu.getButtonByClass('sql_mod').click(e);
            return false;
          }
        }
      });
    },
    appyQuery: function(sql) {
      var self = this;
      self.sqlView.setSQL(sql);
      self.table.useSQLView(self.sqlView);
      // if there is some error the query is rollbacked
      self.sqlView.fetch();
    },

    _initModels: function() {
      var self = this;
      this.table = new cdb.admin.CartoDBTableMetadata({
        id: this.options.table_id
      });
      this.columns = this.table.data();
      this.map = new cdb.admin.Map();
      this.infowindow = new cdb.geo.ui.InfowindowModel({
        template_name: 'table/views/infowindow_light'
      });
      this.sqlView = new cdb.admin.SQLViewData();
      this.geocoder = new cdb.admin.Geocoding('', this.table);

      //TODO: load this from an initial data file or d
      var layers = [
        {
          url: 'http://tile.stamen.com/toner/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-light/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        //'http://tile.stamen.com/terrain/{z}/{x}/{y}.png',
        //'http://tile.stamen.com/watercolor/{z}/{x}/{y}.png',
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-streets/{z}/{x}/{y}.png',
          maxZoom: 17
        }

      ];

      this.baseLayers = this.user.layers;
      _(layers).map(function(m) {
        self.baseLayers.add(new cdb.admin.TileLayer({
          urlTemplate: m.url,
          read_only: true,
          maxZoom: m.maxZoom
        }));
      });

      // fetch or create map id
      this.map.relatedTo(this.table);

      this.map.bind('change:dataLayer', _.once(function() {

        // cache the value to access it in all the view
        self.dataLayer = self.map.get('dataLayer');

        // when the layer query changes the table should change
        self.dataLayer.bind('change:query', function() {
          var sql = this.get('query');
          if(sql) {
            self.appyQuery(sql);
          } else {
            self.table.useSQLView(null); }
        });

        self.sqlView.bind('error', function() {
          self.dataLayer.save({query: null}, {silent: true});
        });

        // trigger the event to ping all views
        self.dataLayer.trigger('change:query');

        var infowindowData = self.dataLayer.get('infowindow');
        if(infowindowData) {
          self.infowindow.set(infowindowData);
        } else {
          // assign a position from start
          var pos = 0;
          _(self.table.get('schema')).each(function(v) {
            self.infowindow.addField(v[0], pos);
            ++pos;
          });
        }

        // check all the fields in the infowindows are in table schema
        // remove the missing ones
        self.table.bind('change:schema', function() {
          var columns = self.table.columnNames();
          _(self.infowindow.get('fields')).each(function(c) {
            if(!_.contains(columns, c.name)) {
              self.infowindow.removeField(c.name);
            }
          });

        });

        self.infowindow.bind('change:fields change:template_name', _.debounce(function() {
          // call with silent so the layer is no realoded
          // if some view needs to be changed when infowindow is changed it should be
          // subscribed to infowindow model not to dataLayer
          // (which is only a data container for infowindow)
          self.dataLayer.save({ infowindow: self.infowindow.toJSON() }, { silent: true });
        }, 200));

      }));

    },

    _initViews: function() {
      var self = this;

      this.header = new cdb.admin.Header({
        el: this.$('header'),
        model: this.table,
        user: this.user,
        geocoder: this.geocoder
      });
      this.addView(this.header);

      this.tabs = new cdb.admin.Tabs({
        el: this.$('nav')
      });
      this.addView(this.tabs);

      this.workView = new cdb.ui.common.TabPane({
        el: this.$('.panes')
      });

      this.addView(this.workView);

      this.tableTab = new cdb.admin.TableTab({
        model: this.table,
        sqlView: this.sqlView
      });

      this.mapTab = new cdb.admin.MapTab({
        model: this.map,
        baseLayers: this.baseLayers,
        table: this.table,
        infowindow: this.infowindow
      });

      this.globalError = new cdb.admin.GlobalError({
        el: $('.globalerror')
      });

      this.table.bind('notice', this.globalError.showError, this.globalError);

      this.addView(this.globalError);

      // used to show progress on stuff being done
      var bkg_importer = this.bkg_importer = new cdb.ui.common.BackgroundImporter({
        template_base: 'table/views/geocoder_progress',
        import_: this.geocoder
      });
      this.$el.append(this.bkg_importer.render().el);

      this.geocoder.bind('start', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.geocoder.bind('progress', function() {
        self.bkg_importer.render();
        if(self.geocoder.total_connections%10 == 0) {
          //self.dataLayer.trigger('change');
        }
      });

      this.geocoder.bind('finish', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.menu = new cdb.admin.RightMenu({});
      this.$el.append(this.menu.render().el);
      this.menu.hide();
      this.addView(this.menu);

      this.map.bind('change:dataLayer', _.once(function() {

        self.header.setDataLayer(self.dataLayer);

        self.table.bind('change:name', function() {
          self.dataLayer.set({ table_name: self.table.get('name') });
          self.dataLayer.save();
        });

        self.dataLayer.set({
          table_name: self.table.get('name'),
          user_name: self.user.get("username"),
          sql: sql,
          extra_params: {
            map_key: self.user.get('api_key')
          },
          sql_api_domain: cdb.config.get('sql_api_domain'),
          sql_api_endpoint: cdb.config.get('sql_api_endpoint'),
          sql_api_port: cdb.config.get('sql_api_port'),
          tiler_domain: cdb.config.get('tiler_domain'),
          tiler_port: cdb.config.get('tiler_port')
        });

        self.dataLayer.save();

        // set api key when we have api key and the data layer loaded
        var sql = self.table.isInSQLView() ?
                      self.table.data().getSQL() :
                      undefined;

        // lateral menu modules
        var sql = new cdb.admin.mod.SQL({
          model: self.dataLayer,
          sqlView: self.sqlView,
          table: self.table
        });

        sql.bind('writeSQL', self.appyQuery, self);

        var carto = new cdb.admin.mod.Carto({
          model: self.dataLayer,
          table: self.table
        });

        var infowindow = new cdb.admin.mod.InfoWindow({
          table: self.table,
          model: self.infowindow
        });
        self.menu.addModule(sql.render(), ['table', 'map']);
        self.menu.addModule(carto.render(), 'map');
        self.menu.addModule(infowindow.render(), 'map');

        var addRow = self.menu.addToolButton('add_row', 'table');
        var addColumn = self.menu.addToolButton('add_column', 'table');
        addColumn.bind('click', function() {
            new cdb.admin.NewColumnDialog({
              table: self.table
            }).appendToBody().open();
        });
        addRow.bind('click', function() {
          self.table.data().addRow({ at: 0});
          self.trigger('createRow');
        });

      }));

      this.workView.addTab('table', this.tableTab.render());
      this.workView.addTab('map', this.mapTab.render());
      this.workView.bind('tabEnabled:map', this.mapTab.enableMap, this.mapTab);

      this.workView.bind('tabEnabled', this.tabs.activate);
      this.workView.active('table');

      // global click
      enableClickOut(this.$el);

      this.mapTab.bind('missingClick', function() {
        self.menu.hide();
      });
      this.tableTab.tableView.bind('cellClick', function() {
        self.menu.hide();
      });

      // On resize window...
      $(window).bind("resize", this._onResize);

    },

    // Close all dialogs in window resize
    _onResize: function(e) {
      cdb.god.trigger("closeDialogs");
    },

    keyUp: function(e) {
    },

    keyPress: function(e) {
      /*if(e.which == 19) {
        this.menu.show();
        this.menu.active('sql_mod');
        e.preventDefault();
        return false;
      }*/
    }

  });

    cdb._test = cdb._test || {};
    cdb._test.Table = Table;

    var TableRouter = Backbone.Router.extend({

        initialize: function(table) {
          var self = this;
          this.table = table;
          /*
          this.table.table.bind('change:dataSource', function() {
            if(this.isInSQLView()) {
              var sql = this.data().getSQL();
              if(!this.alterTableData(sql)) {
                self.navigate('table/' + encodeURIComponent(sql));
              }
            } else {
              self.navigate('table');
            }
          });
          */
        },

        routes: {
            '': 'index',
            'table': 'index',
            'table/:sql': 'table_sql',
            'map': 'map'
        },

        index: function() {
          this.table.workView.active('table');
          this.table.menu.showTools('table');
        },

        table_sql: function(sql) {
          this.index();
          if(!this.table.table.alterTableData(sql)) {
            this.table.sqlView.setSQL(decodeURIComponent(sql));
            this.table.table.useSQLView(this.table.sqlView);
          }
        },

        map: function() {
          this.table.workView.active('map');
          this.table.menu.showTools('map');
        }

    });

    cdb.init(function() {
      cdb.config.set(config);
      cdb.templates.namespace = 'cartodb/';
      var table = new Table({
        table_id: table_id,
        user_data: user_data
      });
      var router = new TableRouter(table);
      // expose to debug
      window.table = table;
      Backbone.history.start();
    });

});
<commit_msg>fix #461<commit_after>/**
 *  entry point for table
 */

$(function() {

  var Table = cdb.core.View.extend({

    el: document.body,

    events: {
      'keypress': 'keyPress',
      'keyup': 'keyUp'
    },

    initialize: function() {
      this.user = new cdb.admin.User(this.options.user_data);

      this._initModels();
      this._initViews();

      // init data
      // table change will raise the map and columns fetch
      this.table.fetch();
      this.keyBind();
    },
    /**
    * Bind the keystrokes associated with menu actions
    * alt + <- : show right menu
    * alt + -> : hide right menu
    * alt + c : toggle carto
    * alt + s : toggle sql
    * @method keyBind
    * TODO: extract to a better place to allow use in all the views
    */
    keyBind: function() {
      var self = this;
      $('body').bind('keydown', function(e) {
        if(e.altKey) {
          //37 39
          if(e.keyCode == 37) { // left arrow
            e.preventDefault();
            e.stopPropagation();
            self.menu.show()
            return false;
          }
          if(e.keyCode == 39) { // right arrow
            e.preventDefault();
            e.stopPropagation();
            self.menu.hide()
            return false;
          }
          if(e.keyCode == 67) { // c key
            e.preventDefault();
            e.stopPropagation();
            self.menu.getButtonByClass('carto_mod').click(e);
            return false;
          }
          if(e.keyCode == 83) { // s key
            e.preventDefault();
            e.stopPropagation();
            self.menu.getButtonByClass('sql_mod').click(e);
            return false;
          }
        }
      });
    },
    appyQuery: function(sql) {
      var self = this;
      self.sqlView.setSQL(sql);
      self.table.useSQLView(self.sqlView);
      // if there is some error the query is rollbacked
      self.sqlView.fetch();
    },

    _initModels: function() {
      var self = this;
      this.table = new cdb.admin.CartoDBTableMetadata({
        id: this.options.table_id
      });
      this.columns = this.table.data();
      this.map = new cdb.admin.Map();
      this.infowindow = new cdb.geo.ui.InfowindowModel({
        template_name: 'table/views/infowindow_light'
      });
      this.sqlView = new cdb.admin.SQLViewData();
      this.geocoder = new cdb.admin.Geocoding('', this.table);

      //TODO: load this from an initial data file or d
      var layers = [
        {
          url: 'http://tile.stamen.com/toner/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-light/{z}/{x}/{y}.png',
          maxZoom: 17
        },
        //'http://tile.stamen.com/terrain/{z}/{x}/{y}.png',
        //'http://tile.stamen.com/watercolor/{z}/{x}/{y}.png',
        {
          url: 'http://a.tiles.mapbox.com/v3/mapbox.mapbox-streets/{z}/{x}/{y}.png',
          maxZoom: 17
        }

      ];

      this.baseLayers = this.user.layers;
      _(layers).map(function(m) {
        self.baseLayers.add(new cdb.admin.TileLayer({
          urlTemplate: m.url,
          read_only: true,
          maxZoom: m.maxZoom
        }));
      });

      // fetch or create map id
      this.map.relatedTo(this.table);

      this.map.bind('change:dataLayer', _.once(function() {

        // cache the value to access it in all the view
        self.dataLayer = self.map.get('dataLayer');

        // when the layer query changes the table should change
        self.dataLayer.bind('change:query', function() {
          var sql = this.get('query');
          if(sql) {
            self.appyQuery(sql);
          } else {
            self.table.useSQLView(null); }
        });

        self.sqlView.bind('error', function() {
          self.dataLayer.save({query: null}, {silent: true});
        });

        // trigger the event to ping all views
        self.dataLayer.trigger('change:query');

        var infowindowData = self.dataLayer.get('infowindow');
        if(infowindowData) {
          self.infowindow.set(infowindowData);
        } else {
          // assign a position from start
          var pos = 0;
          _(self.table.get('schema')).each(function(v) {
            self.infowindow.addField(v[0], pos);
            ++pos;
          });
        }

        // check all the fields in the infowindows are in table schema
        // remove the missing ones
        self.table.bind('change:schema', function() {
          var columns = self.table.columnNames();
          _(self.infowindow.get('fields')).each(function(c) {
            if(!_.contains(columns, c.name)) {
              self.infowindow.removeField(c.name);
            }
          });

        });

        self.infowindow.bind('change:fields change:template_name', _.debounce(function() {
          // call with silent so the layer is no realoded
          // if some view needs to be changed when infowindow is changed it should be
          // subscribed to infowindow model not to dataLayer
          // (which is only a data container for infowindow)
          self.dataLayer.save({ infowindow: self.infowindow.toJSON() }, { silent: true });
        }, 200));

      }));

    },

    _initViews: function() {
      var self = this;

      this.header = new cdb.admin.Header({
        el: this.$('header'),
        model: this.table,
        user: this.user,
        geocoder: this.geocoder
      });
      this.addView(this.header);

      this.tabs = new cdb.admin.Tabs({
        el: this.$('nav')
      });
      this.addView(this.tabs);

      this.workView = new cdb.ui.common.TabPane({
        el: this.$('.panes')
      });

      this.addView(this.workView);

      this.tableTab = new cdb.admin.TableTab({
        model: this.table,
        sqlView: this.sqlView
      });

      this.mapTab = new cdb.admin.MapTab({
        model: this.map,
        baseLayers: this.baseLayers,
        table: this.table,
        infowindow: this.infowindow
      });

      this.globalError = new cdb.admin.GlobalError({
        el: $('.globalerror')
      });

      this.table.bind('notice', this.globalError.showError, this.globalError);

      this.addView(this.globalError);

      // used to show progress on stuff being done
      var bkg_importer = this.bkg_importer = new cdb.ui.common.BackgroundImporter({
        template_base: 'table/views/geocoder_progress',
        import_: this.geocoder
      });
      this.$el.append(this.bkg_importer.render().el);

      this.geocoder.bind('start', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.geocoder.bind('progress', function() {
        self.bkg_importer.render();
        if(self.geocoder.total_connections%10 == 0) {
          //self.dataLayer.trigger('change');
        }
      });

      this.geocoder.bind('finish', function() {
        self.bkg_importer.changeState(self.geocoder);
      });

      this.menu = new cdb.admin.RightMenu({});
      this.$el.append(this.menu.render().el);
      this.menu.hide();
      this.addView(this.menu);

      this.map.bind('change:dataLayer', _.once(function() {

        self.header.setDataLayer(self.dataLayer);

        self.table.bind('change:name', function() {
          self.dataLayer.set({ table_name: self.table.get('name') });
          self.dataLayer.save();
        });

        self.dataLayer.set({
          table_name: self.table.get('name'),
          user_name: self.user.get("username"),
          sql: sql,
          extra_params: {
            map_key: self.user.get('api_key')
          },
          sql_api_domain: cdb.config.get('sql_api_domain'),
          sql_api_endpoint: cdb.config.get('sql_api_endpoint'),
          sql_api_port: cdb.config.get('sql_api_port'),
          tiler_domain: cdb.config.get('tiler_domain'),
          tiler_port: cdb.config.get('tiler_port')
        });

        // set api key when we have api key and the data layer loaded
        var sql = self.table.isInSQLView() ?
                      self.table.data().getSQL() :
                      undefined;

        // lateral menu modules
        var sql = new cdb.admin.mod.SQL({
          model: self.dataLayer,
          sqlView: self.sqlView,
          table: self.table
        });

        sql.bind('writeSQL', self.appyQuery, self);

        var carto = new cdb.admin.mod.Carto({
          model: self.dataLayer,
          table: self.table
        });

        var infowindow = new cdb.admin.mod.InfoWindow({
          table: self.table,
          model: self.infowindow
        });
        self.menu.addModule(sql.render(), ['table', 'map']);
        self.menu.addModule(carto.render(), 'map');
        self.menu.addModule(infowindow.render(), 'map');

        var addRow = self.menu.addToolButton('add_row', 'table');
        var addColumn = self.menu.addToolButton('add_column', 'table');
        addColumn.bind('click', function() {
            new cdb.admin.NewColumnDialog({
              table: self.table
            }).appendToBody().open();
        });
        addRow.bind('click', function() {
          self.table.data().addRow({ at: 0});
          self.trigger('createRow');
        });

      }));

      this.workView.addTab('table', this.tableTab.render());
      this.workView.addTab('map', this.mapTab.render());
      this.workView.bind('tabEnabled:map', this.mapTab.enableMap, this.mapTab);

      this.workView.bind('tabEnabled', this.tabs.activate);
      this.workView.active('table');

      // global click
      enableClickOut(this.$el);

      this.mapTab.bind('missingClick', function() {
        self.menu.hide();
      });
      this.tableTab.tableView.bind('cellClick', function() {
        self.menu.hide();
      });

      // On resize window...
      $(window).bind("resize", this._onResize);

    },

    // Close all dialogs in window resize
    _onResize: function(e) {
      cdb.god.trigger("closeDialogs");
    },

    keyUp: function(e) {
    },

    keyPress: function(e) {
      /*if(e.which == 19) {
        this.menu.show();
        this.menu.active('sql_mod');
        e.preventDefault();
        return false;
      }*/
    }

  });

    cdb._test = cdb._test || {};
    cdb._test.Table = Table;

    var TableRouter = Backbone.Router.extend({

        initialize: function(table) {
          var self = this;
          this.table = table;
          /*
          this.table.table.bind('change:dataSource', function() {
            if(this.isInSQLView()) {
              var sql = this.data().getSQL();
              if(!this.alterTableData(sql)) {
                self.navigate('table/' + encodeURIComponent(sql));
              }
            } else {
              self.navigate('table');
            }
          });
          */
        },

        routes: {
            '': 'index',
            'table': 'index',
            'table/:sql': 'table_sql',
            'map': 'map'
        },

        index: function() {
          this.table.workView.active('table');
          this.table.menu.showTools('table');
        },

        table_sql: function(sql) {
          this.index();
          if(!this.table.table.alterTableData(sql)) {
            this.table.sqlView.setSQL(decodeURIComponent(sql));
            this.table.table.useSQLView(this.table.sqlView);
          }
        },

        map: function() {
          this.table.workView.active('map');
          this.table.menu.showTools('map');
        }

    });

    cdb.init(function() {
      cdb.config.set(config);
      cdb.templates.namespace = 'cartodb/';
      var table = new Table({
        table_id: table_id,
        user_data: user_data
      });
      var router = new TableRouter(table);
      // expose to debug
      window.table = table;
      Backbone.history.start();
    });

});
<|endoftext|>