text: var challenges;
  var templates = {};
  
  Handlebars.registerHelper('splitSlash', function(filename) {
      var filename = filename.split("/");
      filename = filename[filename.length - 1];
      return filename;
  });
  
  function loadchal(id) {
      var obj = $.grep(challenges['game'], function (e) {
          return e.id == id;
      })[0];
  
      updateChalWindow(obj);
  }
  
  function loadchalbyname(chalname) {
      var obj = $.grep(challenges['game'], function (e) {
        return e.name == chalname;
      })[0];
  
      updateChalWindow(obj);
  }
  
  function updateChalWindow(obj) {
      $.get(script_root + obj.template, function(template_data){
          $('#chal-window').empty();
          templates[obj.type] = template_data;
          var template_data = templates[obj.type];
          template_data['script_root'] = script_root;
          var template = Handlebars.compile(template_data);
          var solves = obj.solves == 1 ? " Solve" : " Solves";
          var solves = obj.solves + solves;
  
          var nonce = $('#nonce').val();
          var wrapper  = {
              id: obj.id,
              name: obj.name,
              value: obj.value,
              tags: obj.tags,
              desc: obj.description,
              solves: solves,
              files: obj.files,
              hints: obj.hints
          };
  
          $('#chal-window').append(template(wrapper));
          $.getScript(script_root + obj.script,
              function() {
                  // Handle Solves tab
                  $('.chal-solves').click(function (e) {
                      getsolves($('#chal-id').val())
                  });
                  $('.nav-tabs a').click(function (e) {
                      e.preventDefault();
                      $(this).tab('show')
                  });
  
                  // Handle modal toggling
                  $('#chal-window').on('hide.bs.modal', function (event) {
                      $("#answer-input").removeClass("wrong");
                      $("#answer-input").removeClass("correct");
                      $("#incorrect-key").slideUp();
                      $("#correct-key").slideUp();
                      $("#already-solved").slideUp();
                      $("#too-fast").slideUp();
                  });
  
                  // $('pre code').each(function(i, block) {
                  //     hljs.highlightBlock(block);
                  // });
  
                  window.location.replace(window.location.href.split('#')[0] + '#' + obj.name);
                  $('#chal-window').modal();
          });
      });
  }
  
  $("#answer-input").keyup(function(event){
      if(event.keyCode == 13){
          $("#submit-key").click();
      }
  });
  
  
  function submitkey(chal, key, nonce) {
      $('#submit-key').addClass("disabled-button");
      $('#submit-key').prop('disabled', true);
      $.post(script_root + "/chal/" + chal, {
          key: key,
          nonce: nonce
      }, function (data) {
          var result = $.parseJSON(JSON.stringify(data));
  
          var result_message = $('#result-message');
          var result_notification = $('#result-notification');
          var answer_input = $("#answer-input");
          result_notification.removeClass();
          result_message.text(result.message);
  
          if (result.status == -1){
            window.location = script_root + "/login?next=" + script_root + window.location.pathname + window.location.hash
            return
          }
          else if (result.status == 0){ // Incorrect key
              result_notification.addClass('alert alert-danger alert-dismissable text-center');
              result_notification.slideDown();
  
              answer_input.removeClass("correct");
              answer_input.addClass("wrong");
              setTimeout(function () {
                  answer_input.removeClass("wrong");
              }, 3000);
          }
          else if (result.status == 1){ // Challenge Solved
              result_notification.addClass('alert alert-success alert-dismissable text-center');
              result_notification.slideDown();
  
              $('.chal-solves').text((parseInt($('.chal-solves').text().split(" ")[0]) + 1 +  " Solves") );
  
              answer_input.val("");
              answer_input.removeClass("wrong");
              answer_input.addClass("correct");
          }
          else if (result.status == 2){ // Challenge already solved
              result_notification.addClass('alert alert-info alert-dismissable text-center');
              result_notification.slideDown();
  
              answer_input.addClass("correct");
          }
          else if (result.status == 3){ // Keys per minute too high
              result_notification.addClass('alert alert-warning alert-dismissable text-center');
              result_notification.slideDown();
  
              answer_input.addClass("too-fast");
              setTimeout(function() {
                  answer_input.removeClass("too-fast");
              }, 3000);
          }
          marksolves();
          updatesolves();
          setTimeout(function(){
            $('.alert').slideUp();
            $('#submit-key').removeClass("disabled-button");
            $('#submit-key').prop('disabled', false);
          }, 3000);
      })
  }
  
  function marksolves(cb) {
      $.get(script_root + '/solves', function (data) {
          var solves = $.parseJSON(JSON.stringify(data));
          for (var i = solves['solves'].length - 1; i >= 0; i--) {
              var id = solves['solves'][i].chalid;
              $('button[value="' + id + '"]').removeClass('theme-background');
              $('button[value="' + id + '"]').addClass('solved-challenge');
          };
          if (cb) {
              cb();
          }
      });
  }
  
  function updatesolves(cb){
      $.get(script_root + '/chals/solves', function (data) {
          var solves = $.parseJSON(JSON.stringify(data));
          var chalids = Object.keys(solves);
  
          for (var i = 0; i < chalids.length; i++) {
              for (var z = 0; z < challenges['game'].length; z++) {
                  var obj = challenges['game'][z];
                  var solve_cnt = solves[chalids[i]];
                  if (obj.id == chalids[i]){
                      if (solve_cnt) {
                          obj.solves = solve_cnt;
                      } else {
                          obj.solves = 0;
                      }
                  }
              }
          };
          if (cb) {
              cb();
          }
      });
  }
  
  function getsolves(id){
    $.get(script_root + '/chal/'+id+'/solves', function (data) {
      var teams = data['teams'];
      $('.chal-solves').text((parseInt(teams.length) + " Solves"));
      var box = $('#chal-solves-names');
      box.empty();
      for (var i = 0; i < teams.length; i++) {
        var id = teams[i].id;
        var name = teams[i].name;
        var date = moment(teams[i].date).local().format('LLL');
        box.append('<tr><td><a href="team/{0}">{1}</td><td>{2}</td></tr>'.format(id, htmlentities(name), date));
      };
    });
  }
  
  function loadchals(cb) {
      $.get(script_root + "/chals", function (data) {
          var categories = [];
          challenges = $.parseJSON(JSON.stringify(data));
  
          $('#challenges-board').html("");
  
          for (var i = challenges['game'].length - 1; i >= 0; i--) {
              challenges['game'][i].solves = 0
              if ($.inArray(challenges['game'][i].category, categories) == -1) {
                  var category = challenges['game'][i].category;
                  categories.push(category);
  
                  var categoryid = category.replace(/ /g,"-").hashCode();
                  var categoryrow = $('' +
                      '<div id="{0}-row">'.format(categoryid) +
                          '<div class="category-header col-md-2">' +
                          '</div>' +
                          '<div class="category-challenges col-md-12">' +
                              '<div class="chal-row"></div>' +
                          '</div>' +
                      '</div>');
                  categoryrow.find(".category-header").append($("<h3>"+ category +"</h3>"));
  
                  $('#challenges-board').append(categoryrow);
              }
          };
  
          for (var i = 0; i <= challenges['game'].length - 1; i++) {
              var chalinfo = challenges['game'][i];
              var challenge = chalinfo.category.replace(/ /g,"-").hashCode();
              var chalid = chalinfo.name.replace(/ /g,"-").hashCode();
              var catid = chalinfo.category.replace(/ /g,"-").hashCode();
              var chalwrap = $("<div id='{0}' class='challenge-wrapper col-md-2'></div>".format(chalid));
              var chalbutton = $("<button class='challenge-button trigger theme-background hide-text' value='{0}'></div>".format(chalinfo.id));
              var chalheader = $("<h5>{0}</h5>".format(chalinfo.name));
              var chalscore = $("<span>{0}</span>".format(chalinfo.value));
              for (var j = 0; j < chalinfo.tags.length; j++) {
                  var tag = 'tag-' + chalinfo.tags[j].replace(/ /g, '-');
                  chalwrap.addClass(tag);
              }
  
              chalbutton.append(chalheader);
              chalbutton.append(chalscore);
              chalwrap.append(chalbutton);
  
              $("#"+ catid +"-row").find(".category-challenges > .chal-row").append(chalwrap);
          };
  
          marksolves();
  
          $('.challenge-button').click(function (e) {
              loadchal(this.value);
          });
  
          if (cb){
              cb();
          }
      });
  }
  
  function loadhint(hintid){
      if (confirm("Are you sure you want to open this hint?")){
          $.post(script_root + "/hints/" + hintid, {'nonce': $('#nonce').val()}, function(data){
              if (data.errors){
                  alert(data.errors);
              } else {
                  $('#hint-modal-body').html(marked(data.hint, {'gfm':true, 'breaks':true}));
                  $('#hint-modal').modal();
              }
          });
      }
  }
  
  $('#submit-key').click(function (e) {
      submitkey($('#chal-id').val(), $('#answer-input').val(), $('#nonce').val())
  });
  
  $('.chal-solves').click(function (e) {
      getsolves($('#chal-id').val())
  });
  
  $('#chal-window').on('hide.bs.modal', function (event) {
      $("#answer-input").removeClass("wrong");
      $("#answer-input").removeClass("correct");
      $("#incorrect-key").slideUp();
      $("#correct-key").slideUp();
      $("#already-solved").slideUp();
      $("#too-fast").slideUp();
  });
  
  // $.distint(array)
  // Unique elements in array
  $.extend({
      distinct : function(anArray) {
         var result = [];
         $.each(anArray, function(i,v){
             if ($.inArray(v, result) == -1) result.push(v);
         });
         return result;
      }
  });
  
  function colorhash (x) {
      color = "";
      for (var i = 20; i <= 60; i+=20){
          x += i;
          x *= i;
          color += x.toString(16)
      };
      return "#" + color.substring(0, 6);
  }
  
  var load_location_hash = function () {
      if (window.location.hash.length > 0) {
          loadchalbyname(window.location.hash.substring(1));
          $("#chal-window").modal("show");
      }
  };
  
  function update(){
      loadchals(function(){
          updatesolves();
      });
  }
  
  $(function() {
      loadchals(function(){
          updatesolves(load_location_hash);
      });
  });
  
  $('.nav-tabs a').click(function (e) {
      e.preventDefault();
      $(this).tab('show')
  })
  
  $('#chal-window').on('hidden.bs.modal', function() {
      $('.nav-tabs a:first').tab('show');
      history.replaceState('', document.title, window.location.pathname);
  });
  
  setInterval(update, 300000);
  