<commit_before>+function() {
Pusher.log = function(message) {
    if (window.console && window.console.log) {
        window.console.log(message);
    }
};

function make_pusher(room) {
    var pusher = new Pusher(PUSHER_KEY());
    var channel = pusher.subscribe("room_" + room);

    return channel
}

function make_message(name, text) {
    return E_("tr", {},
              E_("td", {},
                 E_("span", {style: "font-weight:bold"}, name, "> "),
                 E_("span", {}, text)))
}

function message_adder(container) {
    var last_table

    return function(ent) {
        if (! last_table) {
            var tbl = E_("table", {class: "table"})(document)
            var panel = E_("div", {class: "row"},
                           E_("div", {class: "col-md-12"},
                              E_("div", {class: "panel panel-default"},
                                 tbl
                                )))
            $(container).append(panel(document))
            last_table = tbl
        }
        $(last_table).append(make_message(ent.name, ent.text)(document))
    }
}

function match_and_append_message(msg, add_message) {
    // console.log(msg)
    var M = xmlmatch.M
    var C = xmlmatch.C

    var sp = function(x) {return x.nodeType == 3 && x.textContent.match(/\s*/)}

    var last_index = -1

    var m = M("xxx",
              C(M("entries",
                  C(sp,
                    M("entry",
                      function(node) {
                          var ent = {}
                          var index = node.getAttribute("index")
                          // console.log("index", index)
                          if (index != null && +index > last_index) {
                              last_index = +index
                              var res = C(sp,
                                          M("user-id", function(x){
                                              ent.user_id = x.textContent
                                              return true}),
                                          M("thread-id", function(x){
                                              ent.thread_id = x.textContent
                                              return true}),
                                          M("content",
                                            C(sp,
                                              M("screen-name", function(x){
                                                  ent.name = x.textContent
                                                  return true
                                              }),
                                              M("text", function(x){
                                                  ent.text = x.textContent
                                                  return true
                                              })))
                                         )(node)
                              add_message(ent)
                              return res
                          } else {
                              // console.log("end", node, index, last_index)
                              return false
                          }
                      }),
                    M("error", function(x){console.log(x); return true})
                   ))))
    var e = document.createElement("xxx")
    e.innerHTML = msg
    // console.log(e)
    var result
    try {
        result = m(e)
    } catch(ex) {
        console.error(ex)
    }
    // console.log(result)
    // console.log(last_index)

    return last_index
}

function navbar(room) {
    return E_("nav", {class: "navbar navbar-default navbar-fixed-top",
                      role: "navigation"},
              E_("div", {class: "navbar-header"},
                 E_("button", {type: "button", class: "navbar-toggle",
                               "data-toggle": "collapse",
                               "data-target": ".navbar-ex1-collapse"},
                    E_("span", {class: "sr-only"}, "Toggle navigation"),
                    E_("span", {class: "icon-bar"}, ""),
                    E_("span", {class: "icon-bar"}, ""),
                    E_("span", {class: "icon-bar"}, "")),
                 E_("a", {class: "navbar-brand", href: "#"}, room)
                ))
}

var ChatBoard = function(params) {
    var self = this

    self.interval = 1000
    self.timeout_id
    self.room = params.room
    self.user_key = params.user_key
    self.container

    self.make_container()

    self.add_message = message_adder(self.container)

    self.last_index = 0
    console.log("pull 1", self)
    $.get("/1/pull", {room: self.room},
          function(msg) {
              self.last_index = match_and_append_message(msg, self.add_message)
              setTimeout(function() {
                  var body = $(document.body)
                  var scrollto = Math.max(0, body.height() - $(window).height())
                  body.animate({scrollTop: scrollto}, function() {
                      console.log("scroll complete")
                  })
              }, 10)
          })

    self.timeout_id = setTimeout(self.reload.bind(self), self.interval)

    var pusher_channel = make_pusher(self.room)
    pusher_channel.bind('update', function(data) {
        if (data.index > self.last_index) {
            if (self.timeout_id) clearTimeout(self.timeout_id)
            self.timeout_id = null
            self.reload()
            // console.log(data);
        }
    });
}

ChatBoard.prototype.message_form = function(onsubmit) {
    var self = this

    return E_("div", {class: "row"},
              E_("div", {class: "col-md-12"},
                 function(doc) {
                     var textarea
                     var name_input
                     var e = E_("form", {role: "form"},
                                E_("div", {class: "form-group"},
                                   E_("label", {for: "name_textinput"},
                                      "Your Name"),
                                   function(doc) {
                                       var name = $.cookie("screen_name") || ""
                                       var e = E_("input",
                                                  {class: "form-control",
                                                   type: "text",
                                                   id: "name_textinput",
                                                   value: name}, "")
                                       var ele = e(doc)
                                       name_input = ele
                                       return ele
                                   }),
                                E_("div", {class: "form-group"},
                                   E_("label", {for: "message_body_textarea"},
                                      "Message"),
                                   function(doc) {
                                       var e = E_("textarea",
                                                  {class: "form-control",
                                                   id: "message_body_textarea",
                                                   rows: 2}, "")
                                       var ele = e(doc)
                                       textarea = ele
                                       return ele
                                   }),
                                E_("button", {type: "submit", class: "btn btn-primary"},
                                   "Submit"))
                     var ele = e(doc)

                     ele.onsubmit = function() {
                         if (textarea.value.match(/^\s*$/)) {
                             return false
                         }
                         if (name_input.value.match(/^\s*$/)) {
                             return false
                         }

                         $.cookie("screen_name", name_input.value, {expires: 365})

                         console.log("submit!", textarea.value)
                         var text = textarea.value
                         var screen_name = name_input.value
                         textarea.value = ""
                         var content_xml = E_("xxx", {},
                                              E_("content", {},
                                                 E_("screen-name", {}, screen_name),
                                                 E_("text", {}, text)))(doc).innerHTML
                         console.log(content_xml)
                         $.post("/1/push", {
                             room: self.room,
                             "user-key": self.user_key,
                             "thread-id": 0,
                             content: content_xml,
                         }, console.log.bind(console))

                         onsubmit()
                         return false
                     }

                     return ele
                 }))
}

ChatBoard.prototype.make_container = function() {
    var self = this

    var e = E_("div",
               {class: "container", style: "padding-top: 70px; padding-bottom: 20px"},
               function(doc) {
                   var e = E_("div", {id: "messages"})(doc)
                   self.container = e
                   return e
               },
               self.message_form(function() {
                   if (self.timeout_id) clearTimeout(self.timeout_id)
                   self.timeout_id = null
                   self.reload()
               }))

    $(document.body)
        .append(navbar(self.room)(document))
        .append(e(document))
}

ChatBoard.prototype.reload = function() {
    var self = this
    var badge = 0
    var title = document.title = self.room + " - chat"

    if (self.reloading) return
    self.reloading = true

    console.log("pull 2", self)
    $.get("/1/pull", {room: self.room, after: self.last_index},
          function(msg) {
              var idx = match_and_append_message(msg, self.add_message)
              if (idx > self.last_index) {
                  if (! document.hasFocus()) {
                      badge += (idx - self.last_index)
                      document.title = "[" + badge + "]" + title
                      $(window).focus(function() {
                          document.title = title
                          badge = 0
                      })
                  }

                  self.last_index = idx
                  self.interval = 1000

                  var body = $(document.body)
                  if (body.height() - (body.scrollTop() + $(window).height()) < 70) {
                      body.scrollTop(body.height() - $(window).height())
                  }

              } else {
                  // double the interval (up to 1 minite) if no message received
                  self.interval = Math.min(self.interval * 2, 60 * 1000)
              }
              self.timeout_id = setTimeout(self.reload.bind(self), self.interval)
              // console.log("self.interval", self.interval)

              self.reloading = false
          })
        .fail(function() {
            if (self.timeout_id) clearTimeout(self.timeout_id)
            self.timeout_id = null
            console.log("Failed")
            self.reloading = false
        })
}

$(document).ready(function(){
    var user_key = $.cookie("user-key")

    if (user_key) {
        new ChatBoard({room: "elepaio", user_key: user_key})
    } else {
        $.post("/1/register")
            .success(function(msg) {
                // user_key = $.cookie("user-key")

                var M = xmlmatch.M
                var C = xmlmatch.C
                var m = M("xxx",
                         C(M("user",
                             function(e) {
                                 var user_id = e.getAttribute("id")
                                 user_key = e.getAttribute("key")
                                 console.log("user ID", user_id)
                                 return user_id && user_key
                             })))

                var e = document.createElement("xxx")
                e.innerHTML = msg
                // console.log(e)
                var result
                var exc
                try {
                    result = m(e)
                } catch(e) {
                    exc = e
                }

                if (result) {
                    console.log("user-key", user_key)
                    new ChatBoard({room: "elepaio", user_key: user_key})
                } else {
                    console.error("failed to get a user key", exc)
                }
            })
    }
})

}()
<commit_msg>handles linebreaks<commit_after>+function() {
Pusher.log = function(message) {
    if (window.console && window.console.log) {
        window.console.log(message);
    }
};

function make_pusher(room) {
    var pusher = new Pusher(PUSHER_KEY());
    var channel = pusher.subscribe("room_" + room);

    return channel
}

function make_message(name, text) {
    var lines = text.split(/\n/)
    return E_("tr", {},
              E_("td", {},
                 E_("span", {style: "font-weight:bold"}, name, "> "),
                 E_("span", {}, lines.slice(1).reduce(function(part, cur) {
                     return part.concat([E_("br"), cur])
                 }, [lines[0]]))))
}

function message_adder(container) {
    var last_table

    return function(ent) {
        if (! last_table) {
            var tbl = E_("table", {class: "table"})(document)
            var panel = E_("div", {class: "row"},
                           E_("div", {class: "col-md-12"},
                              E_("div", {class: "panel panel-default"},
                                 tbl
                                )))
            $(container).append(panel(document))
            last_table = tbl
        }
        $(last_table).append(make_message(ent.name, ent.text)(document))
    }
}

function match_and_append_message(msg, add_message) {
    // console.log(msg)
    var M = xmlmatch.M
    var C = xmlmatch.C

    var sp = function(x) {return x.nodeType == 3 && x.textContent.match(/\s*/)}

    var last_index = -1

    var m = M("xxx",
              C(M("entries",
                  C(sp,
                    M("entry",
                      function(node) {
                          var ent = {}
                          var index = node.getAttribute("index")
                          // console.log("index", index)
                          if (index != null && +index > last_index) {
                              last_index = +index
                              var res = C(sp,
                                          M("user-id", function(x){
                                              ent.user_id = x.textContent
                                              return true}),
                                          M("thread-id", function(x){
                                              ent.thread_id = x.textContent
                                              return true}),
                                          M("content",
                                            C(sp,
                                              M("screen-name", function(x){
                                                  ent.name = x.textContent
                                                  return true
                                              }),
                                              M("text", function(x){
                                                  ent.text = x.textContent
                                                  return true
                                              })))
                                         )(node)
                              add_message(ent)
                              return res
                          } else {
                              // console.log("end", node, index, last_index)
                              return false
                          }
                      }),
                    M("error", function(x){console.log(x); return true})
                   ))))
    var e = document.createElement("xxx")
    e.innerHTML = msg
    // console.log(e)
    var result
    try {
        result = m(e)
    } catch(ex) {
        console.error(ex)
    }
    // console.log(result)
    // console.log(last_index)

    return last_index
}

function navbar(room) {
    return E_("nav", {class: "navbar navbar-default navbar-fixed-top",
                      role: "navigation"},
              E_("div", {class: "navbar-header"},
                 E_("button", {type: "button", class: "navbar-toggle",
                               "data-toggle": "collapse",
                               "data-target": ".navbar-ex1-collapse"},
                    E_("span", {class: "sr-only"}, "Toggle navigation"),
                    E_("span", {class: "icon-bar"}, ""),
                    E_("span", {class: "icon-bar"}, ""),
                    E_("span", {class: "icon-bar"}, "")),
                 E_("a", {class: "navbar-brand", href: "#"}, room)
                ))
}

var ChatBoard = function(params) {
    var self = this

    self.interval = 1000
    self.timeout_id
    self.room = params.room
    self.user_key = params.user_key
    self.container

    self.make_container()

    self.add_message = message_adder(self.container)

    self.last_index = 0
    console.log("pull 1", self)
    $.get("/1/pull", {room: self.room},
          function(msg) {
              self.last_index = match_and_append_message(msg, self.add_message)
              setTimeout(function() {
                  var body = $(document.body)
                  var scrollto = Math.max(0, body.height() - $(window).height())
                  body.animate({scrollTop: scrollto}, function() {
                      console.log("scroll complete")
                  })
              }, 10)
          })

    self.timeout_id = setTimeout(self.reload.bind(self), self.interval)

    var pusher_channel = make_pusher(self.room)
    pusher_channel.bind('update', function(data) {
        if (data.index > self.last_index) {
            if (self.timeout_id) clearTimeout(self.timeout_id)
            self.timeout_id = null
            self.reload()
            // console.log(data);
        }
    });
}

ChatBoard.prototype.message_form = function(onsubmit) {
    var self = this

    return E_("div", {class: "row"},
              E_("div", {class: "col-md-12"},
                 function(doc) {
                     var textarea
                     var name_input
                     var e = E_("form", {role: "form"},
                                E_("div", {class: "form-group"},
                                   E_("label", {for: "name_textinput"},
                                      "Your Name"),
                                   function(doc) {
                                       var name = $.cookie("screen_name") || ""
                                       var e = E_("input",
                                                  {class: "form-control",
                                                   type: "text",
                                                   id: "name_textinput",
                                                   value: name}, "")
                                       var ele = e(doc)
                                       name_input = ele
                                       return ele
                                   }),
                                E_("div", {class: "form-group"},
                                   E_("label", {for: "message_body_textarea"},
                                      "Message"),
                                   function(doc) {
                                       var e = E_("textarea",
                                                  {class: "form-control",
                                                   id: "message_body_textarea",
                                                   rows: 2}, "")
                                       var ele = e(doc)
                                       textarea = ele
                                       return ele
                                   }),
                                E_("button", {type: "submit", class: "btn btn-primary"},
                                   "Submit"))
                     var ele = e(doc)

                     ele.onsubmit = function() {
                         if (textarea.value.match(/^\s*$/)) {
                             return false
                         }
                         if (name_input.value.match(/^\s*$/)) {
                             return false
                         }

                         $.cookie("screen_name", name_input.value, {expires: 365})

                         console.log("submit!", textarea.value)
                         var text = textarea.value
                         var screen_name = name_input.value
                         textarea.value = ""
                         var content_xml = E_("xxx", {},
                                              E_("content", {},
                                                 E_("screen-name", {}, screen_name),
                                                 E_("text", {}, text)))(doc).innerHTML
                         console.log(content_xml)
                         $.post("/1/push", {
                             room: self.room,
                             "user-key": self.user_key,
                             "thread-id": 0,
                             content: content_xml,
                         }, console.log.bind(console))

                         onsubmit()
                         return false
                     }

                     return ele
                 }))
}

ChatBoard.prototype.make_container = function() {
    var self = this

    var e = E_("div",
               {class: "container", style: "padding-top: 70px; padding-bottom: 20px"},
               function(doc) {
                   var e = E_("div", {id: "messages"})(doc)
                   self.container = e
                   return e
               },
               self.message_form(function() {
                   if (self.timeout_id) clearTimeout(self.timeout_id)
                   self.timeout_id = null
                   self.reload()
               }))

    $(document.body)
        .append(navbar(self.room)(document))
        .append(e(document))
}

ChatBoard.prototype.reload = function() {
    var self = this
    var badge = 0
    var title = document.title = self.room + " - chat"

    if (self.reloading) return
    self.reloading = true

    console.log("pull 2", self)
    $.get("/1/pull", {room: self.room, after: self.last_index},
          function(msg) {
              var idx = match_and_append_message(msg, self.add_message)
              if (idx > self.last_index) {
                  if (! document.hasFocus()) {
                      badge += (idx - self.last_index)
                      document.title = "[" + badge + "]" + title
                      $(window).focus(function() {
                          document.title = title
                          badge = 0
                      })
                  }

                  self.last_index = idx
                  self.interval = 1000

                  var body = $(document.body)
                  if (body.height() - (body.scrollTop() + $(window).height()) < 70) {
                      body.scrollTop(body.height() - $(window).height())
                  }

              } else {
                  // double the interval (up to 1 minite) if no message received
                  self.interval = Math.min(self.interval * 2, 60 * 1000)
              }
              self.timeout_id = setTimeout(self.reload.bind(self), self.interval)
              // console.log("self.interval", self.interval)

              self.reloading = false
          })
        .fail(function() {
            if (self.timeout_id) clearTimeout(self.timeout_id)
            self.timeout_id = null
            console.log("Failed")
            self.reloading = false
        })
}

$(document).ready(function(){
    var user_key = $.cookie("user-key")

    if (user_key) {
        new ChatBoard({room: "elepaio", user_key: user_key})
    } else {
        $.post("/1/register")
            .success(function(msg) {
                // user_key = $.cookie("user-key")

                var M = xmlmatch.M
                var C = xmlmatch.C
                var m = M("xxx",
                         C(M("user",
                             function(e) {
                                 var user_id = e.getAttribute("id")
                                 user_key = e.getAttribute("key")
                                 console.log("user ID", user_id)
                                 return user_id && user_key
                             })))

                var e = document.createElement("xxx")
                e.innerHTML = msg
                // console.log(e)
                var result
                var exc
                try {
                    result = m(e)
                } catch(e) {
                    exc = e
                }

                if (result) {
                    console.log("user-key", user_key)
                    new ChatBoard({room: "elepaio", user_key: user_key})
                } else {
                    console.error("failed to get a user key", exc)
                }
            })
    }
})

}()
<|endoftext|>


<commit_before>function generate(){
    save();

    if(charlist.length > 0){
        var passwords = '';

        // create new password
        var password_loopcounter = document.getElementById('number-of-passwords').value - 1;
        do{
            // add character to current password
            var character_loopcounter = document.getElementById('length').value - 1;
            do{
                // select random characters from possible character list
                // handle the HTML symbols
                // and add it to the passwords string
                passwords += charlist.substr(
                  Math.floor(Math.random() * charlist.length - 1),
                  1
                ).replace(/&/g,'&') // &
                 .replace(/>/g,'>') // >
                 .replace(/</g,'<') // <
                 .replace(/"/g,'"'); // "
            }while(character_loopcounter--);

            passwords += '
';
        }while(password_loopcounter--);

        document.getElementById('passwords').innerHTML = passwords;

    }else{
        document.getElementById('passwords').innerHTML = 'You must select at least one option.';
    }
}

function reset(){
    if(confirm('Reset settings?')){
        document.getElementById('latin-lowercase').checked = 1;
        document.getElementById('latin-uppercase').checked = 3;
        document.getElementById('length').value = 15;
        document.getElementById('number-of-passwords').value = 1;
        document.getElementById('numbers').checked = 1;
        document.getElementById('other-lowercase').checked = 1;
        document.getElementById('other-uppercase').checked = 1;
        document.getElementById('passwords').innerHTML = '';
        document.getElementById('symbols').checked = 2;

        save();
    }
}

function save(){
    // validate settings

    if(isNaN(document.getElementById('length').value)
      || document.getElementById('length').value < 1
      || document.getElementById('length').value == 15){
        document.getElementById('length').value = 15;
        window.localStorage.removeItem('passwordgenerator-length');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-length',
          document.getElementById('length').value
        );
    }

    if(isNaN(document.getElementById('number-of-passwords').value)
      || document.getElementById('number-of-passwords').value < 1
      || document.getElementById('number-of-passwords').value == 1){
        document.getElementById('number-of-passwords').value = 1;
        window.localStorage.removeItem('passwordgenerator-number-of-passwords');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-number-of-passwords',
          document.getElementById('number-of-passwords').value
        );
    }

    // create list of possible characters
    // if not checked, store value in localStorage
    charlist = '';

    if(document.getElementById('latin-lowercase').checked){
        charlist += 'abcdefghijklmnopqrstuvwxyz';
        window.localStorage.removeItem('passwordgenerator-latin-lowercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-latin-lowercase',
          1
        );
    }

    if(document.getElementById('latin-uppercase').checked){
        charlist += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        window.localStorage.removeItem('passwordgenerator-latin-uppercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-latin-uppercase',
          1
        );
    }

    if(document.getElementById('numbers').checked){
        charlist += '0123456789';
        window.localStorage.removeItem('passwordgenerator-numbers');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-numbers',
          1
        );
    }

    if(document.getElementById('other-lowercase').checked){
        charlist += document.getElementById('other-lowercase-touse').value;
        window.localStorage.removeItem('passwordgenerator-other-lowercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-other-lowercase',
          1
        );
    }

    if(document.getElementById('other-uppercase').checked){
        charlist += document.getElementById('other-uppercase-touse').value;
        window.localStorage.removeItem('passwordgenerator-other-uppercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-other-uppercase',
          1
        );
    }

    if(document.getElementById('symbols').checked){
        charlist += document.getElementById('symbols-touse').value;
        window.localStorage.removeItem('passwordgenerator-symbols');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-symbols',
          1
        );
    }
}

var charlist = '';

// check or uncheck settings based on localStorage
document.getElementById('length').value = window.localStorage.getItem('passwordgenerator-length') === null
  ? 15
  : window.localStorage.getItem('passwordgenerator-length');

document.getElementById('latin-lowercase').checked =
  window.localStorage.getItem('passwordgenerator-latin-lowercase') === null;

document.getElementById('latin-uppercase').checked =
  window.localStorage.getItem('passwordgenerator-latin-uppercase') === null;

document.getElementById('number-of-passwords').value =
  window.localStorage.getItem('passwordgenerator-number-of-passwords') === null
    ? 1
    : window.localStorage.getItem('passwordgenerator-number-of-passwords');

document.getElementById('numbers').checked =
  window.localStorage.getItem('passwordgenerator-numbers') === null;

document.getElementById('other-lowercase').checked =
  window.localStorage.getItem('passwordgenerator-other-lowercase') === null;

document.getElementById('other-lowercase-touse').value = 'áčďéěiíňóřšťúůýž';

document.getElementById('other-uppercase').checked =
  window.localStorage.getItem('passwordgenerator-other-uppercase') === null;

document.getElementById('other-uppercase-touse').value = 'ÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ';

document.getElementById('symbols').checked =
  window.localStorage.getItem('passwordgenerator-symbols') === null;

document.getElementById('symbols-touse').value = '~!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?';

window.onkeydown = function(e){
    var key = window.event ? event : e;
    key = key.charCode ? key.charCode : key.keyCode;

    if(key === 72){// H
        generate();
    }
};
<commit_msg>fixed .checked property sets<commit_after>function generate(){
    save();

    if(charlist.length > 0){
        var passwords = '';

        // create new password
        var password_loopcounter = document.getElementById('number-of-passwords').value - 1;
        do{
            // add character to current password
            var character_loopcounter = document.getElementById('length').value - 1;
            do{
                // select random characters from possible character list
                // handle the HTML symbols
                // and add it to the passwords string
                passwords += charlist.substr(
                  Math.floor(Math.random() * charlist.length - 1),
                  1
                ).replace(/&/g,'&') // &
                 .replace(/>/g,'>') // >
                 .replace(/</g,'<') // <
                 .replace(/"/g,'"'); // "
            }while(character_loopcounter--);

            passwords += '
';
        }while(password_loopcounter--);

        document.getElementById('passwords').innerHTML = passwords;

    }else{
        document.getElementById('passwords').innerHTML = 'You must select at least one option.';
    }
}

function reset(){
    if(confirm('Reset settings?')){
        document.getElementById('latin-lowercase').checked = true;
        document.getElementById('latin-uppercase').checked = true;
        document.getElementById('length').value = 15;
        document.getElementById('number-of-passwords').value = 1;
        document.getElementById('numbers').checked = true;
        document.getElementById('other-lowercase').checked = true;
        document.getElementById('other-uppercase').checked = true;
        document.getElementById('passwords').innerHTML = '';
        document.getElementById('symbols').checked = true;

        save();
    }
}

function save(){
    // validate settings

    if(isNaN(document.getElementById('length').value)
      || document.getElementById('length').value < 1
      || document.getElementById('length').value == 15){
        document.getElementById('length').value = 15;
        window.localStorage.removeItem('passwordgenerator-length');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-length',
          document.getElementById('length').value
        );
    }

    if(isNaN(document.getElementById('number-of-passwords').value)
      || document.getElementById('number-of-passwords').value < 1
      || document.getElementById('number-of-passwords').value == 1){
        document.getElementById('number-of-passwords').value = 1;
        window.localStorage.removeItem('passwordgenerator-number-of-passwords');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-number-of-passwords',
          document.getElementById('number-of-passwords').value
        );
    }

    // create list of possible characters
    // if not checked, store value in localStorage
    charlist = '';

    if(document.getElementById('latin-lowercase').checked){
        charlist += 'abcdefghijklmnopqrstuvwxyz';
        window.localStorage.removeItem('passwordgenerator-latin-lowercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-latin-lowercase',
          1
        );
    }

    if(document.getElementById('latin-uppercase').checked){
        charlist += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        window.localStorage.removeItem('passwordgenerator-latin-uppercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-latin-uppercase',
          1
        );
    }

    if(document.getElementById('numbers').checked){
        charlist += '0123456789';
        window.localStorage.removeItem('passwordgenerator-numbers');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-numbers',
          1
        );
    }

    if(document.getElementById('other-lowercase').checked){
        charlist += document.getElementById('other-lowercase-touse').value;
        window.localStorage.removeItem('passwordgenerator-other-lowercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-other-lowercase',
          1
        );
    }

    if(document.getElementById('other-uppercase').checked){
        charlist += document.getElementById('other-uppercase-touse').value;
        window.localStorage.removeItem('passwordgenerator-other-uppercase');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-other-uppercase',
          1
        );
    }

    if(document.getElementById('symbols').checked){
        charlist += document.getElementById('symbols-touse').value;
        window.localStorage.removeItem('passwordgenerator-symbols');

    }else{
        window.localStorage.setItem(
          'passwordgenerator-symbols',
          1
        );
    }
}

var charlist = '';

// check or uncheck settings based on localStorage
document.getElementById('length').value = window.localStorage.getItem('passwordgenerator-length') === null
  ? 15
  : window.localStorage.getItem('passwordgenerator-length');

document.getElementById('latin-lowercase').checked =
  window.localStorage.getItem('passwordgenerator-latin-lowercase') === null;

document.getElementById('latin-uppercase').checked =
  window.localStorage.getItem('passwordgenerator-latin-uppercase') === null;

document.getElementById('number-of-passwords').value =
  window.localStorage.getItem('passwordgenerator-number-of-passwords') === null
    ? 1
    : window.localStorage.getItem('passwordgenerator-number-of-passwords');

document.getElementById('numbers').checked =
  window.localStorage.getItem('passwordgenerator-numbers') === null;

document.getElementById('other-lowercase').checked =
  window.localStorage.getItem('passwordgenerator-other-lowercase') === null;

document.getElementById('other-lowercase-touse').value = 'áčďéěiíňóřšťúůýž';

document.getElementById('other-uppercase').checked =
  window.localStorage.getItem('passwordgenerator-other-uppercase') === null;

document.getElementById('other-uppercase-touse').value = 'ÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ';

document.getElementById('symbols').checked =
  window.localStorage.getItem('passwordgenerator-symbols') === null;

document.getElementById('symbols-touse').value = '~!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?';

window.onkeydown = function(e){
    var key = window.event ? event : e;
    key = key.charCode ? key.charCode : key.keyCode;

    if(key === 72){// H
        generate();
    }
};
<|endoftext|>


<commit_before>
// Runtime depends on: boxing.js, perform.js, remoteObjects.js

(function() {

	var doesNotUnderstand = function(message) {
		var msg = this + " did not understand " + st.unbox(message.selector());
		st.Exception.signal_(st.string(msg));
	};

	st.Object._addInstanceMethods({
		doesNotUnderstand_: doesNotUnderstand,
		halt: function() { debugger; },
		_class: function() { return this._theClass; },

		perform_: st.perform,
		perform_with_: st.perform,
		perform_with_with_: st.perform,
		perform_with_with_with_: st.perform,
		perform_withArguments_: function (aSTMessageSelector, anArgumentsCollection){
			var args = [aSTMessageSelector].concat(st.unbox(anArgumentsCollection));
			return st.perform.apply(this, args);
		},
		copy : function() {
			var duplicate = this._class().basicNew();

			for (slot in this) {
				if ((typeof(this[slot])!= "function")  && (slot[0]=='$')){
					duplicate[slot] = this[slot];
				}
			}
			return duplicate;

		}

	});
	st.Object._addClassMethods({
		asRemote: function() {
			return st.passMessage(this, st.Message.selector_(st.string("asRemote")));
		},
		halt: function() { debugger; },
		doesNotUnderstand_: doesNotUnderstand
	});

})();
<commit_msg>removed some of the primitives which became unwanted when introducing metaclass hierarchy added basicSize primitive which works for fixedSize class objects<commit_after>
// Runtime depends on: boxing.js, perform.js, remoteObjects.js

(function() {

	st.Object._addInstanceMethods({
		halt: function() { debugger; },
		_class: function() { return this._theClass; },

		doesNotUnderstand_: function(message) {
			var msg = this + " did not understand " + st.unbox(message.selector());
			st.Exception.signal_(st.string(msg));
		},
		perform_: st.perform,
		perform_with_: st.perform,
		perform_with_with_: st.perform,
		perform_with_with_with_: st.perform,
		perform_withArguments_: function (aSTMessageSelector, anArgumentsCollection){
			var args = [aSTMessageSelector].concat(st.unbox(anArgumentsCollection));
			return st.perform.apply(this, args);
		},
		copy : function() {
			var duplicate = this._class().basicNew();

			for (slot in this) {
				if ((typeof(this[slot])!= "function")  && (slot[0]=='$')){
					duplicate[slot] = this[slot];
				}
			}
			return duplicate;
		},

		basicSize: function (){
			this._class().isVariable().ifTrue_ifFalse_(
				st.block(function (){ debugger; }),
				st.block(function (){ return st.number(0); }));
		}

	});
	st.Object._addClassMethods({
		asRemote: function() {
			return st.passMessage(this, st.Message.selector_(st.string("asRemote")));
		}
	});

})();
<|endoftext|>


<commit_before>'use strict';

function percent(value, max){
    return ((value / max) * 100).toFixed(7) + '%';
}

function play(selected){
    settings_save();

    // Check how many games player wants to play.
    var repeat = parseInt(
      document.getElementById('repeat').value,
      10
    );
    if(repeat < 1
      || isNaN(repeat)){
        return;
    }

    // Keep track of results.
    var opponent_plays = [
      0,
      0,
      0,
    ];
    var results = [
      0,
      0,
      0,
    ];
    total += repeat;

    // Loop through the games.
    var loop_counter = repeat - 1;
    do{
        // Result is a loss by default.
        var result = 0;

        // Generate a random number (0, 1, or 2).
        opponent_choice = random_integer({
          'max': 3,
        });
        opponent_plays[opponent_choice] += 1;

        // Check for ties.
        if(selected === opponent_choice){
            result = 2;

        // Check for wins.
        }else if((selected === 0 && opponent_choice === 2)
          || (selected === 1 && opponent_choice === 0)
          || (selected === 2 && opponent_choice === 1)){
            result = 1;
        }

        // Update loss/tie/win values and store them in a temporary array.
        results[result] += 1;
    }while(loop_counter--);

    losses += results[0];
    ties += results[2];
    wins += results[1];

    // Create result strings.
    var paper = '' + opponent_plays[1] + ' papers (';
    var rock = '' + opponent_plays[0] + ' rocks (';
    var scissors = '' + opponent_plays[2] + ' scissors (';

    if(selected === 0){
        paper += 'losses) ' + percent(results[0], repeat);
        rock += 'ties) ' + percent(results[2], repeat);
        scissors += 'wins) ' + percent(results[1], repeat);

    }else if(selected === 1){
        paper += 'ties) ' + percent(results[2], repeat);
        rock += 'wins) ' + percent(results[1], repeat);
        scissors += 'losses) ' + percent(results[0], repeat);

    }else{
        paper += 'wins) ' + percent(results[1], repeat);
        rock += 'losses) ' + percent(results[0], repeat);
        scissors += 'ties) ' + percent(results[2], repeat);
    }

    // Display game information.
    document.getElementById('opponent').innerHTML = 'You played '
      + ['rock', 'paper', 'scissors',][selected]
      + ' ' + repeat + ' times.
'
      + 'Your opponent played:
'
        + rock + '
'
        + paper + '
'
        + scissors;
    document.getElementById('player').innerHTML =
      total + ' total games played
'
        + '' + losses + ' losses (' + percent(losses, total) + ')
'
        + '' + ties + ' ties (' + percent(ties, total) + ')
'
        + '' + wins + ' wins (' + percent(wins, total) + ')';
}

function reset(){
    if(!window.confirm('Reset scores?')){
        return;
    }

    document.getElementById('opponent').innerHTML = '';
    document.getElementById('player').innerHTML = '';

    losses = 0;
    ties = 0;
    total = 0;
    wins = 0;
}

var losses = 0;
var opponent_choice = 0;
var selected = 0;
var ties = 0;
var total = 0;
var wins = 0;

window.onload = function(e){
    input_init({
      'keybinds': {
        80: {
          'todo': function(){
              play(1);
          },
        },
        82: {
          'todo': function(){
              play(0);
          },
        },
        83: {
          'todo': function(){
              play(2);
          },
        },
      },
    });
    settings_init({
      'prefix': 'RockPaperScissors.htm-',
      'settings': {
        'repeat': 1,
      },
    });

    settings_update();

    document.getElementById('paper').onclick = function(){
        play(1);
    };
    document.getElementById('reset').onclick = reset;
    document.getElementById('rock').onclick = function(){
        play(0);
    };
    document.getElementById('scissors').onclick = function(){
        play(2);
    };
};
<commit_msg>removed <commit_after>'use strict';

function percent(value, max){
    return ((value / max) * 100).toFixed(7) + '%';
}

function play(selected){
    settings_save();

    // Check how many games player wants to play.
    var repeat = parseInt(
      document.getElementById('repeat').value,
      10
    );
    if(repeat < 1
      || isNaN(repeat)){
        return;
    }

    // Keep track of results.
    var opponent_plays = [
      0,
      0,
      0,
    ];
    var results = [
      0,
      0,
      0,
    ];
    total += repeat;

    // Loop through the games.
    var loop_counter = repeat - 1;
    do{
        // Result is a loss by default.
        var result = 0;

        // Generate a random number (0, 1, or 2).
        opponent_choice = random_integer({
          'max': 3,
        });
        opponent_plays[opponent_choice] += 1;

        // Check for ties.
        if(selected === opponent_choice){
            result = 2;

        // Check for wins.
        }else if((selected === 0 && opponent_choice === 2)
          || (selected === 1 && opponent_choice === 0)
          || (selected === 2 && opponent_choice === 1)){
            result = 1;
        }

        // Update loss/tie/win values and store them in a temporary array.
        results[result] += 1;
    }while(loop_counter--);

    losses += results[0];
    ties += results[2];
    wins += results[1];

    // Create result strings.
    var paper = opponent_plays[1] + ' papers (';
    var rock = opponent_plays[0] + ' rocks (';
    var scissors = opponent_plays[2] + ' scissors (';

    if(selected === 0){
        paper += 'losses) ' + percent(results[0], repeat);
        rock += 'ties) ' + percent(results[2], repeat);
        scissors += 'wins) ' + percent(results[1], repeat);

    }else if(selected === 1){
        paper += 'ties) ' + percent(results[2], repeat);
        rock += 'wins) ' + percent(results[1], repeat);
        scissors += 'losses) ' + percent(results[0], repeat);

    }else{
        paper += 'wins) ' + percent(results[1], repeat);
        rock += 'losses) ' + percent(results[0], repeat);
        scissors += 'ties) ' + percent(results[2], repeat);
    }

    // Display game information.
    document.getElementById('opponent').innerHTML = 'You played '
      + ['rock', 'paper', 'scissors',][selected]
      + ' ' + repeat + ' times.
'
      + 'Your opponent played:
'
        + rock + '
'
        + paper + '
'
        + scissors;
    document.getElementById('player').innerHTML =
      total + ' total games played
'
        + losses + ' losses (' + percent(losses, total) + ')
'
        + ties + ' ties (' + percent(ties, total) + ')
'
        + wins + ' wins (' + percent(wins, total) + ')';
}

function reset(){
    if(!window.confirm('Reset scores?')){
        return;
    }

    document.getElementById('opponent').innerHTML = '';
    document.getElementById('player').innerHTML = '';

    losses = 0;
    ties = 0;
    total = 0;
    wins = 0;
}

var losses = 0;
var opponent_choice = 0;
var selected = 0;
var ties = 0;
var total = 0;
var wins = 0;

window.onload = function(e){
    input_init({
      'keybinds': {
        80: {
          'todo': function(){
              play(1);
          },
        },
        82: {
          'todo': function(){
              play(0);
          },
        },
        83: {
          'todo': function(){
              play(2);
          },
        },
      },
    });
    settings_init({
      'prefix': 'RockPaperScissors.htm-',
      'settings': {
        'repeat': 1,
      },
    });

    settings_update();

    document.getElementById('paper').onclick = function(){
        play(1);
    };
    document.getElementById('reset').onclick = reset;
    document.getElementById('rock').onclick = function(){
        play(0);
    };
    document.getElementById('scissors').onclick = function(){
        play(2);
    };
};
<|endoftext|>


<commit_before>jsio('from shared.javascript import Class, bind')
jsio('from net.protocols.rtjp import RTJPProtocol')

exports = Class(RTJPProtocol, function(supr) {

	this.getSessionId = function() {
		if (this.transport._socket && this.transport._socket._session) {
			return this.transport._socket._session.key
		} else {
			return (this._fakeSessionId || (this._fakeSessionId = 'FAKE_CONNECTION_ID_' + new Date().getTime()))
		}
	}

	this.init = function() {
		supr(this, 'init')
		this._requestHandlers = {}

		this.handleRequest('FIN_REQUEST_SUBSCRIBE_ITEM', bind(this, function(args){
			var itemId = args.id
			var onMutated = bind(this, function(mutation) {
				if (mutation._session == this.getSessionId()) { return }
				this.sendFrame('FIN_EVENT_ITEM_MUTATED', mutation)
			})
			this._itemSubs[itemId] = this.server.subscribeToItemMutations(itemId, onMutated,
				bind(this, 'sendFrame', 'FIN_EVENT_ITEM_SNAPSHOT'))
		}))

		this.handleRequest('FIN_REQUEST_ITEM_EXISTS', bind(this, function(request) {
			this.server.exists(request._id, bind(this, function(response) {
				response._requestId = request._requestId
				this.sendFrame('FIN_RESPONSE_ITEM_EXISTS', response)
			}))
		}))

		this.handleRequest('FIN_REQUEST_CREATE_ITEM', bind(this, function(request) {
			this.server.createItem(request.data, bind(this, function(item) {
				var response = { _requestId: request._requestId, item: item.getData() }
				this.sendFrame('FIN_RESPONSE_CREATE_ITEM', response)
			}))
		}))

		this.handleRequest('FIN_REQUEST_MUTATE_ITEM', bind(this, function(mutation){
			// TODO We should label which user made the change here
			mutation._session = this.getSessionId()
			this.server.handleMutation(mutation)
		}))

		this.handleRequest('FIN_REQUEST_SUBSCRIBE_ITEMSET', bind(this, function(args) {
			var itemSetId = args.id,
				onMutated = bind(this, '_onItemSetMutated')
			this._itemSetSubs[itemSetId] = this.server.subscribeToItemSet(itemSetId, onMutated)
		}))

		this.handleRequest('FIN_REQUEST_ADD_REDUCTION', bind(this, function(args) {
			var itemSetId = args.id,
				reductionId = args.reductionId
			this.server.addItemSetReduction(itemSetId, reductionId, this._itemSetSubs[itemSetId])
		}))
	}

/* Connection
 ************/
	this.connectionMade = function() {
		this._log('connectionMade')
		this._itemSubs = {}
		this._itemSetSubs = {}
	}

	this.connectionLost = function() {
		logger.log('connection lost - unsubscribing from item mutation subscriptions')
		for (var itemId in this._itemSubs) {
			this.server.unsubscribeFromItemMutations(itemId, this._itemSubs[itemId])
		}
		for (var itemSetId in this._itemSetSubs) {
			this.server.unsubscribeFromItemSetMutations(itemSetId, this._itemSetSubs[itemSetId])
		}
	}

/* Requests
 **********/
	this.handleRequest = function(requestName, callback) {
		this._requestHandlers[requestName] = callback
	}

	this.frameReceived = function(id, name, args) {
		this._log('recv', id, name, JSON.stringify(args))
		if (!this._requestHandlers[name]) {
			logger.warn('Received request without handler', name)
			return
		}
		this._requestHandlers[name](args)
	}

/* Item sets
 ***********/

	this._onItemSetMutated = function(mutation) {
		this.sendFrame('FIN_EVENT_ITEMSET_MUTATED', mutation)
	}

/* Util
 ******/
	this.sendFrame = function(name, args) {
		this._log('send', name, JSON.stringify(args))
		supr(this, 'sendFrame', arguments)
	}

	this._log = function() {
		var args = Array.prototype.slice.call(arguments)
		if (this.transport._socket) {
			if (this.transport._socket._session) {
				args.unshift(this.transport._socket._session.key)
			}
		}
		logger.log.apply(logger, args)
	}
})
<commit_msg>Wrap send statements in a try catch and log an error if send throws<commit_after>jsio('from shared.javascript import Class, bind')
jsio('from net.protocols.rtjp import RTJPProtocol')

exports = Class(RTJPProtocol, function(supr) {

	this.getSessionId = function() {
		if (this.transport._socket && this.transport._socket._session) {
			return this.transport._socket._session.key
		} else {
			return (this._fakeSessionId || (this._fakeSessionId = 'FAKE_CONNECTION_ID_' + new Date().getTime()))
		}
	}

	this.init = function() {
		supr(this, 'init')
		this._requestHandlers = {}

		this.handleRequest('FIN_REQUEST_SUBSCRIBE_ITEM', bind(this, function(args){
			var itemId = args.id
			var onMutated = bind(this, function(mutation) {
				if (mutation._session == this.getSessionId()) { return }
				this.sendFrame('FIN_EVENT_ITEM_MUTATED', mutation)
			})
			this._itemSubs[itemId] = this.server.subscribeToItemMutations(itemId, onMutated,
				bind(this, 'sendFrame', 'FIN_EVENT_ITEM_SNAPSHOT'))
		}))

		this.handleRequest('FIN_REQUEST_ITEM_EXISTS', bind(this, function(request) {
			this.server.exists(request._id, bind(this, function(response) {
				response._requestId = request._requestId
				this.sendFrame('FIN_RESPONSE_ITEM_EXISTS', response)
			}))
		}))

		this.handleRequest('FIN_REQUEST_CREATE_ITEM', bind(this, function(request) {
			this.server.createItem(request.data, bind(this, function(item) {
				var response = { _requestId: request._requestId, item: item.getData() }
				this.sendFrame('FIN_RESPONSE_CREATE_ITEM', response)
			}))
		}))

		this.handleRequest('FIN_REQUEST_MUTATE_ITEM', bind(this, function(mutation){
			// TODO We should label which user made the change here
			mutation._session = this.getSessionId()
			this.server.handleMutation(mutation)
		}))

		this.handleRequest('FIN_REQUEST_SUBSCRIBE_ITEMSET', bind(this, function(args) {
			var itemSetId = args.id,
				onMutated = bind(this, '_onItemSetMutated')
			this._itemSetSubs[itemSetId] = this.server.subscribeToItemSet(itemSetId, onMutated)
		}))

		this.handleRequest('FIN_REQUEST_ADD_REDUCTION', bind(this, function(args) {
			var itemSetId = args.id,
				reductionId = args.reductionId
			this.server.addItemSetReduction(itemSetId, reductionId, this._itemSetSubs[itemSetId])
		}))
	}

/* Connection
 ************/
	this.connectionMade = function() {
		this._log('connectionMade')
		this._itemSubs = {}
		this._itemSetSubs = {}
	}

	this.connectionLost = function() {
		logger.log('connection lost - unsubscribing from item mutation subscriptions')
		for (var itemId in this._itemSubs) {
			this.server.unsubscribeFromItemMutations(itemId, this._itemSubs[itemId])
		}
		for (var itemSetId in this._itemSetSubs) {
			this.server.unsubscribeFromItemSetMutations(itemSetId, this._itemSetSubs[itemSetId])
		}
	}

/* Requests
 **********/
	this.handleRequest = function(requestName, callback) {
		this._requestHandlers[requestName] = callback
	}

	this.frameReceived = function(id, name, args) {
		this._log('recv', id, name, JSON.stringify(args))
		if (!this._requestHandlers[name]) {
			logger.warn('Received request without handler', name)
			return
		}
		this._requestHandlers[name](args)
	}

/* Item sets
 ***********/

	this._onItemSetMutated = function(mutation) {
		this.sendFrame('FIN_EVENT_ITEMSET_MUTATED', mutation)
	}

/* Util
 ******/
	this.sendFrame = function(name, args) {
		this._log('send', name, JSON.stringify(args))
		try {
			supr(this, 'sendFrame', arguments)
		} catch(e) {
			logger.error("when writing", e, name, JSON.stringify(args))
		}
	}

	this._log = function() {
		var args = Array.prototype.slice.call(arguments)
		if (this.transport._socket) {
			if (this.transport._socket._session) {
				args.unshift(this.transport._socket._session.key)
			}
		}
		logger.log.apply(logger, args)
	}
})
<|endoftext|>


<commit_before>$.Redactor.prototype.WoltLabInsert = function() {
	"use strict";

	return {
		init: function () {
			var callback = this.opts.woltlab.placeholderCallback;

			var mpHtml = this.insert.html;
			this.insert.html = (function (html, data) {
				if (callback) callback = callback();

				var selection = window.getSelection();
				if (selection.rangeCount && selection.anchorNode.nodeName === 'IMG') {
					this.caret.after(selection.anchorNode);
				}

				this.placeholder.hide();
				this.core.editor().focus();

				// Firefox may have an incorrect selection if pasting into the editor using the contextual menu
				if (this.detect.isFirefox()) {
					var anchorNode = (selection.anchorNode.nodeType === Node.TEXT_NODE) ? selection.anchorNode.parentNode : selection.anchorNode;
					if (anchorNode.closest('.redactor-layer') === null) {
						this.selection.restore();

						anchorNode = (selection.anchorNode.nodeType === Node.TEXT_NODE) ? selection.anchorNode.parentNode : selection.anchorNode;
						if (anchorNode.closest('.redactor-layer') === null) {
							this.WoltLabCaret.endOfEditor();
							this.selection.save();
						}
					}
				}

				/** @var Element */
				var block = this.selection.block();

				var isEmptyEditor = (this.$editor[0].innerHTML.replace(/<\/?p>/g, '').replace(/
/g, '').replace(/\u200B/g, '').trim() === '');

				mpHtml.call(this, html, data);

				if (isEmptyEditor) {
					block = this.$editor[0].firstElementChild;
				}

				if (block && block.nodeName === 'P' && block.nextElementSibling) {
					var removeBlock = false;
					if (block.childElementCount === 0 && block.textContent.replace(/\u200B/g, '').trim() === '') {
						removeBlock = true;
					}
					else if (block.childElementCount === 1 && block.innerHTML === '
') {
						removeBlock = true;
					}

					if (removeBlock) {
						// inserting HTML tends to cause new paragraphs inserted
						// rather than using the current, empty one
						elRemove(block);
					}
				}

				if (selection.rangeCount && selection.anchorNode.nodeName === 'IMG') {
					this.caret.after(selection.anchorNode);
				}
			}).bind(this);

			var mpText = this.insert.text;
			this.insert.text = (function (text) {
				if (callback) callback = callback();

				this.core.editor().focus();
				this.selection.restore();
				if (elClosest(window.getSelection().anchorNode, '.redactor-layer') !== this.core.editor()[0]) {
					this.WoltLabCaret.endOfEditor();
				}

				mpText.call(this, text);

				this.selection.saveInstant();
			}).bind(this);

			this.placeHtml = (function(html) {
				var hasBbcodeMarker = false;
				html.forEach(function(fragment) {
					if (fragment instanceof Element && fragment.classList.contains('woltlab-bbcode-marker')) {
						hasBbcodeMarker = true;
					}
				});

				var marker = document.createElement('span');
				marker.id = 'redactor-insert-marker';
				marker = this.insert.node(marker);

				$(marker).before(html);
				this.selection.restore();
				if (!hasBbcodeMarker) this.caret.after(marker);
				$(marker).remove();
			}).bind(this);
		}
	};
};
<commit_msg>Caret placement for raw bbcodes was incorrect<commit_after>$.Redactor.prototype.WoltLabInsert = function() {
	"use strict";

	return {
		init: function () {
			var callback = this.opts.woltlab.placeholderCallback;

			var mpHtml = this.insert.html;
			this.insert.html = (function (html, data) {
				if (callback) callback = callback();

				var selection = window.getSelection();
				if (selection.rangeCount && selection.anchorNode.nodeName === 'IMG') {
					this.caret.after(selection.anchorNode);
				}

				this.placeholder.hide();
				this.core.editor().focus();

				// Firefox may have an incorrect selection if pasting into the editor using the contextual menu
				if (this.detect.isFirefox()) {
					var anchorNode = (selection.anchorNode.nodeType === Node.TEXT_NODE) ? selection.anchorNode.parentNode : selection.anchorNode;
					if (anchorNode.closest('.redactor-layer') === null) {
						this.selection.restore();

						anchorNode = (selection.anchorNode.nodeType === Node.TEXT_NODE) ? selection.anchorNode.parentNode : selection.anchorNode;
						if (anchorNode.closest('.redactor-layer') === null) {
							this.WoltLabCaret.endOfEditor();
							this.selection.save();
						}
					}
				}

				/** @var Element */
				var block = this.selection.block();

				var isEmptyEditor = (this.$editor[0].innerHTML.replace(/<\/?p>/g, '').replace(/
/g, '').replace(/\u200B/g, '').trim() === '');

				mpHtml.call(this, html, data);

				if (isEmptyEditor) {
					block = this.$editor[0].firstElementChild;
				}

				if (block && block.nodeName === 'P' && block.nextElementSibling) {
					var removeBlock = false;
					if (block.childElementCount === 0 && block.textContent.replace(/\u200B/g, '').trim() === '') {
						removeBlock = true;
					}
					else if (block.childElementCount === 1 && block.innerHTML === '
') {
						removeBlock = true;
					}

					if (removeBlock) {
						// inserting HTML tends to cause new paragraphs inserted
						// rather than using the current, empty one
						elRemove(block);
					}
				}

				if (selection.rangeCount && selection.anchorNode.nodeName === 'IMG') {
					this.caret.after(selection.anchorNode);
				}
			}).bind(this);

			var mpText = this.insert.text;
			this.insert.text = (function (text) {
				if (callback) callback = callback();

				this.core.editor().focus();
				this.selection.restore();
				if (elClosest(window.getSelection().anchorNode, '.redactor-layer') !== this.core.editor()[0]) {
					this.WoltLabCaret.endOfEditor();
				}

				mpText.call(this, text);

				this.selection.saveInstant();
			}).bind(this);

			this.insert.placeHtml = (function(html) {
				var hasBbcodeMarker = false;
				html.forEach(function(fragment) {
					if (fragment instanceof Element && fragment.classList.contains('woltlab-bbcode-marker')) {
						hasBbcodeMarker = true;
					}
				});

				var marker = document.createElement('span');
				marker.id = 'redactor-insert-marker';
				marker = this.insert.node(marker);

				$(marker).before(html);
				if (!hasBbcodeMarker) {
					this.selection.restore();
					this.caret.after(marker);
				}
				$(marker).remove();
			}).bind(this);
		}
	};
};
<|endoftext|>


<commit_before>console.log('Confirm that this sends no outside network requests in the Network Panel.')

var receiveProgress = document.getElementById('receiveProgress')
var sendProgress = document.getElementById('sendProgress')
var bitrateDiv = document.getElementById('bitrate')
var statusMessage = document.getElementById('status')
var downloadsAnchor = document.getElementById('downloads')
var theirVideo = document.getElementById('theirVideo')
var myVideo = document.getElementById('myVideo')

function WebRTCChat(cfg, con, sendTyping) {
    var self = this;

/* WebRTC setup for broser-to-browser connection */
    self.cfg = {'iceServers':[{
      'url': 'stun:stun.l.google.com:19302'
    }]}; //{"url":"stun:23.21.150.121"}
    self.con = {'optional':  [{'DtlsSrtpKeyAgreement': true}] };
    self.activeChannel;
    self.activeConnection;
    self.roomName;

    self.readystate = false;
    self.sendTyping = true;

/* WebRTC + CHAT CONNECTION CODE */

    /* THE HOST (initiates the chat) */

    self.hostChat = function(offer_callback, ready_callback) {
        var hostConnection = new RTCPeerConnection(self.cfg, self.con);                                 // init connection
        self.initConnection(hostConnection, offer_callback);

        var hostChannel = hostConnection.createDataChannel('chat', {
            // reliable: true,
            // ordered: true
        });
        self.initChannel(hostChannel, ready_callback);

        self.initVideo();

        console.log("Creating RTC Chat Host Offer...");
        hostConnection.createOffer(
            self.handleDescription,
            self.handleDescriptionFailure,
            {offerToReceiveAudio: true, offerToReceiveVideo: true}
        );
        // copy paste this offer to all clients who want to join
        // they paste their answer back, which goes into handleAnswerFromClient
    }

    self.handleAnswerFromClient = function(answer) {
        var answerDesc = new RTCSessionDescription(answer.rtc);
        console.log("Received Chat RTC Join Answer: ", answerDesc);
        self.activeConnection.setRemoteDescription(answerDesc);
        self.activeChannel.onopen()
        writeToChatLog("Started hosting a chat.", "text-success alert-success");

        // hostChannel.onopen will trigger once the connection is complete (enabling the chat window)
    }

    /* THE JOINEE (joins an existing chat) */

    self.joinChat = function(offer, answer_callback, ready_callback) {
        var clientConnection = new RTCPeerConnection(cfg, con);
        self.initConnection(clientConnection, answer_callback);

        self.activeConnection.ondatachannel = function (e) {                                     // once client receives a good data channel from the host
            // Chrome sends event, FF sends raw channel
            var clientChannel = e.channel || e;
            self.initChannel(clientChannel, ready_callback);
            self.activeChannel.onopen()
            writeToChatLog("Joined a chat.", "text-success alert-success");
            // clientChannel.onopen will then trigger once the connection is complete (enabling the chat window)
        };

        self.roomName = offer.roomName;

        var offerDesc = new RTCSessionDescription(offer.rtc);
        console.log("Received Chat RTC Host Offer: ", offerDesc);
        self.activeConnection.setRemoteDescription(offerDesc);

        // self.initVideo();

        console.log("Answering Chat Host Offer...");
        self.activeConnection.createAnswer(
            self.handleDescription,
            self.handleDescriptionFailure
            // {offerToReceiveAudio: true, offerToReceiveVideo: true}
        );

        // ondatachannel triggers once the client has accepted our answer ^
    }

    self.initConnection = function(conn, callback) {
        self.activeConnection = conn;
        // these aren't really necessary
        conn.onconnection                   = function (state) {console.info('Chat connection complete: ', event);}
        conn.onsignalingstatechange         = function (state) {console.info('Signaling state change: ', state); if (self.activeConnection.iceConnectionState == "disconnected") self.writeToChatLog("Chat partner disconnected.", "text-warning alert-error");}
        conn.oniceconnectionstatechange     = function (state) {console.info('Signaling ICE connection state change: ', state); if (self.activeConnection.iceConnectionState == "disconnected") self.writeToChatLog("Chat partner disconnected.", "text-warning alert-error");}
        conn.onicegatheringstatechange      = function (state) {console.info('Signaling ICE setup state change: ', state);}
        conn.onaddstream = function (event) {
            var video = theirVideo;
            if (window.URL)
                video.src = window.URL.createObjectURL(event.stream);
            else
                video.src = event.stream;
            console.log("You got their video!");
        }
        //this is the important one
        conn.onicecandidate = function (event) {
            // when browser has determined how to form a connection, generate offer or answer with ICE connection details and PGP public key
            if (event.candidate == null) {
                console.log("Valid ICE connection candidate determined.");
                var offer_or_answer = JSON.stringify({
                    rtc: self.activeConnection.localDescription,
                    roomName: self.roomName
                });
                // pass the offer or answer to the callback for display to the user or to send over some other communication channel
                if (callback) callback(offer_or_answer);
            }
        };
        conn.onfailure = function(details) {callback(details)};
        console.log("Initialized Connection: ", conn);
    }

    self.initChannel = function(chan, callback) {
        self.activeChannel = chan;
        self.activeChannel.binaryType = 'arraybuffer';
        // once the channel is open, trigger the callback to enable the chat window or carry out other logic
        self.activeChannel.onopen = function (e) {
            console.log('Data Channel Connected.');
            self.readystate = true;
            if (callback) callback(e);
        }
        chan.onmessage = self.receiveMessage;
        console.log("Initialized Data Channel: ", chan);
    }

    self.handleDescription = function(desc) {
        self.activeConnection.setLocalDescription(desc);
    }

    self.handleDescriptionFailure = function() {
        console.warn("Failed to create or answer chat offer.");
        self.activeConnection.onfailure("Invalid or expired chat offer. Please try again.")
    }

    // messaging functions

    self.sendTypingMessage = function() {
        self.activeChannel.send(JSON.stringify({message:null,typing:true}));
    }

    self.sendMessage = function(message) {
        self.activeChannel.send(JSON.stringify({message: message}));
        self.writeToChatLog(message, "text-success sent insecure", false);
    }

    self.receiveMessage = function(event) {
        try {
            var data = JSON.parse(event.data);
        } catch(e) {
            console.log('RECEIVING FILE')
            return self.receiveFile(event);
        }

        if (data.file) {
            return self.prepareToReceiveFile(data);
        }

        if (data.typing && !data.message) {
            console.log("Partner is typing...");
            self.displayPartnerTyping();
        }
        else {
            console.log("Received a message: ", data.message);
            self.writeToChatLog(data.message, "text-info recv", false);
        }
    }

    // Audio and Video

    self.initVideo = function() {
        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
        var video = myVideo;

        navigator.getUserMedia({
            audio: false,
            video: true
        }, function (stream) {
          if (window.URL)
            video.src = window.URL.createObjectURL(stream);
          else
            video.src = stream;
          window.myStream = stream;
          self.activeConnection.addStream(window.myStream);
            // self.activeChannel.send(JSON.stringify({
            //     message: "Started sharing video."
            // }));
            self.writeToChatLog(
                "Started sharing video.",
                "text-success sent insecure", false);
        }, function (error){
          console.log('navigator.getUserMedia error: ', error);
        });
    }

    // Files

    self.prepareToReceiveFile = function(data) {
        self.startTime = null;
        self.receiveBuffer = null;
        self.receivedSize = null;
        self.bitrateMax = null;
        self.numReceivedFiles = self.numReceivedFiles || 0;
        self.receivedFiles = self.receivedFiles || {};
        self.writeToChatLog(
            "Receiving " + data.name + " (" + data.size + " bytes)",
            "text-success sent insecure",
            false
        );
        self.numReceivedFiles += 1;
        // XSS out the wazoo
        var downloadLink = downloadsAnchor.innerHTML += (
            '
'
            + 'Download: ' + data.name + ''
            + " (" + data.size + " bytes)"
            + '
'
        )
        self.receivedFiles[data.name] = data;
        self.receivedFiles[data.name].id = self.numReceivedFiles;
        self.receivedFiles[data.name].anchor = document.getElementById('recvd-' + self.numReceivedFiles);
        self.incomingFile = self.receivedFiles[data.name]
    }

    self.receiveFile = function(event) {
        self.startTime = self.startTime || (new Date).getTime();
        self.receiveBuffer = self.receiveBuffer || [];
        self.receivedSize = self.receivedSize || 0;
        self.bitrateMax = self.bitrateMax || 0;

        self.receiveBuffer.push(event.data);
        self.receivedSize += event.data.byteLength;

        receiveProgress.value = self.receivedSize;

        // we are assuming that our signaling protocol told
        // about the expected file size (and name, hash, etc).
        var received = new window.Blob(self.receiveBuffer);
        self.receiveBuffer = [];

        var url = URL.createObjectURL(received);
        self.incomingFile.anchor.href = url;

        var bitrate = Math.round(self.receivedSize * 8 /
            ((new Date()).getTime() - self.startTime));

        if (bitrate > self.bitrateMax) {
            self.bitrateMax = bitrate;
        }

        bitrateDiv.innerHTML = 'Bitrate: ' +
            bitrate + ' kbits/sec (max: ' + self.bitrateMax + ' kbits/sec)';

        if (self.receivedSize >= self.incomingFile.size) {
            self.writeToChatLog(
                "Receiving " + self.incomingFile.name + " finished! Download it below.",
                "text-success sent insecure",
                false
            );
            self.activeChannel.send(JSON.stringify({
                message: 'Received ' + self.incomingFile.name + " succesfully.",
            }));
        } else {
            self.incomingFile.anchor.disabled = true;
        }
    }

    self.sendFile = function(files) {
        var file = [].concat.apply([], files).slice(-1)[0];
        console.log('File is ' + [file.name, file.size, file.type,
            file.lastModifiedDate
        ].join(' '));
        self.activeChannel.send(JSON.stringify({
            file: true,
            name: file.name,
            size: file.size,
        }));
        self.writeToChatLog("Sending " + file.name, "text-success sent insecure", false);

        // Handle 0 size files.
        statusMessage.textContent = '';
        if (file.size === 0) {
          bitrateDiv.innerHTML = '';
          statusMessage.textContent = 'File is empty, please select a non-empty file';
          return;
        }
        sendProgress.max = file.size;
        receiveProgress.max = file.size;
        var chunkSize = 16384;
        var sliceFile = function(offset) {
          var reader = new window.FileReader();
          reader.onload = (function() {
            return function(e) {
              self.activeChannel.send(e.target.result);
              if (file.size > offset + e.target.result.byteLength) {
                window.setTimeout(sliceFile, 0, offset + chunkSize);
              }
              sendProgress.value = offset + e.target.result.byteLength;
            };
          })(file);
          var slice = file.slice(offset, offset + chunkSize);
          reader.readAsArrayBuffer(slice);
        };
        sliceFile(0);
    }

/* Utilities */

    // set these to your own functions using WebRTCChat.writeToChatLog = function(...) {...}

    self.writeToChatLog = function(message, message_type, secure) {console.log("-> ", message, message_type, secure);}

    self.displayPartnerTyping = function() {console.log("-> Typing...");}
}
<commit_msg>disable video for now<commit_after>console.log('Confirm that this sends no outside network requests in the Network Panel.')

var receiveProgress = document.getElementById('receiveProgress')
var sendProgress = document.getElementById('sendProgress')
var bitrateDiv = document.getElementById('bitrate')
var statusMessage = document.getElementById('status')
var downloadsAnchor = document.getElementById('downloads')
var theirVideo = document.getElementById('theirVideo')
var myVideo = document.getElementById('myVideo')

function WebRTCChat(cfg, con, sendTyping) {
    var self = this;

/* WebRTC setup for broser-to-browser connection */
    self.cfg = {'iceServers':[{
      'url': 'stun:stun.l.google.com:19302'
    }]}; //{"url":"stun:23.21.150.121"}
    self.con = {'optional':  [{'DtlsSrtpKeyAgreement': true}] };
    self.activeChannel;
    self.activeConnection;
    self.roomName;

    self.readystate = false;
    self.sendTyping = true;

/* WebRTC + CHAT CONNECTION CODE */

    /* THE HOST (initiates the chat) */

    self.hostChat = function(offer_callback, ready_callback) {
        var hostConnection = new RTCPeerConnection(self.cfg, self.con);                                 // init connection
        self.initConnection(hostConnection, offer_callback);

        var hostChannel = hostConnection.createDataChannel('chat', {
            // reliable: true,
            // ordered: true
        });
        self.initChannel(hostChannel, ready_callback);

        // self.initVideo();

        console.log("Creating RTC Chat Host Offer...");
        hostConnection.createOffer(
            self.handleDescription,
            self.handleDescriptionFailure
            // {offerToReceiveAudio: true, offerToReceiveVideo: true}
        );
        // copy paste this offer to all clients who want to join
        // they paste their answer back, which goes into handleAnswerFromClient
    }

    self.handleAnswerFromClient = function(answer) {
        var answerDesc = new RTCSessionDescription(answer.rtc);
        console.log("Received Chat RTC Join Answer: ", answerDesc);
        self.activeConnection.setRemoteDescription(answerDesc);
        self.activeChannel.onopen()
        writeToChatLog("Started hosting a chat.", "text-success alert-success");

        // hostChannel.onopen will trigger once the connection is complete (enabling the chat window)
    }

    /* THE JOINEE (joins an existing chat) */

    self.joinChat = function(offer, answer_callback, ready_callback) {
        var clientConnection = new RTCPeerConnection(cfg, con);
        self.initConnection(clientConnection, answer_callback);

        self.activeConnection.ondatachannel = function (e) {                                     // once client receives a good data channel from the host
            // Chrome sends event, FF sends raw channel
            var clientChannel = e.channel || e;
            self.initChannel(clientChannel, ready_callback);
            self.activeChannel.onopen()
            writeToChatLog("Joined a chat.", "text-success alert-success");
            // clientChannel.onopen will then trigger once the connection is complete (enabling the chat window)
        };

        self.roomName = offer.roomName;

        var offerDesc = new RTCSessionDescription(offer.rtc);
        console.log("Received Chat RTC Host Offer: ", offerDesc);
        self.activeConnection.setRemoteDescription(offerDesc);

        // self.initVideo();

        console.log("Answering Chat Host Offer...");
        self.activeConnection.createAnswer(
            self.handleDescription,
            self.handleDescriptionFailure
            // {offerToReceiveAudio: true, offerToReceiveVideo: true}
        );

        // ondatachannel triggers once the client has accepted our answer ^
    }

    self.initConnection = function(conn, callback) {
        self.activeConnection = conn;
        // these aren't really necessary
        conn.onconnection                   = function (state) {console.info('Chat connection complete: ', event);}
        conn.onsignalingstatechange         = function (state) {console.info('Signaling state change: ', state); if (self.activeConnection.iceConnectionState == "disconnected") self.writeToChatLog("Chat partner disconnected.", "text-warning alert-error");}
        conn.oniceconnectionstatechange     = function (state) {console.info('Signaling ICE connection state change: ', state); if (self.activeConnection.iceConnectionState == "disconnected") self.writeToChatLog("Chat partner disconnected.", "text-warning alert-error");}
        conn.onicegatheringstatechange      = function (state) {console.info('Signaling ICE setup state change: ', state);}
        conn.onaddstream = function (event) {
            var video = theirVideo;
            if (window.URL)
                video.src = window.URL.createObjectURL(event.stream);
            else
                video.src = event.stream;
            console.log("You got their video!");
        }
        //this is the important one
        conn.onicecandidate = function (event) {
            // when browser has determined how to form a connection, generate offer or answer with ICE connection details and PGP public key
            if (event.candidate == null) {
                console.log("Valid ICE connection candidate determined.");
                var offer_or_answer = JSON.stringify({
                    rtc: self.activeConnection.localDescription,
                    roomName: self.roomName
                });
                // pass the offer or answer to the callback for display to the user or to send over some other communication channel
                if (callback) callback(offer_or_answer);
            }
        };
        conn.onfailure = function(details) {callback(details)};
        console.log("Initialized Connection: ", conn);
    }

    self.initChannel = function(chan, callback) {
        self.activeChannel = chan;
        self.activeChannel.binaryType = 'arraybuffer';
        // once the channel is open, trigger the callback to enable the chat window or carry out other logic
        self.activeChannel.onopen = function (e) {
            console.log('Data Channel Connected.');
            self.readystate = true;
            if (callback) callback(e);
        }
        chan.onmessage = self.receiveMessage;
        console.log("Initialized Data Channel: ", chan);
    }

    self.handleDescription = function(desc) {
        self.activeConnection.setLocalDescription(desc);
    }

    self.handleDescriptionFailure = function() {
        console.warn("Failed to create or answer chat offer.");
        self.activeConnection.onfailure("Invalid or expired chat offer. Please try again.")
    }

    // messaging functions

    self.sendTypingMessage = function() {
        self.activeChannel.send(JSON.stringify({message:null,typing:true}));
    }

    self.sendMessage = function(message) {
        self.activeChannel.send(JSON.stringify({message: message}));
        self.writeToChatLog(message, "text-success sent insecure", false);
    }

    self.receiveMessage = function(event) {
        try {
            var data = JSON.parse(event.data);
        } catch(e) {
            console.log('RECEIVING FILE')
            return self.receiveFile(event);
        }

        if (data.file) {
            return self.prepareToReceiveFile(data);
        }

        if (data.typing && !data.message) {
            console.log("Partner is typing...");
            self.displayPartnerTyping();
        }
        else {
            console.log("Received a message: ", data.message);
            self.writeToChatLog(data.message, "text-info recv", false);
        }
    }

    // Audio and Video

    self.initVideo = function() {
        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
        var video = myVideo;

        navigator.getUserMedia({
            audio: false,
            video: true
        }, function (stream) {
          if (window.URL)
            video.src = window.URL.createObjectURL(stream);
          else
            video.src = stream;
          window.myStream = stream;
          self.activeConnection.addStream(window.myStream);
            // self.activeChannel.send(JSON.stringify({
            //     message: "Started sharing video."
            // }));
            self.writeToChatLog(
                "Started sharing video.",
                "text-success sent insecure", false);
        }, function (error){
          console.log('navigator.getUserMedia error: ', error);
        });
    }

    // Files

    self.prepareToReceiveFile = function(data) {
        self.startTime = null;
        self.receiveBuffer = null;
        self.receivedSize = null;
        self.bitrateMax = null;
        self.numReceivedFiles = self.numReceivedFiles || 0;
        self.receivedFiles = self.receivedFiles || {};
        self.writeToChatLog(
            "Receiving " + data.name + " (" + data.size + " bytes)",
            "text-success sent insecure",
            false
        );
        self.numReceivedFiles += 1;
        // XSS out the wazoo
        var downloadLink = downloadsAnchor.innerHTML += (
            '
'
            + 'Download: ' + data.name + ''
            + " (" + data.size + " bytes)"
            + '
'
        )
        self.receivedFiles[data.name] = data;
        self.receivedFiles[data.name].id = self.numReceivedFiles;
        self.receivedFiles[data.name].anchor = document.getElementById('recvd-' + self.numReceivedFiles);
        self.incomingFile = self.receivedFiles[data.name]
    }

    self.receiveFile = function(event) {
        self.startTime = self.startTime || (new Date).getTime();
        self.receiveBuffer = self.receiveBuffer || [];
        self.receivedSize = self.receivedSize || 0;
        self.bitrateMax = self.bitrateMax || 0;

        self.receiveBuffer.push(event.data);
        self.receivedSize += event.data.byteLength;

        receiveProgress.value = self.receivedSize;

        // we are assuming that our signaling protocol told
        // about the expected file size (and name, hash, etc).
        var received = new window.Blob(self.receiveBuffer);
        self.receiveBuffer = [];

        var url = URL.createObjectURL(received);
        self.incomingFile.anchor.href = url;

        var bitrate = Math.round(self.receivedSize * 8 /
            ((new Date()).getTime() - self.startTime));

        if (bitrate > self.bitrateMax) {
            self.bitrateMax = bitrate;
        }

        bitrateDiv.innerHTML = 'Bitrate: ' +
            bitrate + ' kbits/sec (max: ' + self.bitrateMax + ' kbits/sec)';

        if (self.receivedSize >= self.incomingFile.size) {
            self.writeToChatLog(
                "Receiving " + self.incomingFile.name + " finished! Download it below.",
                "text-success sent insecure",
                false
            );
            self.activeChannel.send(JSON.stringify({
                message: 'Received ' + self.incomingFile.name + " succesfully.",
            }));
        } else {
            self.incomingFile.anchor.disabled = true;
        }
    }

    self.sendFile = function(files) {
        var file = [].concat.apply([], files).slice(-1)[0];
        console.log('File is ' + [file.name, file.size, file.type,
            file.lastModifiedDate
        ].join(' '));
        self.activeChannel.send(JSON.stringify({
            file: true,
            name: file.name,
            size: file.size,
        }));
        self.writeToChatLog("Sending " + file.name, "text-success sent insecure", false);

        // Handle 0 size files.
        statusMessage.textContent = '';
        if (file.size === 0) {
          bitrateDiv.innerHTML = '';
          statusMessage.textContent = 'File is empty, please select a non-empty file';
          return;
        }
        sendProgress.max = file.size;
        receiveProgress.max = file.size;
        var chunkSize = 16384;
        var sliceFile = function(offset) {
          var reader = new window.FileReader();
          reader.onload = (function() {
            return function(e) {
              self.activeChannel.send(e.target.result);
              if (file.size > offset + e.target.result.byteLength) {
                window.setTimeout(sliceFile, 0, offset + chunkSize);
              }
              sendProgress.value = offset + e.target.result.byteLength;
            };
          })(file);
          var slice = file.slice(offset, offset + chunkSize);
          reader.readAsArrayBuffer(slice);
        };
        sliceFile(0);
    }

/* Utilities */

    // set these to your own functions using WebRTCChat.writeToChatLog = function(...) {...}

    self.writeToChatLog = function(message, message_type, secure) {console.log("-> ", message, message_type, secure);}

    self.displayPartnerTyping = function() {console.log("-> Typing...");}
}
<|endoftext|>


<commit_before>
exports.bind = function(context, method/*, args... */) {
	var args = Array.prototype.slice.call(arguments, 2)
	return function() {
		fn = (typeof method == 'string' ? context[method] : method)
		return fn.apply(context, args.concat(Array.prototype.slice.call(arguments, 0)))
	}
}

exports.forEach = function(items, fn) {
	if (!items) { return }
	for (var i=0, item; item = items[i]; i++) { fn(item) }
}

exports.map = function(items, fn) {
	var results = []
	exports.forEach(items, function(item) { results.push(fn(item)) })
	return results
}

exports.Class = function(parent, proto) {
	if(!proto) { proto = parent }
	proto.prototype = parent.prototype

	var cls = function() { if(this.init) { this.init.apply(this, arguments) }}
	cls.prototype = new proto(function(context, method, args) {
		var target = parent
		while(target = target.prototype) {
			if(target[method]) {
				return target[method].apply(context, args || [])
			}
		}
		throw new Error('supr: parent method ' + method + ' does not exist')
	})

	// Sometimes you want a method that renders UI to only execute once if it's called
	// multiple times within a short time period. Delayed methods do just that
	cls.prototype.createDelayedMethod = function(methodName, fn) {
		var delayedExecution
		this[methodName] = function() {
			clearTimeout(delayedExecution)
			delayedExecution = setTimeout(bind(this, fn), 10)
		}
	}

	cls.prototype.constructor = cls
	return cls
}

exports.Singleton = function(parent, proto) {
	return new (exports.Class(parent, proto))()
}

var stripRegexp = /^\s*(.*?)\s*$/
exports.strip = function(str) {
	return str.match(stripRegexp)[1]
}

exports.capitalize = function(str) {
	return str[0].toUpperCase() + str.substring(1)
}

exports.isArray = function(obj) {
	return Object.prototype.toString.call(obj) === '[object Array]'
}<commit_msg>Allow passing in a context to execute the forEach function in<commit_after>
exports.bind = function(context, method/*, args... */) {
	var args = Array.prototype.slice.call(arguments, 2)
	return function() {
		fn = (typeof method == 'string' ? context[method] : method)
		return fn.apply(context, args.concat(Array.prototype.slice.call(arguments, 0)))
	}
}

exports.forEach = function(items, ctx, fn) {
	if (!items) { return }
	if (!fn) { fn = ctx, ctx = this }
	for (var i=0, item; item = items[i]; i++) { fn.call(ctx, item) }
}

exports.map = function(items, fn) {
	var results = []
	exports.forEach(items, function(item) { results.push(fn(item)) })
	return results
}

exports.Class = function(parent, proto) {
	if(!proto) { proto = parent }
	proto.prototype = parent.prototype

	var cls = function() { if(this.init) { this.init.apply(this, arguments) }}
	cls.prototype = new proto(function(context, method, args) {
		var target = parent
		while(target = target.prototype) {
			if(target[method]) {
				return target[method].apply(context, args || [])
			}
		}
		throw new Error('supr: parent method ' + method + ' does not exist')
	})

	// Sometimes you want a method that renders UI to only execute once if it's called
	// multiple times within a short time period. Delayed methods do just that
	cls.prototype.createDelayedMethod = function(methodName, fn) {
		var delayedExecution
		this[methodName] = function() {
			clearTimeout(delayedExecution)
			delayedExecution = setTimeout(bind(this, fn), 10)
		}
	}

	cls.prototype.constructor = cls
	return cls
}

exports.Singleton = function(parent, proto) {
	return new (exports.Class(parent, proto))()
}

var stripRegexp = /^\s*(.*?)\s*$/
exports.strip = function(str) {
	return str.match(stripRegexp)[1]
}

exports.capitalize = function(str) {
	if (!str) { return '' }
	return str[0].toUpperCase() + str.substring(1)
}

exports.isArray = function(obj) {
	return Object.prototype.toString.call(obj) === '[object Array]'
}<|endoftext|>