<commit_before>// Auto Generated on 2022-05-07T03:24:44.048Z
 module.exports = [
  {
    "event": {
      "title": "data.MAY <- Provisional: MLens and Cubist",
      "description": "CALL FOR SPEAKERS:\n\nDo you have an interesting data story to tell?\n\nWould you like to give this month's presentation?\n\nFollow the link below to our Google form to express your interest and we'll contact you soon!\n\nhttps://forms.gle/y57b2seehSgvtGgn7\n\n##-------------------------------------------------------------------##\n\nVENUE:\n\nNEW LOCATION!\n\nThe university's brand new Q building in Honeysuckle!\n\nhttps://goo.gl/maps/35LwcLhKV1nvoFAh7\n\nIMPORTANT this is NOT the NewSpace building where we met last year.\n\nWe will meet in the Level 2 Seminar Space. You'll need to enter through the main doors on Worth Place and will be directed to the elevators to join the meetup.\n\nPARKING: The closest parking is Wright Lane Carpark.\nhttps://goo.gl/maps/rj6Yg8EkpjYzUmbi7\n\nAfter 5pm it is free and is a 400m - 5 minute walk.\n\n##-------------------------------------------------------------------##\n\nTIME: 5.30pm - 7.30pm\n\nFOOD: 🍕 + 🥤\n- Wood fired pizza, sponsored by Newy Tech People\n- Please advise dietary requirements in RSVP\n- Soft drinks\n\nSCHEDULE:\n- 5:30pm: Networking + Food + Drinks\n(Don't stress if you are held up in traffic)\n- 6:15pm: Presentation\n- 7:15pm: Packing up + Bonus questions\n- 7:30pm: Close",
      "dateTime": "2022-05-19T17:30+10:00",
      "eventUrl": "https://www.meetup.com/Hunter-Data-Analytics/events/283702245",
      "going": 12,
      "maxTickets": 40,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/501789003/676x380.webp",
      "venue": {
        "name": "Q Building, The University of Newcastle",
        "lat": -32.926277,
        "lng": 151.7683,
        "address": "16B Honeysuckle Dr",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Hunter Data Analytics",
      "urlname": "Hunter-Data-Analytics",
      "groupPhoto": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "Beer and chats",
      "description": "It's been a while... time for a beer (or drink of choice) and a chat, whether you work in the design space, are studying design or just interested in design.\n\nPlease stay at home if you're unwell, you know the drill by now!\n\nLooking forward to catching up in person.",
      "dateTime": "2022-05-25T18:00+10:00",
      "eventUrl": "https://www.meetup.com/IxDA-Newcastle/events/285605518",
      "going": 11,
      "maxTickets": 0,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/468275527/676x380.webp",
      "venue": {
        "name": "The Edwards",
        "lat": -32.92747,
        "lng": 151.75963,
        "address": "148 Parry St",
        "city": "Newcastle West"
      }
    },
    "group": {
      "name": "IxDA Newcastle",
      "urlname": "IxDA-Newcastle",
      "groupPhoto": {
        "id": "468275527",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "468275527",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "NCSG, May* 2022 | Dr. Alana Maurushat",
      "description": "Hello friends! Welcome back to another instalment of NCSG.\n\nThis month, we're lucky to have Dr. Alana Maurushat, Director of CACE (the Western Centre for Cybersecurity Aid & Community Engagement). Dr. Maurushat will be talking about the world of cybercrime and its evolution, and considering her background, this'll be an interesting dive into the underbelly of cybersecurity.\n\nTo learn more about Dr. Maurushat, check out her LinkedIn [here](https://www.linkedin.com/in/alana-maurushat-587116204/?originalSubdomain=au), as well as her profile on AustCyber [here](https://www.austcyber.com/alana-maurushat).\n\n**Event details:**\n\nDate: June 2, 2022 (aka May 33rd 😎)\nTime: 18:00-20:00ish (or until we go to the pub)\nVenue: 16 Honeysuckle Drive, Newcastle (The University of Newcastle 'Q Building') - seminar space on Level 2\nFood: Provided, please inform us of dietary requirements when RSVPing\nDrink: Non-alcoholic provided, come and grab a few with us at the pub after if you'd like!\n\n**The rest:**\n\nIf you’re experiencing any symptoms representative of COVID-19, please don’t attend. We’ll miss you, but the health/safety of attendees is paramount.\n\nNCSG is a community group determined to improve and uplift the Newcastle cybersecurity community. We meet monthly (on the last Thursday of each month... except for this one) and have a bunch of interesting speakers, from local legends to heavy hitters in the enterprise world.\n\nWant to learn more? Be sure to follow us on LinkedIn: linkedin.com/company/newcastlecybersecuritygroup/ or visit newwwie.com, join the community and come and chat in the #security channel.",
      "dateTime": "2022-06-02T18:00+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-Cyber-Security-Group/events/285731908",
      "going": 11,
      "maxTickets": 50,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/503902798/676x380.webp",
      "venue": {
        "name": "Q Building, The University of Newcastle",
        "lat": -32.926277,
        "lng": 151.7683,
        "address": "16B Honeysuckle Dr",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Newcastle Cyber Security Group",
      "urlname": "Newcastle-Cyber-Security-Group",
      "groupPhoto": {
        "id": "483205216",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483205216",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "Innovation in the Water Industry using IoT",
      "description": "IoT Pioneers in June, hear from Sydney Water's IoT Manager Christoph Prackwieser as he walks us through innovation in the water Industry.\n\nWith a PHD in business informatics and a degree in IT from Vienna, Christoph has had more than 20 years of experience in Aligning information technology with business needs to create solutions that drive change.\n\nAs always, after the presentation, there will be opportunities to network with other attendees and enjoy some of the fine food on offer.\n\nJoin us on June 2nd from 6:30 pm - 8:30 pm at The Stag & Hunter Hotel. Feel free to grab a drink at the bar and come on up; dinner will be provided.\n\nPlease make sure to RSVP\n\n#meetup #networking #engineering #startup #IoT",
      "dateTime": "2022-06-02T18:30+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-IoT-Pioneers/events/285707120",
      "going": 3,
      "maxTickets": 0,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/503884007/676x380.webp",
      "venue": {
        "name": "The Stag and Hunter hotel ",
        "lat": -32.897346,
        "lng": 151.73651,
        "address": "cnr hanbury and maitland rd  mayfield",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Newcastle IoT Pioneers",
      "urlname": "Newcastle-IoT-Pioneers",
      "groupPhoto": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  }
]<commit_msg>Get latest set of Meetup events<commit_after>// Auto Generated on 2022-05-07T06:35:49.213Z
 module.exports = [
  {
    "event": {
      "title": "data.MAY <- Provisional: MLens and Cubist",
      "description": "CALL FOR SPEAKERS:\n\nDo you have an interesting data story to tell?\n\nWould you like to give this month's presentation?\n\nFollow the link below to our Google form to express your interest and we'll contact you soon!\n\nhttps://forms.gle/y57b2seehSgvtGgn7\n\n##-------------------------------------------------------------------##\n\nVENUE:\n\nNEW LOCATION!\n\nThe university's brand new Q building in Honeysuckle!\n\nhttps://goo.gl/maps/35LwcLhKV1nvoFAh7\n\nIMPORTANT this is NOT the NewSpace building where we met last year.\n\nWe will meet in the Level 2 Seminar Space. You'll need to enter through the main doors on Worth Place and will be directed to the elevators to join the meetup.\n\nPARKING: The closest parking is Wright Lane Carpark.\nhttps://goo.gl/maps/rj6Yg8EkpjYzUmbi7\n\nAfter 5pm it is free and is a 400m - 5 minute walk.\n\n##-------------------------------------------------------------------##\n\nTIME: 5.30pm - 7.30pm\n\nFOOD: 🍕 + 🥤\n- Wood fired pizza, sponsored by Newy Tech People\n- Please advise dietary requirements in RSVP\n- Soft drinks\n\nSCHEDULE:\n- 5:30pm: Networking + Food + Drinks\n(Don't stress if you are held up in traffic)\n- 6:15pm: Presentation\n- 7:15pm: Packing up + Bonus questions\n- 7:30pm: Close",
      "dateTime": "2022-05-19T17:30+10:00",
      "eventUrl": "https://www.meetup.com/Hunter-Data-Analytics/events/283702245",
      "going": 12,
      "maxTickets": 40,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/501789003/676x380.webp",
      "venue": {
        "name": "Q Building, The University of Newcastle",
        "lat": -32.926277,
        "lng": 151.7683,
        "address": "16B Honeysuckle Dr",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Hunter Data Analytics",
      "urlname": "Hunter-Data-Analytics",
      "groupPhoto": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483576656",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "Beer and chats",
      "description": "It's been a while... time for a beer (or drink of choice) and a chat, whether you work in the design space, are studying design or just interested in design.\n\nPlease stay at home if you're unwell, you know the drill by now!\n\nLooking forward to catching up in person.",
      "dateTime": "2022-05-25T18:00+10:00",
      "eventUrl": "https://www.meetup.com/IxDA-Newcastle/events/285605518",
      "going": 11,
      "maxTickets": 0,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/468275527/676x380.webp",
      "venue": {
        "name": "The Edwards",
        "lat": -32.92747,
        "lng": 151.75963,
        "address": "148 Parry St",
        "city": "Newcastle West"
      }
    },
    "group": {
      "name": "IxDA Newcastle",
      "urlname": "IxDA-Newcastle",
      "groupPhoto": {
        "id": "468275527",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "468275527",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "NCSG, May* 2022 | Dr. Alana Maurushat",
      "description": "Hello friends! Welcome back to another instalment of NCSG.\n\nThis month, we're lucky to have Dr. Alana Maurushat, Director of CACE (the Western Centre for Cybersecurity Aid & Community Engagement). Dr. Maurushat will be talking about the world of cybercrime and its evolution, and considering her background, this'll be an interesting dive into the underbelly of cybersecurity.\n\nTo learn more about Dr. Maurushat, check out her LinkedIn [here](https://www.linkedin.com/in/alana-maurushat-587116204/?originalSubdomain=au), as well as her profile on AustCyber [here](https://www.austcyber.com/alana-maurushat).\n\n**Event details:**\n\nDate: June 2, 2022 (aka May 33rd 😎)\nTime: 18:00-20:00ish (or until we go to the pub)\nVenue: 16 Honeysuckle Drive, Newcastle (The University of Newcastle 'Q Building') - seminar space on Level 2\nFood: Provided, please inform us of dietary requirements when RSVPing\nDrink: Non-alcoholic provided, come and grab a few with us at the pub after if you'd like!\n\n**The rest:**\n\nIf you’re experiencing any symptoms representative of COVID-19, please don’t attend. We’ll miss you, but the health/safety of attendees is paramount.\n\nNCSG is a community group determined to improve and uplift the Newcastle cybersecurity community. We meet monthly (on the last Thursday of each month... except for this one) and have a bunch of interesting speakers, from local legends to heavy hitters in the enterprise world.\n\nWant to learn more? Be sure to follow us on LinkedIn: linkedin.com/company/newcastlecybersecuritygroup/ or visit newwwie.com, join the community and come and chat in the #security channel.",
      "dateTime": "2022-06-02T18:00+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-Cyber-Security-Group/events/285731908",
      "going": 11,
      "maxTickets": 50,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/503902798/676x380.webp",
      "venue": {
        "name": "Q Building, The University of Newcastle",
        "lat": -32.926277,
        "lng": 151.7683,
        "address": "16B Honeysuckle Dr",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Newcastle Cyber Security Group",
      "urlname": "Newcastle-Cyber-Security-Group",
      "groupPhoto": {
        "id": "483205216",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "483205216",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  },
  {
    "event": {
      "title": "Innovation in the Water Industry using IoT",
      "description": "IoT Pioneers in June, hear from Sydney Water's IoT Manager Christoph Prackwieser as he walks us through innovation in the water Industry.\n\nWith a PHD in business informatics and a degree in IT from Vienna, Christoph has had more than 20 years of experience in Aligning information technology with business needs to create solutions that drive change.\n\nAs always, after the presentation, there will be opportunities to network with other attendees and enjoy some of the fine food on offer.\n\nJoin us on June 2nd from 6:30 pm - 8:30 pm at The Stag & Hunter Hotel. Feel free to grab a drink at the bar and come on up; dinner will be provided.\n\nPlease make sure to RSVP\n\n#meetup #networking #engineering #startup #IoT",
      "dateTime": "2022-06-02T18:30+10:00",
      "eventUrl": "https://www.meetup.com/Newcastle-IoT-Pioneers/events/285707120",
      "going": 3,
      "maxTickets": 0,
      "duration": "PT2H",
      "imageUrl": "https://secure-content.meetupstatic.com/images/classic-events/503884007/676x380.webp",
      "venue": {
        "name": "The Stag and Hunter hotel ",
        "lat": -32.897346,
        "lng": 151.73651,
        "address": "cnr hanbury and maitland rd  mayfield",
        "city": "Newcastle"
      }
    },
    "group": {
      "name": "Newcastle IoT Pioneers",
      "urlname": "Newcastle-IoT-Pioneers",
      "groupPhoto": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      },
      "logo": {
        "id": "465862831",
        "baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
        "preview": null
      }
    }
  }
]<|endoftext|>


<commit_before>(function (){

/** Scroll to current line when hash changes */
function hashchanged(){
  var line, name, elems;
  if((line = findLine()) != -1){
    if(elem = document.getElementById("line-" + line)){
      // Remove highlighted from everything
      var highligted = document.querySelectorAll(".highlight");
      for(var i = 0; i < highligted.length; i++)
        highligted[i].classList.remove("highlight");
      // Highlight the line
      elem.parentNode.classList.add("highlight");
      // Highlight the annotation set for the line
      var aset = document.getElementById("aset-" + line);
      aset.classList.add("highlight");
      window.scroll(0, findPosTop(elem) - window.innerHeight / 4.0);
    }
  }
}

/** Add auxiliary string method for indexOf using regexp
 * Credits to: http://stackoverflow.com/a/274094
 */
String.prototype.regexIndexOf = function(regex, startpos){
  var indexOf = this.substring(startpos || 0).search(regex);
  return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}

/** Add auxiliary string method for LastIndexOf using regexp
 * Credits to: http://stackoverflow.com/a/274094
 */
String.prototype.regexLastIndexOf = function(regex, startpos){
  if(!regex.global){
    var flags = "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : "");
    regex = new RegExp(regex.source, flags);
  }
  if(typeof (startpos) == "undefined") {
      startpos = this.length;
  } else if(startpos < 0) {
      startpos = 0;
  }
  var stringToWorkWith = this.substring(0, startpos + 1);
  var lastIndexOf = -1;
  var nextStop = 0;
  while((result = regex.exec(stringToWorkWith)) != null) {
      lastIndexOf = result.index;
      regex.lastIndex = ++nextStop;
  }
  return lastIndexOf;
}

/** Initialize the context menu */
function init_menu(){
  var pre = document.querySelector(".file-lines pre");
  // Show menu when text is clicked
  pre.addEventListener('click', function(e){
    // Abort if the target isn't a code node underneath
    if(e.target == pre) return;
    var links = []
    // Find the word clicked
    var s = window.getSelection();
    // If there's a selection, we don't show menu, so users can copy/paste things
    if(!s.isCollapsed) return;
    var offset = s.focusOffset;
    var text  = s.anchorNode.nodeValue;
    var start = text.regexLastIndexOf(/[^A-Z0-9_]/i, offset) + 1;
    var end   = text.regexIndexOf(/[^A-Z0-9_]/i, offset);
    if(start == -1) start = 0;
    if(end   == -1) end   = text.length;
    var word = text.substr(start, end - start);
    // Make work link
    if(word.length > 0){
      links.push({
        icon:   'search',
        text:   "Search for \"" + htmlEntities(word) + "\"",
        title:  "Search for documents with the substring \"" + htmlEntities(word) + "\"",
        href:   wwwroot + "/" + encodeURIComponent(dxr.tree()) + "/search?q=" + encodeURIComponent(word)
      });
    }
    // Append menu from target, if any
    if(e.target.dataset.menu){
      links = [].concat(links, JSON.parse(e.target.dataset.menu));
    }
    if(links.length == 0) return;
    // Populate and launch menu
    menu.populate(links);
    if(e.target.dataset.menu){
      menu.launch(e.target);
    }else{
      // Create a text range, and use it to get a bounding box
      // Our range will never cross elements, because we create it from
      // carat position, and when there's an actual non-empty selection
      // well, we can't really get the position of the click as text offset.
      var range = document.createRange();
      range.setStart(s.anchorNode, start);
      range.setEnd(s.anchorNode, end);
      var left = range.getBoundingClientRect().left;
      menu.launchAt(left, menu.posTop(e.target) + e.target.offsetHeight);
    }
    // Stop event propagation
    e.preventDefault();
    e.stopPropagation();
  }, false);
}

var pattern = /^#l[0-9]+$/;
/** Find line by anchor */
function findLine(){
  var result;
  if((result = pattern.exec(window.location.hash)) != null){
    return parseInt(result[0].substr(2));
  }
  return -1;
}

/** Find object position from the top */
function findPosTop(obj) {
  var top = 0;
  do{
    top += obj.offsetTop;
  }while(obj = obj.offsetParent);
  return top;
}

/** Find object position from the left */
function findPosLeft(obj) {
  var left = 0;
  do{
    left += obj.offsetLeft;
  }while(obj = obj.offsetParent);
  return left;
}

/** Initialize search tips */
function init_tip(){
  // Parse querystring for from=
  var query = null;
  var items = window.location.search.substr(1).split("&");
  for(var i = 0; i < items.length; i++){
    var keyvalue = items[i].split("=");
    if(keyvalue[0] == "from")
      query = keyvalue[1];
  }
  if(query){
    // Set a nice search tip, so people can go the results
    var url = wwwroot + "/" + encodeURIComponent(dxr.tree()) + "/search?q=" + encodeURIComponent(query) + "&redirect=false";
    text = ("You've been taken to a direct result " +
                     "click here" +
                     " to see all search results").replace("{{url}}", url);
    dxr.setTip(text);
    // Insert the query into the search field
    var q = document.getElementById("query");
    q.value     = query;
    state.query = query;
    // Make search field redirect = false, untill user types a different query
    var redirect = document.getElementById("redirect");
    redirect.value = "false";
    q.focus();
    window.addEventListener('dxr-state-changed', function(){
      if(state.query != query)
        redirect.value = "true";
      else
        redirect.value = "false";
    }, false);
  }
}

/** Escape HTML Entitites */
function htmlEntities(str) {
  return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
}

/** Hijack the blame link, to toggle blame annotations */
function hijackBlame(){
  var pc = document.getElementById("panel-content");
  var annos = document.getElementById("annotations");
  var blaming = false;
  // Helper for toggling the blame annotations
  function toggleBlame(){
    if(blaming)
      annos.classList.remove('blame');
    else
      annos.classList.add('blame');
    blaming = !blaming;
  }
  // Hijack click we think are hitting the blame link
  pc.addEventListener('click', function(e){
    // If the name is 'Blame'
    if(e.target.innerHTML != "Blame")
      return;
    // And it links to some sort of annotate
    var href = e.target.getAttribute('href');
    if(href.indexOf("/annotate/") == -1)
      return;
    // And it has the blame icon
    if(e.target.style.backgroundImage.indexOf("blame") == -1)
      return;
    // It's probably the blame link and we hijack it :)
    // I know this ugly, but short of allowing plugins to define
    // javascript and other bad things, there's no other way to integrate
    // tightly. Besides all the ugly stuff is in the template in javascript
    // and javascript can't be pretty anyway.
    // NOTE: While this is an ugly hack, the plugin and template interfaces
    // are fully respected, if we remove the blame specific things the
    // annotations still work, they just can't be toggled.
    e.preventDefault();
    e.stopPropagation();
    toggleBlame();
  }, true);

  // Get the info box
  var infobox = document.getElementById("info-box");

  // Handle clicks on note-blame annotations
  annos.addEventListener('click', function(e){
    if(e.target.classList.contains("note-blame")){
      // Stop what you're doing we've got a info-box to show
      e.preventDefault();
      e.stopPropagation();
      var data = e.target.dataset;
      var html = ""
       + ""
       + "" + htmlEntities(data.hgUser) + "
"
       + "" + dxr.prettyDate(data.hgDate) + "
"
       + e.target.getAttribute("title");
      infobox.innerHTML = html;
      infobox.style.display = 'block';
      infobox.style.top     = (menu.posTop(e.target) + e.target.offsetHeight) + "px";
      infobox.style.left    = menu.posLeft(e.target) + "px";
    }
  }, false);

  // Stop event to reaching window
  infobox.addEventListener('mousedown', function(e){
    e.stopPropagation();
  }, false);

  // Hide info when something is clicked
  window.addEventListener('mousedown', function(e){
    infobox.style.display = 'none';
  }, false);
}

/** Initialize everything */
window.addEventListener('load', function (){
  window.addEventListener('hashchange', hashchanged, false);
  init_tip();
  init_menu();
  hijackBlame();
  setTimeout(hashchanged, 0);
}, false);

}());
<commit_msg>Fix overzealous URL escaping on search strings. Fix #855506.<commit_after>(function (){

/** Scroll to current line when hash changes */
function hashchanged(){
  var line, name, elems;
  if((line = findLine()) != -1){
    if(elem = document.getElementById("line-" + line)){
      // Remove highlighted from everything
      var highligted = document.querySelectorAll(".highlight");
      for(var i = 0; i < highligted.length; i++)
        highligted[i].classList.remove("highlight");
      // Highlight the line
      elem.parentNode.classList.add("highlight");
      // Highlight the annotation set for the line
      var aset = document.getElementById("aset-" + line);
      aset.classList.add("highlight");
      window.scroll(0, findPosTop(elem) - window.innerHeight / 4.0);
    }
  }
}

/** Add auxiliary string method for indexOf using regexp
 * Credits to: http://stackoverflow.com/a/274094
 */
String.prototype.regexIndexOf = function(regex, startpos){
  var indexOf = this.substring(startpos || 0).search(regex);
  return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}

/** Add auxiliary string method for LastIndexOf using regexp
 * Credits to: http://stackoverflow.com/a/274094
 */
String.prototype.regexLastIndexOf = function(regex, startpos){
  if(!regex.global){
    var flags = "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : "");
    regex = new RegExp(regex.source, flags);
  }
  if(typeof (startpos) == "undefined") {
      startpos = this.length;
  } else if(startpos < 0) {
      startpos = 0;
  }
  var stringToWorkWith = this.substring(0, startpos + 1);
  var lastIndexOf = -1;
  var nextStop = 0;
  while((result = regex.exec(stringToWorkWith)) != null) {
      lastIndexOf = result.index;
      regex.lastIndex = ++nextStop;
  }
  return lastIndexOf;
}

/** Initialize the context menu */
function init_menu(){
  var pre = document.querySelector(".file-lines pre");
  // Show menu when text is clicked
  pre.addEventListener('click', function(e){
    // Abort if the target isn't a code node underneath
    if(e.target == pre) return;
    var links = []
    // Find the word clicked
    var s = window.getSelection();
    // If there's a selection, we don't show menu, so users can copy/paste things
    if(!s.isCollapsed) return;
    var offset = s.focusOffset;
    var text  = s.anchorNode.nodeValue;
    var start = text.regexLastIndexOf(/[^A-Z0-9_]/i, offset) + 1;
    var end   = text.regexIndexOf(/[^A-Z0-9_]/i, offset);
    if(start == -1) start = 0;
    if(end   == -1) end   = text.length;
    var word = text.substr(start, end - start);
    // Make work link
    if(word.length > 0){
      links.push({
        icon:   'search',
        text:   "Search for \"" + htmlEntities(word) + "\"",
        title:  "Search for documents with the substring \"" + htmlEntities(word) + "\"",
        href:   wwwroot + "/" + encodeURIComponent(dxr.tree()) + "/search?q=" + encodeURIComponent(word)
      });
    }
    // Append menu from target, if any
    if(e.target.dataset.menu){
      links = [].concat(links, JSON.parse(e.target.dataset.menu));
    }
    if(links.length == 0) return;
    // Populate and launch menu
    menu.populate(links);
    if(e.target.dataset.menu){
      menu.launch(e.target);
    }else{
      // Create a text range, and use it to get a bounding box
      // Our range will never cross elements, because we create it from
      // carat position, and when there's an actual non-empty selection
      // well, we can't really get the position of the click as text offset.
      var range = document.createRange();
      range.setStart(s.anchorNode, start);
      range.setEnd(s.anchorNode, end);
      var left = range.getBoundingClientRect().left;
      menu.launchAt(left, menu.posTop(e.target) + e.target.offsetHeight);
    }
    // Stop event propagation
    e.preventDefault();
    e.stopPropagation();
  }, false);
}

var pattern = /^#l[0-9]+$/;
/** Find line by anchor */
function findLine(){
  var result;
  if((result = pattern.exec(window.location.hash)) != null){
    return parseInt(result[0].substr(2));
  }
  return -1;
}

/** Find object position from the top */
function findPosTop(obj) {
  var top = 0;
  do{
    top += obj.offsetTop;
  }while(obj = obj.offsetParent);
  return top;
}

/** Find object position from the left */
function findPosLeft(obj) {
  var left = 0;
  do{
    left += obj.offsetLeft;
  }while(obj = obj.offsetParent);
  return left;
}

/** Initialize search tips */
function init_tip(){
  // Parse querystring for from=
  var query = null;
  var items = window.location.search.substr(1).split("&");
  for(var i = 0; i < items.length; i++){
    var keyvalue = items[i].split("=");
    if(keyvalue[0] == "from")
      query = decodeURIComponent(keyvalue[1]);
  }
  if(query){
    // Set a nice search tip, so people can go the results
    var url = wwwroot + "/" + encodeURIComponent(dxr.tree()) + "/search?q=" + encodeURIComponent(query) + "&redirect=false";
    text = ("You've been taken to a direct result " +
                     "click here" +
                     " to see all search results").replace("{{url}}", url);
    dxr.setTip(text);
    // Insert the query into the search field
    var q = document.getElementById("query");
    q.value     = query;
    state.query = query;
    // Make search field redirect = false, untill user types a different query
    var redirect = document.getElementById("redirect");
    redirect.value = "false";
    q.focus();
    window.addEventListener('dxr-state-changed', function(){
      if(state.query != query)
        redirect.value = "true";
      else
        redirect.value = "false";
    }, false);
  }
}

/** Escape HTML Entitites */
function htmlEntities(str) {
  return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
}

/** Hijack the blame link, to toggle blame annotations */
function hijackBlame(){
  var pc = document.getElementById("panel-content");
  var annos = document.getElementById("annotations");
  var blaming = false;
  // Helper for toggling the blame annotations
  function toggleBlame(){
    if(blaming)
      annos.classList.remove('blame');
    else
      annos.classList.add('blame');
    blaming = !blaming;
  }
  // Hijack click we think are hitting the blame link
  pc.addEventListener('click', function(e){
    // If the name is 'Blame'
    if(e.target.innerHTML != "Blame")
      return;
    // And it links to some sort of annotate
    var href = e.target.getAttribute('href');
    if(href.indexOf("/annotate/") == -1)
      return;
    // And it has the blame icon
    if(e.target.style.backgroundImage.indexOf("blame") == -1)
      return;
    // It's probably the blame link and we hijack it :)
    // I know this ugly, but short of allowing plugins to define
    // javascript and other bad things, there's no other way to integrate
    // tightly. Besides all the ugly stuff is in the template in javascript
    // and javascript can't be pretty anyway.
    // NOTE: While this is an ugly hack, the plugin and template interfaces
    // are fully respected, if we remove the blame specific things the
    // annotations still work, they just can't be toggled.
    e.preventDefault();
    e.stopPropagation();
    toggleBlame();
  }, true);

  // Get the info box
  var infobox = document.getElementById("info-box");

  // Handle clicks on note-blame annotations
  annos.addEventListener('click', function(e){
    if(e.target.classList.contains("note-blame")){
      // Stop what you're doing we've got a info-box to show
      e.preventDefault();
      e.stopPropagation();
      var data = e.target.dataset;
      var html = ""
       + ""
       + "" + htmlEntities(data.hgUser) + "
"
       + "" + dxr.prettyDate(data.hgDate) + "
"
       + e.target.getAttribute("title");
      infobox.innerHTML = html;
      infobox.style.display = 'block';
      infobox.style.top     = (menu.posTop(e.target) + e.target.offsetHeight) + "px";
      infobox.style.left    = menu.posLeft(e.target) + "px";
    }
  }, false);

  // Stop event to reaching window
  infobox.addEventListener('mousedown', function(e){
    e.stopPropagation();
  }, false);

  // Hide info when something is clicked
  window.addEventListener('mousedown', function(e){
    infobox.style.display = 'none';
  }, false);
}

/** Initialize everything */
window.addEventListener('load', function (){
  window.addEventListener('hashchange', hashchanged, false);
  init_tip();
  init_menu();
  hijackBlame();
  setTimeout(hashchanged, 0);
}, false);

}());
<|endoftext|>


<commit_before>let rhino3dm = require ('../../../libs/rhino3dm.min.js')
let fs = require ('fs');
let path = require ('path');

function Write3dmFileToJson (rhino, rhinoFileName, outputFolder)
{
	console.log ('Writing 3dm to json: ' + outputFolder);
	if (!fs.existsSync (outputFolder)){
		fs.mkdirSync (outputFolder);
	}
	let inputBuffer = fs.readFileSync (rhinoFileName, null).buffer;
	let inputArray = new Uint8Array (inputBuffer);
	let inputDoc = rhino.File3dm.fromByteArray (inputArray);
	let objects = inputDoc.objects ();
	for (let i = 0; i < objects.count; i++) {
		let mesh = objects.get (i).geometry ();
		if (mesh instanceof rhino.Mesh) {
			let threeJson = mesh.toThreejsJSON ();
			let jsonFileName = path.join (outputFolder, 'mesh' + i + '.json');
			fs.writeFileSync (jsonFileName, JSON.stringify (threeJson, null, 4));
		}
	}
}

function WriteJsonTo3dmFile (rhino, inputFolder)
{
	console.log ('Writing json to 3dm: ' + inputFolder);
	let outputDoc = new rhino.File3dm ();
	let fileNames = fs.readdirSync (inputFolder);
	for (let i = 0; i < fileNames.length; i++) {
		let fileName = fileNames[i];
		if (path.extname (fileName) != '.json') {
			continue;
		}
		let filePath = path.join (inputFolder, fileName);
		let fileContent = fs.readFileSync (filePath);
		let jsonContent = JSON.parse (fileContent);
		let rhinoMesh = new rhino.Mesh.createFromThreejsJSON (jsonContent);
		outputDoc.objects ().add (rhinoMesh, null);
	}
	let writeOptions = new rhino.File3dmWriteOptions ();
	writeOptions.version = 6;
	let outputBuffer = outputDoc.toByteArray (writeOptions);
	fs.writeFileSync (path.join (inputFolder, 'model.3dm'), outputBuffer);
}

if (!fs.existsSync ('output')){
	fs.mkdirSync ('output');
}

rhino3dm ().then (async function (rhinoIn) {
	Write3dmFileToJson (rhinoIn, 'input/hello_mesh.3dm', 'output/hello_mesh');
	Write3dmFileToJson (rhinoIn, 'input/one_cube.3dm', 'output/one_cube');
	Write3dmFileToJson (rhinoIn, 'input/two_cubes.3dm', 'output/two_cubes');
	Write3dmFileToJson (rhinoIn, 'input/three_cubes.3dm', 'output/three_cubes');
	rhino3dm ().then (async function (rhinoOut) {
		WriteJsonTo3dmFile (rhinoOut, 'output/hello_mesh');
		WriteJsonTo3dmFile (rhinoOut, 'output/one_cube');
		WriteJsonTo3dmFile (rhinoOut, 'output/two_cubes');
		WriteJsonTo3dmFile (rhinoOut, 'output/three_cubes');
	});
});
<commit_msg>Do not write jsons to a file.<commit_after>let rhino3dm = require ('../../../libs/rhino3dm.min.js')
let fs = require ('fs');
let path = require ('path');

function GetThreeMeshesFrom3dm (rhino, rhinoFileName)
{
	let inputBuffer = fs.readFileSync (rhinoFileName, null).buffer;
	let inputArray = new Uint8Array (inputBuffer);
	let inputDoc = rhino.File3dm.fromByteArray (inputArray);
	let objects = inputDoc.objects ();
	let threeMeshes = [];
	for (let i = 0; i < objects.count; i++) {
		let mesh = objects.get (i).geometry ();
		if (mesh instanceof rhino.Mesh) {
			threeMeshes.push (mesh.toThreejsJSON ());
		}
	}
	return threeMeshes;
}

function WriteThreeMeshesTo3dm (rhino, threeMeshes, rhinoFileName)
{
	let outputDoc = new rhino.File3dm ();
	for (let i = 0; i < threeMeshes.length; i++) {
		let rhinoMesh = new rhino.Mesh.createFromThreejsJSON (threeMeshes[i]);
		outputDoc.objects ().add (rhinoMesh, null);
	}
	let writeOptions = new rhino.File3dmWriteOptions ();
	writeOptions.version = 6;
	let outputBuffer = outputDoc.toByteArray (writeOptions);
	fs.writeFileSync (rhinoFileName, outputBuffer);
}

function ReadWriteRhinoFile (rhinoIn, rhinoOut, inputRhinoFile, outputRhinoFile)
{
	let threeMeshes = GetThreeMeshesFrom3dm (rhinoIn, inputRhinoFile);
	console.log ('Meshes in ' + inputRhinoFile + ': ' + threeMeshes.length);
	WriteThreeMeshesTo3dm (rhinoOut, threeMeshes, outputRhinoFile);
}

if (!fs.existsSync ('output')){
	fs.mkdirSync ('output');
}

rhino3dm ().then (async function (rhinoIn) {
	rhino3dm ().then (async function (rhinoOut) {
		ReadWriteRhinoFile (rhinoIn, rhinoOut, 'input/one_cube.3dm', 'output/one_cube.3dm');
		ReadWriteRhinoFile (rhinoIn, rhinoOut, 'input/two_cubes.3dm', 'output/two_cubes.3dm');
		ReadWriteRhinoFile (rhinoIn, rhinoOut, 'input/three_cubes.3dm', 'output/three_cubes.3dm');
	});
});
<|endoftext|>


<commit_before>var
  uuid = require("node-uuid"),
  extend = require("extend"),
  templates = require("../../sender/templates.js"),
  htmlToText = require('html-to-text'),
  mailer = require("../../sender/mail.js");

var mailregEx = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

module.exports = function(usermodel){
  usermodel.drafts = {};

  usermodel.drafts.getDraftIds = function(user, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){

        //extract the draft ids
        var draftIds = [];
        for(var i=0;i<message.length;i++){
          draftIds.push(message[i].id);
        }

        //and send them
        callback(true, draftIds);
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.getDraft = function(user, id, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){

        //search for the draft and find it.
        for(var i=0;i<message.length;i++){
          if(message[i].id == id){
            usermodel.drafts.buildDraft(user, message[i].data, callback);
            return;
          }
        }

        //hmm, can't find it.
        callback(false, "Draft does not exist. ");
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.getDrafts = function(user, callback){
    //extract the drafts
    var drafts = [];
    var rawDrafts = [];

    var step = function(i, length){
      if(i < length){
        usermodel.drafts.buildDraft(user, rawDrafts[i].data, function(success, message){
          if(success){
            drafts.push({id: rawDrafts[i].id, data: message});
            step(i+1, length);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(true, drafts);
      }
    }

    usermodel.users.getDrafts(user, function(success, message){
      if(success){
        rawDrafts = message;
        step(0, rawDrafts.length);
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.setDraft = function(user, id, draft, callback){
    usermodel.drafts.buildDraft(user, draft, function(success, message){
      if(success){
        var draft = message;
        usermodel.users.getDrafts(user, function(success, message){
          if(success){

            var done = false;

            //search for the draft and insert it.
            for(var i=0;i<message.length;i++){
              if(message[i].id == id){
                message[i].data = draft;
                done = true;
                break;
              }
            }

            if(!done){
              message.push({
                "id": id,
                "data": draft
              });
            }

            //set the drafts
            usermodel.users.setDrafts(user, message, callback);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });
  }
  usermodel.drafts.hasDraft = function(user, id, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){
        //search for the draft and find it.
        for(var i=0;i<message.length;i++){
          if(message[i].id == id){
            callback(true, true);
            return;
          }
        }

        //hmm, can't find it.
        callback(true, false);
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.deleteDraft = function(user, id, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){

        //search for the draft and delete it
        for(var i=0;i<message.length;i++){
          if(message[i].id == id){
            message.splice(i, 1);
            usermodel.users.setDrafts(user, message, callback);
            return;
          }
        }

        callback(false, "Draft does not exist. ");
      } else {
        callback(false, message);
      }
    });
  }

  usermodel.drafts.buildDraft = function(user, draft, callback){
    usermodel.users.getAllowedEmails(user, function(success, message){
      if(success){
        var availableEmails = message;
        usermodel.drafts.getAvailableTemplates(function(success, message){
          if(success){
            var cleanDraft = {};
            var availableTemplates = message;

            if(typeof draft !== "object"){
              callback(false, "Draft must be an object. ");
              return;
            }

            var done=false;

            ["to", "cc", "bcc"].map(function(to){
              if(done){
                return;
              }

              var toValue = draft[to];

              if(typeof toValue == "string"){
                if(toValue !== ""){
                  toValue = draft[to].split(",");
                } else {
                  toValue = [];
                }
              } else if(!Array.isArray(toValue)){
                toValue = [];
              }

              for(var i=0;i<toValue.length;i++){
                if(!mailregEx.test(toValue[i])){
                  callback(false, "Invalid e-mail adress '"+toValue[i]+"'. ")
                  done = true;
                  return;
                }
              }

              //and set the cleanDraft
              cleanDraft[to] = toValue;
            });

            if(done){
              return;
            }

            //validate subject
            if(!draft.hasOwnProperty("subject") || typeof draft.subject !== "string"){
              cleanDraft.subject = "(New mail)";
            } else {
              cleanDraft.subject = draft.subject;
            }

            //check from
            if(!draft.hasOwnProperty("from") || typeof draft.from !== "string" || availableEmails.indexOf(draft.from) == -1){
              cleanDraft.from = user; //from myself.
            } else {
              cleanDraft.from = draft.from;
            }

            //check content
            if(!draft.hasOwnProperty("content") || typeof draft.content !== "string"){
              cleanDraft.content = "";
            } else {
              cleanDraft.content = draft.content;
            }

            //check template
            if(!draft.hasOwnProperty("template") || typeof draft.template !== "string" || availableTemplates.indexOf(draft.template) == -1){
              cleanDraft.template = availableTemplates[0];
            } else {
              cleanDraft.template = draft.template;
            }

            //message content-type, either text or html.
            if(!draft.hasOwnProperty("content_type") || typeof draft.content_type !== "string" || ["html", "text"].indexOf(draft.content_type) == -1){
              cleanDraft.content_type = "html"; //default content type is html.
            } else {
              cleanDraft.content_type = draft.content_type;
            }

            //Render the draft
            var theTemplate = templates.getTemplateIfAvailable(cleanDraft.template);
            var theDraft = theTemplate[cleanDraft.content_type] || theTemplate["text"] || theTemplate["html"];

            //render the draft
            try{
              cleanDraft.content_cooked = theDraft(JSON.parse(JSON.stringify(cleanDraft)));
            } catch(e){
              callback(false, "Unable to render template '"+cleanDraft.template+"': "+e.message);
              return;
            }

            if(cleanDraft.content_type == "html"){
              if(theTemplate["text"]){
                cleanDraft.content_cooked_text = theTemplate["text"](JSON.parse(JSON.stringify(cleanDraft)));
              } else {
                cleanDraft.content_cooked_text = htmlToText.fromString(cleanDraft.content_cooked);
              }
            }

            //The end.
            callback(true, cleanDraft);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });
  }

  usermodel.drafts.getAvailableTemplates = function(callback){
    var templData = templates.getAll();
    var templateNames = [];

    for(var i=0;i<templData.length;i++){
      templateNames.push(templData[i].meta.title);
    }

    callback(true, templateNames);
  }

  usermodel.drafts.createNewDraft = function(user, callback){
    usermodel.drafts.createNewDraftId(user, function(success, message){
      var id = message;
      if(success){
        usermodel.drafts.setDraft(user, message, {}, function(success, message){
          if(success){
            callback(true, id);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });

  }

  usermodel.drafts.sendMail = function(user, id, callback){
    usermodel.drafts.getDraft(user, id, function(success, message){
      if(success){
        mailer(message, function(success, message){
          if(success){
            usermodel.drafts.deleteDraft(user, id, callback);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });
  };

  usermodel.drafts.createNewDraftId = function(user, callback){
    usermodel.drafts.getDraftIds(user, function(success, message){
      if(success){
        var newId;
        while(message.indexOf(newId = uuid.v1()+uuid.v4()) != -1){
          //do nothing.
        }

        callback(true, newId);
      } else {
        callback(false, message)
      }
    });
  }
}
<commit_msg>Fix Siggis bug<commit_after>var
  uuid = require("node-uuid"),
  extend = require("extend"),
  templates = require("../../sender/templates.js"),
  htmlToText = require('html-to-text'),
  mailer = require("../../sender/mail.js");

var mailregEx = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

module.exports = function(usermodel){
  usermodel.drafts = {};

  usermodel.drafts.getDraftIds = function(user, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){

        //extract the draft ids
        var draftIds = [];
        for(var i=0;i<message.length;i++){
          draftIds.push(message[i].id);
        }

        //and send them
        callback(true, draftIds);
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.getDraft = function(user, id, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){

        //search for the draft and find it.
        for(var i=0;i<message.length;i++){
          if(message[i].id == id){
            usermodel.drafts.buildDraft(user, message[i].data, callback);
            return;
          }
        }

        //hmm, can't find it.
        callback(false, "Draft does not exist. ");
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.getDrafts = function(user, callback){
    //extract the drafts
    var drafts = [];
    var rawDrafts = [];

    var step = function(i, length){
      if(i < length){
        usermodel.drafts.buildDraft(user, rawDrafts[i].data, function(success, message){
          if(success){
            drafts.push({id: rawDrafts[i].id, data: message});
            step(i+1, length);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(true, drafts);
      }
    }

    usermodel.users.getDrafts(user, function(success, message){
      if(success){
        rawDrafts = message;
        step(0, rawDrafts.length);
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.setDraft = function(user, id, draft, callback){
    usermodel.drafts.buildDraft(user, draft, function(success, message){
      if(success){
        var draft = message;
        usermodel.users.getDrafts(user, function(success, message){
          if(success){

            var done = false;

            //search for the draft and insert it.
            for(var i=0;i<message.length;i++){
              if(message[i].id == id){
                message[i].data = draft;
                done = true;
                break;
              }
            }

            if(!done){
              message.push({
                "id": id,
                "data": draft
              });
            }

            //set the drafts
            usermodel.users.setDrafts(user, message, callback);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });
  }
  usermodel.drafts.hasDraft = function(user, id, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){
        //search for the draft and find it.
        for(var i=0;i<message.length;i++){
          if(message[i].id == id){
            callback(true, true);
            return;
          }
        }

        //hmm, can't find it.
        callback(true, false);
      } else {
        callback(false, message);
      }
    })
  }

  usermodel.drafts.deleteDraft = function(user, id, callback){
    usermodel.users.getDrafts(user, function(success, message){
      if(success){

        //search for the draft and delete it
        for(var i=0;i<message.length;i++){
          if(message[i].id == id){
            message.splice(i, 1);
            usermodel.users.setDrafts(user, message, callback);
            return;
          }
        }

        callback(false, "Draft does not exist. ");
      } else {
        callback(false, message);
      }
    });
  }

  usermodel.drafts.buildDraft = function(user, draft, callback){
    usermodel.users.getAllowedEmails(user, function(success, message){
      if(success){
        var availableEmails = message;
        usermodel.drafts.getAvailableTemplates(function(success, message){
          if(success){
            var cleanDraft = {};
            var availableTemplates = message;

            if(typeof draft !== "object"){
              callback(false, "Draft must be an object. ");
              return;
            }

            var done=false;

            ["to", "cc", "bcc"].map(function(to){
              if(done){
                return;
              }

              var toValue = draft[to];

              if(typeof toValue == "string"){
                if(toValue !== ""){
                  toValue = draft[to].split(",");
                } else {
                  toValue = [];
                }
              } else if(!Array.isArray(toValue)){
                toValue = [];
              }

              for(var i=0;i<toValue.length;i++){
                //remove spaces from the adress
                //fix for siggis bug.
                toValue[i] = toValue[i].replace(" ", "");
                if(!mailregEx.test(toValue[i])){
                  callback(false, "Invalid e-mail adress '"+toValue[i]+"'. ")
                  done = true;
                  return;
                }
              }

              //and set the cleanDraft
              cleanDraft[to] = toValue;
            });

            if(done){
              return;
            }

            //validate subject
            if(!draft.hasOwnProperty("subject") || typeof draft.subject !== "string"){
              cleanDraft.subject = "(New mail)";
            } else {
              cleanDraft.subject = draft.subject;
            }

            //check from
            if(!draft.hasOwnProperty("from") || typeof draft.from !== "string" || availableEmails.indexOf(draft.from) == -1){
              cleanDraft.from = user; //from myself.
            } else {
              cleanDraft.from = draft.from;
            }

            //check content
            if(!draft.hasOwnProperty("content") || typeof draft.content !== "string"){
              cleanDraft.content = "";
            } else {
              cleanDraft.content = draft.content;
            }

            //check template
            if(!draft.hasOwnProperty("template") || typeof draft.template !== "string" || availableTemplates.indexOf(draft.template) == -1){
              cleanDraft.template = availableTemplates[0];
            } else {
              cleanDraft.template = draft.template;
            }

            //message content-type, either text or html.
            if(!draft.hasOwnProperty("content_type") || typeof draft.content_type !== "string" || ["html", "text"].indexOf(draft.content_type) == -1){
              cleanDraft.content_type = "html"; //default content type is html.
            } else {
              cleanDraft.content_type = draft.content_type;
            }

            //Render the draft
            var theTemplate = templates.getTemplateIfAvailable(cleanDraft.template);
            var theDraft = theTemplate[cleanDraft.content_type] || theTemplate["text"] || theTemplate["html"];

            //render the draft
            try{
              cleanDraft.content_cooked = theDraft(JSON.parse(JSON.stringify(cleanDraft)));
            } catch(e){
              callback(false, "Unable to render template '"+cleanDraft.template+"': "+e.message);
              return;
            }

            if(cleanDraft.content_type == "html"){
              if(theTemplate["text"]){
                cleanDraft.content_cooked_text = theTemplate["text"](JSON.parse(JSON.stringify(cleanDraft)));
              } else {
                cleanDraft.content_cooked_text = htmlToText.fromString(cleanDraft.content_cooked);
              }
            }

            //The end.
            callback(true, cleanDraft);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });
  }

  usermodel.drafts.getAvailableTemplates = function(callback){
    var templData = templates.getAll();
    var templateNames = [];

    for(var i=0;i<templData.length;i++){
      templateNames.push(templData[i].meta.title);
    }

    callback(true, templateNames);
  }

  usermodel.drafts.createNewDraft = function(user, callback){
    usermodel.drafts.createNewDraftId(user, function(success, message){
      var id = message;
      if(success){
        usermodel.drafts.setDraft(user, message, {}, function(success, message){
          if(success){
            callback(true, id);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });

  }

  usermodel.drafts.sendMail = function(user, id, callback){
    usermodel.drafts.getDraft(user, id, function(success, message){
      if(success){
        mailer(message, function(success, message){
          if(success){
            usermodel.drafts.deleteDraft(user, id, callback);
          } else {
            callback(false, message);
          }
        });
      } else {
        callback(false, message);
      }
    });
  };

  usermodel.drafts.createNewDraftId = function(user, callback){
    usermodel.drafts.getDraftIds(user, function(success, message){
      if(success){
        var newId;
        while(message.indexOf(newId = uuid.v1()+uuid.v4()) != -1){
          //do nothing.
        }

        callback(true, newId);
      } else {
        callback(false, message)
      }
    });
  }
}
<|endoftext|>


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

    var katex = null;
    var WebFontLoader = null;
    var fontsLoaded = false;
    var waitingInstances = [];

    createCindy.loadScript("WebFont", "webfont.js", loadFonts);
    createCindy.loadScript("katex", "katex/katex.min.js", katexReady);

    function loadFonts() {
        console.log("WebFontLoader is now available.");
        WebFontLoader = window.WebFont;
        WebFontLoader.load({
            custom: {
                families: [
                    "KaTeX_Main:n7,i4,n4",
                    "KaTeX_Math:i7,i4,n4",
                    "KaTeX_Size1:n4",
                    "KaTeX_Size2:n4",
                    "KaTeX_Size3:n4",
                    "KaTeX_Size4:n4",
                ],
                urls: [createCindy.getBaseDir() + "katex/katex.min.css"]
            },
            classes: false,
            active: fontsReady
        });
    }

    function fontsReady() {
        console.log("Math fonts are now available.");
        fontsLoaded = true;
        if (katex) doneWaiting();
    }

    function katexReady() {
        console.log("KaTeX is now available.");
        katex = window.katex;
        if (fontsLoaded) doneWaiting();
    }

    function doneWaiting() {
        var instances = waitingInstances;
        waitingInstances = null;
        for (var i = 0; i < instances.length; ++i)
            instances[i].evokeCS(""); // trigger repaint
    }

    createCindy.registerPlugin(1, "katex", plugin);

    function plugin(api) {
        if (waitingInstances)
            waitingInstances.push(api.instance);
        var storage = {cache: {}, misses:0};
        api.setTextRenderer(katexRenderer.bind(storage));
    }

    function textBox(ctx, text) {
        this.width = ctx.measureText(text).width;
        this.renderAt = function(x, y) {
            ctx.fillText(text, x, y);
        };
    }

    var firstMessage = true;

    function katexRenderer(ctx, text, x, y, align) {
        if (waitingInstances !== null) {
            if (firstMessage) {
                console.log("KaTeX is not ready yet.");
                firstMessage = false;
            }
            /*
            var width = ctx.measureText(text).width;
            ctx.fillText(text, x - align * width, y);
            */
            return;
        }
        var fontSize = /(?:^| )([0-9]+)px(?:$| )/.exec(ctx.font);
        fontSize = fontSize ? +fontSize[1] : 16;
        var key = fontSize + ":" + text;
        var parts, n, i;
        if (this.cache.hasOwnProperty(key)) {
            parts = this.cache[key];
            n = parts.length;
        } else {
            var opts = {
                fontSize: fontSize
            };
            parts = text.split("$");
            n = parts.length;
            for (i = 0; i < n; i += 2) {
                parts[i] = new textBox(ctx, parts[i]);
            }
            for (i = 1; i < n; i += 2) {
                try {
                    parts[i] = katex.canvasBox(parts[i], ctx, opts);
                } catch(e) {
                    console.error(e);
                    parts[i] = new textBox(ctx, "$" + parts[i] + "$");
                }
            }
            if (++this.misses === 1024) {
                this.misses = 0;
                this.cache = {};
            }
            this.cache[key] = parts;
        }
        var total = 0;
        for (i = 0; i < n; ++i)
            total += parts[i].width;
        x -= align * total;
        for (i = 0; i < n; ++i) {
            parts[i].renderAt(x, y);
            x += parts[i].width;
        }
    };
})();
<commit_msg>Use custom test strings for KaTeX fonts<commit_after>(function() {
    "use strict";

    var katex = null;
    var WebFontLoader = null;
    var fontsLoaded = false;
    var waitingInstances = [];

    createCindy.loadScript("WebFont", "webfont.js", loadFonts);
    createCindy.loadScript("katex", "katex/katex.min.js", katexReady);

    function loadFonts() {
        console.log("WebFontLoader is now available.");
        WebFontLoader = window.WebFont;
        WebFontLoader.load({
            custom: {
                families: [
                    "KaTeX_Main:n7,i4,n4",
                    "KaTeX_Math:i7,i4,n4",
                    "KaTeX_AMS:n4",
                    "KaTeX_Size1:n4",
                    "KaTeX_Size2:n4",
                    "KaTeX_Size3:n4",
                    "KaTeX_Size4:n4",
                ],
                testStrings: {
                  "KaTeX_Size1": "()[]",
                  "KaTeX_Size2": "()[]",
                  "KaTeX_Size3": "()[]",
                  "KaTeX_Size4": "()[]"
                },
                urls: [createCindy.getBaseDir() + "katex/katex.min.css"]
            },
            classes: false,
            active: fontsReady
        });
    }

    function fontsReady() {
        console.log("Math fonts are now available.");
        fontsLoaded = true;
        if (katex) doneWaiting();
    }

    function katexReady() {
        console.log("KaTeX is now available.");
        katex = window.katex;
        if (fontsLoaded) doneWaiting();
    }

    function doneWaiting() {
        var instances = waitingInstances;
        waitingInstances = null;
        for (var i = 0; i < instances.length; ++i)
            instances[i].evokeCS(""); // trigger repaint
    }

    createCindy.registerPlugin(1, "katex", plugin);

    function plugin(api) {
        if (waitingInstances)
            waitingInstances.push(api.instance);
        var storage = {cache: {}, misses:0};
        api.setTextRenderer(katexRenderer.bind(storage));
    }

    function textBox(ctx, text) {
        this.width = ctx.measureText(text).width;
        this.renderAt = function(x, y) {
            ctx.fillText(text, x, y);
        };
    }

    var firstMessage = true;

    function katexRenderer(ctx, text, x, y, align) {
        if (waitingInstances !== null) {
            if (firstMessage) {
                console.log("KaTeX is not ready yet.");
                firstMessage = false;
            }
            /*
            var width = ctx.measureText(text).width;
            ctx.fillText(text, x - align * width, y);
            */
            return;
        }
        var fontSize = /(?:^| )([0-9]+)px(?:$| )/.exec(ctx.font);
        fontSize = fontSize ? +fontSize[1] : 16;
        var key = fontSize + ":" + text;
        var parts, n, i;
        if (this.cache.hasOwnProperty(key)) {
            parts = this.cache[key];
            n = parts.length;
        } else {
            var opts = {
                fontSize: fontSize
            };
            parts = text.split("$");
            n = parts.length;
            for (i = 0; i < n; i += 2) {
                parts[i] = new textBox(ctx, parts[i]);
            }
            for (i = 1; i < n; i += 2) {
                try {
                    parts[i] = katex.canvasBox(parts[i], ctx, opts);
                } catch(e) {
                    console.error(e);
                    parts[i] = new textBox(ctx, "$" + parts[i] + "$");
                }
            }
            if (++this.misses === 1024) {
                this.misses = 0;
                this.cache = {};
            }
            this.cache[key] = parts;
        }
        var total = 0;
        for (i = 0; i < n; ++i)
            total += parts[i].width;
        x -= align * total;
        for (i = 0; i < n; ++i) {
            parts[i].renderAt(x, y);
            x += parts[i].width;
        }
    };
})();
<|endoftext|>


<commit_before>import React from 'react';
import Icon from 'atoms/Icon';
import Tooltip from 'atoms/Tooltip';

export default function renderTooltip(tooltip, className, iconClassName) {
  if (typeof tooltip === 'string') {
    return (
      <Tooltip
        className={className}
        right
        text={
          <Icon
            icon='tooltip'
            className={iconClassName}
          />
        }
      >
        {tooltip}
      </Tooltip>
    );
  }

  return (
    <Tooltip
      className={className}
      revealOnClick={tooltip.revealOnClick}
      right
      text={
        <Icon
          icon='tooltip'
          className={iconClassName}
        />
      }
    >
      { tooltip.children }
    </Tooltip>
  );
}
<commit_msg>Update formfields to accept tooltip render prop<commit_after>import React from 'react';
import Icon from 'atoms/Icon';
import Tooltip from 'atoms/Tooltip';

export default function renderTooltip(tooltip, className, iconClassName) {
  if (typeof tooltip === 'function') {
    return tooltip({
      tooltipPropGetter: (overrides = {}) => ({
        className,
        right: true,
        ...overrides
      }),
      icon: (
        <Icon
          icon='tooltip'
          className={iconClassName}
        />
      )
    });
  }

  if (typeof tooltip === 'string') {
    return (
      <Tooltip
        className={className}
        right
        text={
          <Icon
            icon='tooltip'
            className={iconClassName}
          />
        }
      >
        {tooltip}
      </Tooltip>
    );
  }

  return (
    <Tooltip
      className={className}
      revealOnClick={tooltip.revealOnClick}
      right
      text={
        <Icon
          icon='tooltip'
          className={iconClassName}
        />
      }
    >
      { tooltip.children }
    </Tooltip>
  );
}
<|endoftext|>


<commit_before>/*
Embedded SVG-edit API

General usage:
- Have an iframe somewhere pointing to a version of svg-edit > r1000
- Initialize the magic with:
var svgCanvas = new EmbeddedSVGEdit(window.frames['svgedit']);
- Pass functions in this format:
svgCanvas.setSvgString("string")
- Or if a callback is needed:
svgCanvas.setSvgString("string")(function(data, error){
  if(error){
    //there was an error
  }else{
    //handle data
  }
})

Everything is done with the same API as the real svg-edit,
and all documentation is unchanged.

This file depends on the postMessage API which can only
support JSON-serializable arguments and
return values, so, for example, arguments whose value is
"undefined", a function, a non-finite number, or a built-in
object like Date(), RegExp(), etc. will most likely not behave
as expected. In such a case one may need to host
the SVG editor on the same domain and reference the
JavaScript methods on the frame itself.

The only other difference is
when handling returns: the callback notation is used instead.

var blah = new EmbeddedSVGEdit(window.frames['svgedit']);
blah.clearSelection("woot","blah",1337,[1,2,3,4,5,"moo"],-42,{a: "tree",b:6, c: 9})(function(){console.log("GET DATA",arguments)})
*/

(function () {'use strict';

var cbid = 0;

function getCallbackSetter (d) {
  return function(){
    var t = this, // new callback
      args = [].slice.call(arguments),
      cbid = t.send(d, args, function(){});  // the callback (currently it's nothing, but will be set later)

    return function(newcallback){
      t.callbacks[cbid] = newcallback; // set callback
    };
  };
}

function EmbeddedSVGEdit(frame){
  if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without "new" keyword
    return new EmbeddedSVGEdit(frame);
  }
  // initialize communication
  this.frame = frame;
  this.callbacks = {}; // successor to stack
  //List of functions extracted with this:
  //Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html

  //for(var i=0,q=[],f = document.querySelectorAll("div.CFunction h3.CTitle a");i<f.length;i++){q.push(f[i].name)};q
  //var functions = ["clearSelection", "addToSelection", "removeFromSelection", "open", "save", "getSvgString", "setSvgString",
  //"createLayer", "deleteCurrentLayer", "setCurrentLayer", "renameCurrentLayer", "setCurrentLayerPosition", "setLayerVisibility",
  //"moveSelectedToLayer", "clear"];

  //Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API
  //var l=[];for(var i in svgCanvas){if(typeof svgCanvas[i] == "function"){l.push(i)}};
  //run in svgedit itself
  var i,
    t = this,
    functions = ["updateElementFromJson", "embedImage", "fixOperaXML", "clearSelection", "addToSelection",
		"removeFromSelection", "addNodeToSelection", "open", "save", "getSvgString", "setSvgString", "createLayer",
		"deleteCurrentLayer", "getCurrentDrawing", "setCurrentLayer", "renameCurrentLayer", "setCurrentLayerPosition",
		"setLayerVisibility", "moveSelectedToLayer", "clear", "clearPath", "getNodePoint", "clonePathNode", "deletePathNode",
		"getResolution", "getImageTitle", "setImageTitle", "setResolution", "setBBoxZoom", "setZoom", "getMode", "setMode",
		"getStrokeColor", "setStrokeColor", "getFillColor", "setFillColor", "setStrokePaint", "setFillPaint", "getStrokeWidth",
		"setStrokeWidth", "getStrokeStyle", "setStrokeStyle", "getOpacity", "setOpacity", "getFillOpacity", "setFillOpacity",
		"getStrokeOpacity", "setStrokeOpacity", "getTransformList", "getBBox", "getRotationAngle", "setRotationAngle", "each",
		"bind", "setIdPrefix", "getBold", "setBold", "getItalic", "setItalic", "getFontFamily", "setFontFamily", "getFontSize",
		"setFontSize", "getText", "setTextContent", "setImageURL", "setRectRadius", "setSegType", "quickClone",
		"changeSelectedAttributeNoUndo", "changeSelectedAttribute", "deleteSelectedElements", "groupSelectedElements", "zoomChanged",
		"ungroupSelectedElement", "moveToTopSelectedElement", "moveToBottomSelectedElement", "moveSelectedElements",
		"getStrokedBBox", "getVisibleElements", "cycleElement", "getUndoStackSize", "getRedoStackSize", "getNextUndoCommandText",
		"getNextRedoCommandText", "undo", "redo", "cloneSelectedElements", "alignSelectedElements", "getZoom", "getVersion",
		"setIconSize", "setLang", "setCustomHandlers"];

  // TODO: rewrite the following, it's pretty scary.
  for(i = 0; i < functions.length; i++){
    this[functions[i]] = getCallbackSetter(functions[i]);
  }

  // Older IE may need a polyfill for addEventListener, but so it would for SVG
  window.addEventListener('message', function(e){
    // We accept and post strings for the sake of IE9 support
    if (typeof e.data !== 'string') {
        return;
    }
    var result, cbid,
		data = e.data && JSON.parse(e.data);
    if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit') {
      return;
    }
    result = data.result || data.error;
    cbid = data.id;
    if(t.callbacks[cbid]){
      if(data.result){
       t.callbacks[cbid](result);
      }else{
        t.callbacks[cbid](result, "error");
      }
    }
  }, false);
}

EmbeddedSVGEdit.prototype.send = function(name, args, callback){
  var t = this;
  cbid++;

  this.callbacks[cbid] = callback;
  setTimeout(function(){ // delay for the callback to be set in case its synchronous
    // Todo: Handle non-JSON arguments and return values (undefined, nonfinite numbers, functions, and built-in objects like Date, RegExp), etc.?
    // We accept and post strings for the sake of IE9 support
    t.frame.contentWindow.postMessage(JSON.stringify({namespace: "svgCanvas", id: cbid, name: name, args: args}), '*');
  }, 0);
  return cbid;
};

window.embedded_svg_edit = EmbeddedSVGEdit; // Export old, deprecated API
window.EmbeddedSVGEdit = EmbeddedSVGEdit; // Follows common JS convention of CamelCase and, as enforced in JSLint, of initial caps for constructors

}());
<commit_msg>Clarify, JSLintify examples in comments<commit_after>/*
Embedded SVG-edit API

General usage:
- Have an iframe somewhere pointing to a version of svg-edit > r1000
- Initialize the magic with:
var svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
- Pass functions in this format:
svgCanvas.setSvgString("string")
- Or if a callback is needed:
svgCanvas.setSvgString("string")(function(data, error){
  if (error){
    // There was an error
  } else{
    // Handle data
  }
})

Everything is done with the same API as the real svg-edit,
and all documentation is unchanged.

However, this file depends on the postMessage API which
can only support JSON-serializable arguments and
return values, so, for example, arguments whose value is
"undefined", a function, a non-finite number, or a built-in
object like Date(), RegExp(), etc. will most likely not behave
as expected. In such a case one may need to host
the SVG editor on the same domain and reference the
JavaScript methods on the frame itself.

The only other difference is
when handling returns: the callback notation is used instead.

var blah = new EmbeddedSVGEdit(window.frames.svgedit);
blah.clearSelection("woot","blah",1337,[1,2,3,4,5,"moo"],-42,{a: "tree",b:6, c: 9})(function(){console.log("GET DATA",arguments)})
*/

(function () {'use strict';

var cbid = 0;

function getCallbackSetter (d) {
  return function(){
    var t = this, // new callback
      args = [].slice.call(arguments),
      cbid = t.send(d, args, function(){});  // the callback (currently it's nothing, but will be set later)

    return function(newcallback){
      t.callbacks[cbid] = newcallback; // set callback
    };
  };
}

function EmbeddedSVGEdit(frame){
  if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without "new" keyword
    return new EmbeddedSVGEdit(frame);
  }
  // initialize communication
  this.frame = frame;
  this.callbacks = {}; // successor to stack
  //List of functions extracted with this:
  //Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html

  //for(var i=0,q=[],f = document.querySelectorAll("div.CFunction h3.CTitle a");i<f.length;i++){q.push(f[i].name)};q
  //var functions = ["clearSelection", "addToSelection", "removeFromSelection", "open", "save", "getSvgString", "setSvgString",
  //"createLayer", "deleteCurrentLayer", "setCurrentLayer", "renameCurrentLayer", "setCurrentLayerPosition", "setLayerVisibility",
  //"moveSelectedToLayer", "clear"];

  //Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API
  //var l=[];for(var i in svgCanvas){if(typeof svgCanvas[i] == "function"){l.push(i)}};
  //run in svgedit itself
  var i,
    t = this,
    functions = ["updateElementFromJson", "embedImage", "fixOperaXML", "clearSelection", "addToSelection",
		"removeFromSelection", "addNodeToSelection", "open", "save", "getSvgString", "setSvgString", "createLayer",
		"deleteCurrentLayer", "getCurrentDrawing", "setCurrentLayer", "renameCurrentLayer", "setCurrentLayerPosition",
		"setLayerVisibility", "moveSelectedToLayer", "clear", "clearPath", "getNodePoint", "clonePathNode", "deletePathNode",
		"getResolution", "getImageTitle", "setImageTitle", "setResolution", "setBBoxZoom", "setZoom", "getMode", "setMode",
		"getStrokeColor", "setStrokeColor", "getFillColor", "setFillColor", "setStrokePaint", "setFillPaint", "getStrokeWidth",
		"setStrokeWidth", "getStrokeStyle", "setStrokeStyle", "getOpacity", "setOpacity", "getFillOpacity", "setFillOpacity",
		"getStrokeOpacity", "setStrokeOpacity", "getTransformList", "getBBox", "getRotationAngle", "setRotationAngle", "each",
		"bind", "setIdPrefix", "getBold", "setBold", "getItalic", "setItalic", "getFontFamily", "setFontFamily", "getFontSize",
		"setFontSize", "getText", "setTextContent", "setImageURL", "setRectRadius", "setSegType", "quickClone",
		"changeSelectedAttributeNoUndo", "changeSelectedAttribute", "deleteSelectedElements", "groupSelectedElements", "zoomChanged",
		"ungroupSelectedElement", "moveToTopSelectedElement", "moveToBottomSelectedElement", "moveSelectedElements",
		"getStrokedBBox", "getVisibleElements", "cycleElement", "getUndoStackSize", "getRedoStackSize", "getNextUndoCommandText",
		"getNextRedoCommandText", "undo", "redo", "cloneSelectedElements", "alignSelectedElements", "getZoom", "getVersion",
		"setIconSize", "setLang", "setCustomHandlers"];

  // TODO: rewrite the following, it's pretty scary.
  for(i = 0; i < functions.length; i++){
    this[functions[i]] = getCallbackSetter(functions[i]);
  }

  // Older IE may need a polyfill for addEventListener, but so it would for SVG
  window.addEventListener('message', function(e){
    // We accept and post strings for the sake of IE9 support
    if (typeof e.data !== 'string') {
        return;
    }
    var result, cbid,
		data = e.data && JSON.parse(e.data);
    if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit') {
      return;
    }
    result = data.result || data.error;
    cbid = data.id;
    if(t.callbacks[cbid]){
      if(data.result){
       t.callbacks[cbid](result);
      }else{
        t.callbacks[cbid](result, "error");
      }
    }
  }, false);
}

EmbeddedSVGEdit.prototype.send = function(name, args, callback){
  var t = this;
  cbid++;

  this.callbacks[cbid] = callback;
  setTimeout(function(){ // delay for the callback to be set in case its synchronous
    // Todo: Handle non-JSON arguments and return values (undefined, nonfinite numbers, functions, and built-in objects like Date, RegExp), etc.?
    // We accept and post strings for the sake of IE9 support
    t.frame.contentWindow.postMessage(JSON.stringify({namespace: "svgCanvas", id: cbid, name: name, args: args}), '*');
  }, 0);
  return cbid;
};

window.embedded_svg_edit = EmbeddedSVGEdit; // Export old, deprecated API
window.EmbeddedSVGEdit = EmbeddedSVGEdit; // Follows common JS convention of CamelCase and, as enforced in JSLint, of initial caps for constructors

}());
<|endoftext|>


<commit_before>//export const values = Object => {
    //console.log('fuck');
    if(!Object.values) Object.values = function(object) {
        return Object.keys(object).map(function(key) {
            return object[key];
        });
    };
//};
<commit_msg>clear code<commit_after>if(!Object.values) Object.values = function(object) {
    return Object.keys(object).map(function(key) {
        return object[key];
    });
};
<|endoftext|>


<commit_before>import Model from '../../model/Model';
import ComputationChild from '../../model/ComputationChild';
import { handleChange, unbind } from '../../shared/methodCallers';
import getFunction from '../../shared/getFunction';
import resolveReference from './resolveReference';
import { removeFromArray } from '../../utils/array';

function getValue ( model ) {
	return model ? model.get( true, true ) : undefined;
}

function createResolver ( proxy, ref, index ) {
	const resolver = proxy.fragment.resolve( ref, model => {
		removeFromArray( proxy.resolvers, resolver );
		proxy.models[ index ] = model;
		proxy.bubble();
	});

	proxy.resolvers.push( resolver );
}

export default class ExpressionProxy extends Model {
	constructor ( fragment, template ) {
		super( fragment.ractive.viewmodel, null );

		this.fragment = fragment;
		this.template = template;

		this.isReadonly = true;

		this.fn = getFunction( template.s, template.r.length );
		this.computation = null;

		this.resolvers = [];
		this.models = this.template.r.map( ( ref, index ) => {
			const model = resolveReference( this.fragment, ref );

			if ( !model ) {
				createResolver( this, ref, index );
			}

			return model;
		});

		this.bubble();
	}

	bubble () {
		const ractive = this.fragment.ractive;

		// TODO the @ prevents computed props from shadowing keypaths, but the real
		// question is why it's a computed prop in the first place... (hint, it's
		// to do with {{else}} blocks)
		const key = '@' + this.template.s.replace( /_(\d+)/g, ( match, i ) => {
			if ( i >= this.models.length ) return match;

			const model = this.models[i];
			return model ? model.getKeypath() : '@undefined';
		});

		// TODO can/should we reuse computations?
		const signature = {
			getter: () => {
				const values = this.models.map( getValue );
				return this.fn.apply( ractive, values );
			},
			getterString: key
		};

		const computation = ractive.viewmodel.compute( key, signature );

		this.value = computation.get(); // TODO should not need this, eventually

		if ( this.computation ) {
			this.computation.unregister( this );
			// notify children...
		}

		this.computation = computation;
		computation.register( this );

		this.handleChange();
	}

	get ( shouldCapture ) {
		return this.computation.get( shouldCapture );
	}

	getKeypath () {
		return this.computation ? this.computation.getKeypath() : '@undefined';
	}

	handleChange () {
		this.deps.forEach( handleChange );
		this.children.forEach( handleChange );

		this.clearUnresolveds();
	}

	joinKey ( key ) {
		if ( key === undefined || key === '' ) return this;

		if ( !this.childByKey.hasOwnProperty( key ) ) {
			const child = new ComputationChild( this, key );
			this.children.push( child );
			this.childByKey[ key ] = child;
		}

		return this.childByKey[ key ];
	}

	mark () {
		this.handleChange();
	}

	retrieve () {
		return this.get();
	}

	teardown () {
		this.unbind();
		this.fragment = undefined;
		if ( this.computation ) {
			this.computation.teardown();
		}
		this.computation = undefined;
		super.teardown();
	}

	tryRebind () {
		let dirty = false;
		const unresolved = [];

		this.models.forEach( ( m, i ) => {
			if ( m ) {
				let next = m.tryRebind();
				if ( next === false ) return;
				if ( next ) {
					this.models.splice( i, 1, next );
				} else {
					dirty = true;
				}
			} else {
				unresolved.push( i );
			}
		});

		// update resolvers
		this.resolvers.forEach( unbind );
		unresolved.forEach( idx => {
			createResolver( this, this.template.r[ idx ], idx );
		});

		if ( dirty ) {
			return;
		}

		this.bubble();

		return this;
	}

	unregister( dep ) {
		super.unregister( dep );
		if ( !this.deps.length ) this.teardown();
	}

	unbind () {
		this.resolvers.forEach( unbind );
	}
}
<commit_msg>reset resolvers array during expression rebind<commit_after>import Model from '../../model/Model';
import ComputationChild from '../../model/ComputationChild';
import { handleChange, unbind } from '../../shared/methodCallers';
import getFunction from '../../shared/getFunction';
import resolveReference from './resolveReference';
import { removeFromArray } from '../../utils/array';

function getValue ( model ) {
	return model ? model.get( true, true ) : undefined;
}

function createResolver ( proxy, ref, index ) {
	const resolver = proxy.fragment.resolve( ref, model => {
		removeFromArray( proxy.resolvers, resolver );
		proxy.models[ index ] = model;
		proxy.bubble();
	});

	proxy.resolvers.push( resolver );
}

export default class ExpressionProxy extends Model {
	constructor ( fragment, template ) {
		super( fragment.ractive.viewmodel, null );

		this.fragment = fragment;
		this.template = template;

		this.isReadonly = true;

		this.fn = getFunction( template.s, template.r.length );
		this.computation = null;

		this.resolvers = [];
		this.models = this.template.r.map( ( ref, index ) => {
			const model = resolveReference( this.fragment, ref );

			if ( !model ) {
				createResolver( this, ref, index );
			}

			return model;
		});

		this.bubble();
	}

	bubble () {
		const ractive = this.fragment.ractive;

		// TODO the @ prevents computed props from shadowing keypaths, but the real
		// question is why it's a computed prop in the first place... (hint, it's
		// to do with {{else}} blocks)
		const key = '@' + this.template.s.replace( /_(\d+)/g, ( match, i ) => {
			if ( i >= this.models.length ) return match;

			const model = this.models[i];
			return model ? model.getKeypath() : '@undefined';
		});

		// TODO can/should we reuse computations?
		const signature = {
			getter: () => {
				const values = this.models.map( getValue );
				return this.fn.apply( ractive, values );
			},
			getterString: key
		};

		const computation = ractive.viewmodel.compute( key, signature );

		this.value = computation.get(); // TODO should not need this, eventually

		if ( this.computation ) {
			this.computation.unregister( this );
			// notify children...
		}

		this.computation = computation;
		computation.register( this );

		this.handleChange();
	}

	get ( shouldCapture ) {
		return this.computation.get( shouldCapture );
	}

	getKeypath () {
		return this.computation ? this.computation.getKeypath() : '@undefined';
	}

	handleChange () {
		this.deps.forEach( handleChange );
		this.children.forEach( handleChange );

		this.clearUnresolveds();
	}

	joinKey ( key ) {
		if ( key === undefined || key === '' ) return this;

		if ( !this.childByKey.hasOwnProperty( key ) ) {
			const child = new ComputationChild( this, key );
			this.children.push( child );
			this.childByKey[ key ] = child;
		}

		return this.childByKey[ key ];
	}

	mark () {
		this.handleChange();
	}

	retrieve () {
		return this.get();
	}

	teardown () {
		this.unbind();
		this.fragment = undefined;
		if ( this.computation ) {
			this.computation.teardown();
		}
		this.computation = undefined;
		super.teardown();
	}

	tryRebind () {
		let dirty = false;
		const unresolved = [];

		this.models.forEach( ( m, i ) => {
			if ( m ) {
				let next = m.tryRebind();
				if ( next === false ) return;
				if ( next ) {
					this.models.splice( i, 1, next );
				} else {
					dirty = true;
				}
			} else {
				unresolved.push( i );
			}
		});

		// update resolvers
		this.resolvers.forEach( unbind );
		this.resolvers.length = 0;
		unresolved.forEach( idx => {
			createResolver( this, this.template.r[ idx ], idx );
		});

		if ( dirty ) {
			return;
		}

		this.bubble();

		return this;
	}

	unregister( dep ) {
		super.unregister( dep );
		if ( !this.deps.length ) this.teardown();
	}

	unbind () {
		this.resolvers.forEach( unbind );
	}
}
<|endoftext|>


<commit_before>/**
 * # manager/stylesheet
 *
 * Methods for setting the canvas stylesheet type and making the stylesheets
 *
 * > http://draeton.github.io/stitches

 * > Copyright 2013 Matthew Cobbs

 * > Licensed under the MIT license.
 */

define([
    "wrap/jquery",
    "stylesheet/css",
    "stylesheet/less"
],
function ($, CssStylesheet, LessStylesheet) {

    "use strict";

    // **Canvas stylesheet managers**
    var managers = {
        css: CssStylesheet,
        less: LessStylesheet
    };

    // **Module definition**
    return {
        /**
         * ### @set
         * Set the working stylesheet manager instance by type
         *
         * @param {string} type The stylesheet manager type
         */
        set: function (type) {
            var Manager;

            this.type = type || "css";
            Manager = managers[this.type];
            this.manager = new Manager();
        },

        /**
         * ### @getStylesheet
         * Returns a stylesheet to place images with spritesheet
         *
         * @param {array} options.sprites A list of sprites
         * @param {string} options.spritesheet The data URL of the spritesheet
         * @param {string} options.prefix Used to create CSS classes
         * @param {boolean} options.uri Switch including image as data URI
         * @return string
         */
        getStylesheet: function (options) {
            var sprites = options.sprites;
            var spritesheet = options.spritesheet;
            var prefix = options.prefix;
            var uri = options.uri;
            var dimensions = options.dimensions || {width: 400, height: 400};
            console.log('DIMENSIONS!!!', dimensions, 100*dimensions.width/(sprites || [{width: 30, height: 30}])[0].image.width)

            var styles = this.manager.get(sprites, spritesheet, prefix, uri, dimensions);
            styles = styles.replace(/\\n/g, "\n");

            return styles;
        },

        /**
         * ### @getMarkup
         * Returns markup for spritesheet example usage
         *
         * @param {array} options.sprites A list of sprites
         * @param {string} options.prefix Used to create CSS classes
         * @return string
         */
        getMarkup: function (options) {
            var sprites = options.sprites;
            var prefix = options.prefix;
            var tooltip = options.tooltip || false;

            var markup = this.manager.markup(sprites, prefix, tooltip);
            markup = markup.replace(/\\n/g, "\n");

            return markup;
        }
    };

});<commit_msg>Removed console log that was breaking stuff...<commit_after>/**
 * # manager/stylesheet
 *
 * Methods for setting the canvas stylesheet type and making the stylesheets
 *
 * > http://draeton.github.io/stitches

 * > Copyright 2013 Matthew Cobbs

 * > Licensed under the MIT license.
 */

define([
    "wrap/jquery",
    "stylesheet/css",
    "stylesheet/less"
],
function ($, CssStylesheet, LessStylesheet) {

    "use strict";

    // **Canvas stylesheet managers**
    var managers = {
        css: CssStylesheet,
        less: LessStylesheet
    };

    // **Module definition**
    return {
        /**
         * ### @set
         * Set the working stylesheet manager instance by type
         *
         * @param {string} type The stylesheet manager type
         */
        set: function (type) {
            var Manager;

            this.type = type || "css";
            Manager = managers[this.type];
            this.manager = new Manager();
        },

        /**
         * ### @getStylesheet
         * Returns a stylesheet to place images with spritesheet
         *
         * @param {array} options.sprites A list of sprites
         * @param {string} options.spritesheet The data URL of the spritesheet
         * @param {string} options.prefix Used to create CSS classes
         * @param {boolean} options.uri Switch including image as data URI
         * @return string
         */
        getStylesheet: function (options) {
            var sprites = options.sprites;
            var spritesheet = options.spritesheet;
            var prefix = options.prefix;
            var uri = options.uri;
            var dimensions = options.dimensions || {width: 400, height: 400};

            var styles = this.manager.get(sprites, spritesheet, prefix, uri, dimensions);
            styles = styles.replace(/\\n/g, "\n");

            return styles;
        },

        /**
         * ### @getMarkup
         * Returns markup for spritesheet example usage
         *
         * @param {array} options.sprites A list of sprites
         * @param {string} options.prefix Used to create CSS classes
         * @return string
         */
        getMarkup: function (options) {
            var sprites = options.sprites;
            var prefix = options.prefix;
            var tooltip = options.tooltip || false;

            var markup = this.manager.markup(sprites, prefix, tooltip);
            markup = markup.replace(/\\n/g, "\n");

            return markup;
        }
    };

});
<|endoftext|>


<commit_before>"use strict";

let commonContentSchema = {
	"type": "object",
	"required": false,
	"additionalProperties": false,
	"properties": {
		"data": {
			"type": "array",
			"items": {
				"type": "object",
				"required": true
			},
			"minItems": 1,
			"uniqueItems": true
		}
	}
};

module.exports = {
	"type": "object",
	"required": true,
	"properties": {
		"name": {"type": "string", "required": true},
		"description": {"type": "string", "required": true},
		"link": {"type": "string", "required": false, "format": "uri"},
		"content": {
			"type": "object",
			"required": false,
			"additionalProperties": false,
			"properties":{
				"recipes": {
					"type": "object",
					"required": false,
					"additionalProperties": false,
					"properties":{
						"ci": {
							"type": "array",
							"required": false,
							"items": {
								"type": "object",
								"required": true
							},
							"minItems": 1,
							"uniqueItems": true
						},
						"deployment": {
							"type": "array",
							"required": false,
							"items": {
								"type": "object",
								"required": true
							},
							"minItems": 1,
							"uniqueItems": true
						}
					}
				},
				"endpoints": commonContentSchema,
				"custom_registry": commonContentSchema,
				"productization": commonContentSchema,
				"tenant": commonContentSchema,
				"secrets": commonContentSchema,
				"deployments": {
					"type": "object",
					"required": false,
					"additionalProperties": false,
					"properties": {
						"repo": {
							"type": "object",
							"required": false,
							"additionalProperties":{
								"type": "object",
								"required": true
							}
						},
						"resources": {
							"type": "object",
							"required": false,
							"additionalProperties":{
								"type": "object",
								"required": true
							}
						}
					}
				}
			}
		},
		"deploy": {
			"type": "object",
			"required": false,
			"additionalProperties": false,
			"properties": {
				"database": {
					"type": "object",
					"required": false
				},
				"deployment": {
					"type": "object",
					"required": false
				}
			}
		},
	}
};<commit_msg>update validation schema deploy section<commit_after>"use strict";

let commonContentSchema = {
	"type": "object",
	"required": false,
	"additionalProperties": false,
	"properties": {
		"data": {
			"type": "array",
			"items": {
				"type": "object",
				"required": true
			},
			"minItems": 1,
			"uniqueItems": true
		}
	}
};

let commonDeploySchema = {
	"type": "object",
	"required": false,
	"additionalProperties": false,
	"properties":{
		"pre": {
			"type": "object",
			"additionalProperties":{
				"type": "object",
				"required": true
			}
		},
		"steps": {
			"type": "object",
			"additionalProperties":{
				"type": "object",
				"required": true
			}
		},
		"post": {
			"type": "object",
			"additionalProperties":{
				"type": "object",
				"required": true
			}
		},
	}
};

module.exports = {
	"type": "object",
	"required": true,
	"properties": {
		"name": {"type": "string", "required": true},
		"description": {"type": "string", "required": true},
		"link": {"type": "string", "required": false, "format": "uri"},
		"content": {
			"type": "object",
			"required": false,
			"additionalProperties": false,
			"properties":{
				"recipes": {
					"type": "object",
					"required": false,
					"additionalProperties": false,
					"properties":{
						"ci": {
							"type": "array",
							"required": false,
							"items": {
								"type": "object",
								"required": true
							},
							"minItems": 1,
							"uniqueItems": true
						},
						"deployment": {
							"type": "array",
							"required": false,
							"items": {
								"type": "object",
								"required": true
							},
							"minItems": 1,
							"uniqueItems": true
						}
					}
				},
				"endpoints": commonContentSchema,
				"custom_registry": commonContentSchema,
				"productization": commonContentSchema,
				"tenant": commonContentSchema,
				"secrets": commonContentSchema,
				"deployments": {
					"type": "object",
					"required": false,
					"additionalProperties": false,
					"properties": {
						"repo": {
							"type": "object",
							"required": false,
							"additionalProperties":{
								"type": "object",
								"required": true
							}
						},
						"resources": {
							"type": "object",
							"required": false,
							"additionalProperties":{
								"type": "object",
								"required": true
							}
						}
					}
				}
			}
		},
		"deploy": {
			"type": "object",
			"required": false,
			"additionalProperties": false,
			"properties": {
				"database": commonDeploySchema,
				"deployments": commonDeploySchema
			}
		},
	}
};<|endoftext|>


<commit_before>'use strict';

module.exports = function (options, foundEntries) {
  return function (tree) {
    var matchers = [];

    if (options.images) {
      matchers.push({
        tag: 'img',
        attrs: {
          src: true
        }
      });
    }

    if (options.scripts) {
      matchers.push({
        tag: 'script',
        attrs: {
          src: true
        }
      });
    }

    if (options.styles) {
      matchers.push({
        tag: 'link',
        attrs: {
          rel: 'stylesheet'
        }
      });
    }

    if (matchers) {
      tree.match(matchers, function (node) {
        switch (node.tag) {
          case 'img':
            foundEntries.push([node.attrs.src, 'image']);
            break;
          case 'script':
            foundEntries.push([node.attrs.src, 'script']);
            break;
          case 'link':
            foundEntries.push([node.attrs.href, 'style']);
            break;
          // no default
        }
        return node;
      });
    }

    return foundEntries;
  };
};
<commit_msg>fix(matchers): skip traversal when all matches are disabled<commit_after>'use strict';

module.exports = function (options, foundEntries) {
  return function (tree) {
    var matchers = [];

    if (options.images) {
      matchers.push({
        tag: 'img',
        attrs: {
          src: true
        }
      });
    }

    if (options.scripts) {
      matchers.push({
        tag: 'script',
        attrs: {
          src: true
        }
      });
    }

    if (options.styles) {
      matchers.push({
        tag: 'link',
        attrs: {
          rel: 'stylesheet'
        }
      });
    }

    if (matchers.length) {
      tree.match(matchers, function (node) {
        switch (node.tag) {
          case 'img':
            foundEntries.push([node.attrs.src, 'image']);
            break;
          case 'script':
            foundEntries.push([node.attrs.src, 'script']);
            break;
          case 'link':
            foundEntries.push([node.attrs.href, 'style']);
            break;
          // no default
        }
        return node;
      });
    }

    return foundEntries;
  };
};
<|endoftext|>