<commit_before>var oscar = (function(o, $) {

    o.getCsrfToken = function() {
        // Extract CSRF token from cookies
        var cookies = document.cookie.split(';');
        var csrf_token = null;
        $.each(cookies, function(index, cookie) {
            cookieParts = $.trim(cookie).split('=');
            if (cookieParts[0] == 'csrftoken') {
                csrfToken = cookieParts[1];
            }
        });
        return csrfToken;
    };

    o.dashboard = {
        init: function(options) {
            // Run initialisation that should take place on every page of the dashboard.
            var defaults = {
                'languageCode': 'en',
                'dateFormat': 'yy-mm-dd',
                'timeFormat': 'hh:ii',
                'datetimeFormat': 'yy-mm-dd hh:ii',
                'stepMinute': 15,
                'tinyConfig': {
                    statusbar: false,
                    menubar: false,
                    plugins: "link",
                    style_formats: [
                        {title: 'Heading', block: 'h2'},
                        {title: 'Subheading', block: 'h3'}
                    ],
                    toolbar: "styleselect | bold italic blockquote | bullist numlist | link"
                }
            };
            o.dashboard.options = $.extend(true, defaults, options);

            o.dashboard.initWidgets(window.document);
            o.dashboard.initForms();

            $(".category-select ul").prev('a').on('click', function(){
                var $this = $(this),
                plus = $this.hasClass('ico_expand');
                if (plus) {
                    $this.removeClass('ico_expand').addClass('ico_contract');
                } else {
                    $this.removeClass('ico_contract').addClass('ico_expand');
                }
                return false;
            });

            // Adds error icon if there are errors in the product update form
            $('[data-behaviour="affix-nav-errors"] .tab-pane').each(function(){
              var productErrorListener = $(this).find('[class*="error"]:not(:empty)').closest('.tab-pane').attr('id');
              $('[data-spy="affix"] a[href="#' + productErrorListener + '"]').append('');
            });

            o.dashboard.filereader.init();
        },
        initWidgets: function(el) {
            /** Attach widgets to form input.
             *
             * This function is called once for the whole page. In that case el is window.document.
             *
             * It is also called when input elements have been dynamically added. In that case el
             * contains the newly added elements.
             *
             * If the element selector refers to elements that may be outside of newly added
             * elements, don't limit to elements within el. Then the operation will be performed
             * twice for these elements. Make sure that that is harmless.
             */
            o.dashboard.initDatePickers(el);
            o.dashboard.initMasks(el);
            o.dashboard.initWYSIWYG(el);
            o.dashboard.initSelects(el);
        },
        initMasks: function(el) {
            $(el).find(':input').inputmask()
        },
        initSelects: function(el) {
            // Adds type/search for select fields
            var $selects = $(el).find('select').not('.no-widget-init select').not('.no-widget-init');
            $selects.select2({width: 'resolve'});
            $(el).find('input.select2').each(function(i, e) {
                var opts = {};
                if($(e).data('ajax-url')) {
                    opts = {
                        'ajax': {
                            'url': $(e).data('ajax-url'),
                            'dataType': 'json',
                            'results': function(data, page) {
                                if((page==1) && !($(e).data('required')=='required')) {
                                    data.results.unshift({'id': '', 'text': '------------'});
                                }
                                return data;
                            },
                            'data': function(term, page) {
                                return {
                                    'q': term,
                                    'page': page
                                };
                            }
                        },
                        'multiple': $(e).data('multiple'),
                        'initSelection': function(e, callback){
                            if($(e).val()) {
                                $.ajax({
                                    'type': 'GET',
                                    'url': $(e).data('ajax-url'),
                                    'data': [{'name': 'initial', 'value': $(e).val()}],
                                    'success': function(data){
                                        if(data.results) {
                                            if($(e).data('multiple')){
                                                callback(data.results);
                                            } else {
                                                callback(data.results[0]);
                                            }
                                        }
                                    },
                                    'dataType': 'json'
                                });
                            }
                        }
                    };
                }
                $(e).select2(opts);
            });
        },
        initDatePickers: function(el) {
            if (!$.fn.datetimepicker) {
                return;
            }
            var initDatePicker = function(ele) {
                ele = $(ele);
                var defaultDatepickerConfig = {
                    'format': o.dashboard.options.dateFormat,
                    'autoclose': true,
                    'language': o.dashboard.options.languageCode,
                    'minView': 2
                };
                var config = $.extend({}, defaultDatepickerConfig, {
                        'format': ele.data('dateformat')
                    });
                ele.datetimepicker(config);
                ele.addClass('oscarWidgetInitialized');
            };
            var initTimePicker = function(ele) {
                ele = $(ele);
                var defaultTimepickerConfig = {
                    'format': o.dashboard.options.timeFormat,
                    'minuteStep': o.dashboard.options.stepMinute,
                    'autoclose': true,
                    'language': o.dashboard.options.languageCode
                };
                var config = $.extend({}, defaultTimepickerConfig, {
                      'format': ele.data('timeformat'),
                      'minuteStep': ele.data('stepminute'),
                      'startView': 1,
                      'maxView': 1,
                      'formatViewType': 'time'
                    });
                ele.datetimepicker(config);
                ele.addClass('oscarWidgetInitialized');
            };
            var initDatetimePicker = function(ele) {
                ele = $(ele);
                var defaultDatetimepickerConfig = {
                    'format': o.dashboard.options.datetimeFormat,
                    'minuteStep': o.dashboard.options.stepMinute,
                    'autoclose': true,
                    'language': o.dashboard.options.languageCode
                };

                var config = $.extend({}, defaultDatetimepickerConfig, {
                      'format': ele.data('datetimeformat'),
                      'minuteStep': ele.data('stepminute')
                    });
                ele.datetimepicker(config);
                ele.addClass('oscarWidgetInitialized');
            };

            var dateWidgetSelector = '[data-oscarWidget="date"]:not(.oscarWidgetInitialized):not(.no-widget-init):not(no-widget-init *)';
            var timeWidgetSelector = '[data-oscarWidget="time"]:not(.oscarWidgetInitialized):not(.no-widget-init):not(no-widget-init *)';
            var datetimeWidgetSelector = '[data-oscarWidget="datetime"]:not(.oscarWidgetInitialized):not(.no-widget-init):not(no-widget-init *)';
            if (el == window.document) {
                // if this wants to initialize all widgets for the whole document, then
                // we delegate the initialization to the first time a mouse moves over the
                // widget, so the initialization on page load is fast
                $(el).on("mouseover", dateWidgetSelector, function() {
                    initDatePicker(this);
                });
                $(el).on("mouseover", timeWidgetSelector, function() {
                    initTimePicker(this);
                });
                $(el).on("mouseover", datetimeWidgetSelector, function() {
                    initDatetimePicker(this);
                });
            } else {
                // however, if a specific dom node is given, then we need to initialize
                // the element(s) present in that node immediately, as they likely are
                // being used by JS code right after
                $(el).find(dateWidgetSelector).each(function(ind, ele) {
                    initDatePicker(ele);
                });
                $(el).find(timeWidgetSelector).each(function(ind, ele) {
                    initTimePicker(ele);
                });
                $(el).find(datetimeWidgetSelector).each(function(ind, ele) {
                    initDatetimePicker(ele);
                });
            }
        },
        initWYSIWYG: function(el) {
            // Use TinyMCE by default
            $textareas = $(el).find('textarea').not('.no-widget-init textarea').not('.no-widget-init');
            $textareas.filter('form.wysiwyg textarea').tinymce(o.dashboard.options.tinyConfig);
            $textareas.filter('.wysiwyg').tinymce(o.dashboard.options.tinyConfig);
        },
        initForms: function() {
            // Disable buttons when they are clicked and show a "loading" message taken from the
            // data-loading-text attribute (http://getbootstrap.com/2.3.2/javascript.html#buttons).
            // Do not disable if button is inside a form with invalid fields.
            // This uses a delegated event so that it keeps working for forms that are reloaded
            // via AJAX: https://api.jquery.com/on/#direct-and-delegated-events
            $(document.body).on('click', '[data-loading-text]', function(){
                var form = $(this).parents("form");
                if (!form || $(":invalid", form).length == 0)
                    $(this).button('loading');
            });
        },
        offers: {
            init: function() {
                oscar.dashboard.offers.adjustBenefitForm();
                $('#id_type').change(function() {
                    oscar.dashboard.offers.adjustBenefitForm();
                });
            },
            adjustBenefitForm: function() {
                var type = $('#id_type').val(),
                    $valueContainer = $('#id_value').parents('.control-group');
                if (type == 'Multibuy') {
                    $('#id_value').val('');
                    $valueContainer.hide();
                } else {
                    $valueContainer.show();
                }
            }
        },
        ranges: {
            init: function() {
                $('[data-behaviours~="remove"]').click(function() {
                    $this = $(this);
                    $this.parents('table').find('input').attr('checked', false);
                    $this.parents('tr').find('input').attr('checked', 'checked');
                    $this.parents('form').submit();
                });
            }
        },
        orders: {
            initTabs: function() {
                if (location.hash) {
                    $('.nav-tabs a[href=' + location.hash + ']').tab('show');
                }
            },
            initTable: function() {
                var table = $('form table'),
                    input = $('<input type="checkbox" />').css({
                        'margin-right': '5px',
                        'vertical-align': 'top'
                    });
                $('th:first', table).prepend(input);
                $(input).change(function(){
                    $('tr', table).each(function() {
                        $('td:first input', this).prop("checked", $(input).is(':checked'));
                    });
                });
            }
        },
        reordering: (function() {
            var options = {
                handle: '.btn-handle',
                submit_url: '#'
            },
            saveOrder = function(event, ui) {
                // Get the csrf token, otherwise django will not accept the
                // POST request.
                var serial = $(this).sortable("serialize"),
                    csrf = o.getCsrfToken();
                serial = serial + '&csrfmiddlewaretoken=' + csrf;
                $.ajax({
                    type: 'POST',
                    data: serial,
                    dataType: "json",
                    url: options.submit_url,
                    beforeSend: function(xhr, settings) {
                        xhr.setRequestHeader("X-CSRFToken", csrf);
                    }
                });
            },
            init = function(user_options) {
                options = $.extend(options, user_options);
                $(options.wrapper).sortable({
                    handle: options.handle,
                    stop: saveOrder
                });
            };

            return {
                init: init,
                saveOrder: saveOrder
            };
        }()),
        search: {
            init: function() {
                var searchForm = $(".orders_search"),
                    searchLink = $('.pull_out'),
                    doc = $('document');
                searchForm.each(function(index) {
                    doc.css('height', doc.height());
                });
                searchLink.on('click', function() {
                    searchForm.parent()
                        .find('.pull-left')
                        .toggleClass('no-float')
                        .end().end()
                        .slideToggle("fast");
                    }
                );
            }
        },
        filereader: {
            init: function() {
                // Add local file loader to update image files on change in
                // dashboard. This will provide a preview to the selected
                // image without uploading it. Upload only occures when
                // submitting the form.
                if (window.FileReader) {
                    $('input[type="file"]').change(function(evt) {
                        var reader = new FileReader();
                        var imgId = evt.target.id + "-image";
                        reader.onload = (function() {
                            return function(e) {
                                var imgDiv = $("#"+imgId);
                                imgDiv.children('img').attr('src', e.target.result);
                            };
                        })();
                        reader.readAsDataURL(evt.target.files[0]);
                    });
                }
            }
        }
    };

    return o;

})(oscar || {}, jQuery);
<commit_msg>Revert dashboard.js to 533207f version<commit_after>var oscar = (function(o, $) {

    o.getCsrfToken = function() {
        // Extract CSRF token from cookies
        var cookies = document.cookie.split(';');
        var csrf_token = null;
        $.each(cookies, function(index, cookie) {
            cookieParts = $.trim(cookie).split('=');
            if (cookieParts[0] == 'csrftoken') {
                csrfToken = cookieParts[1];
            }
        });
        return csrfToken;
    };

    o.dashboard = {
        init: function(options) {
            // Run initialisation that should take place on every page of the dashboard.
            var defaults = {
                'languageCode': 'en',
                'dateFormat': 'yy-mm-dd',
                'timeFormat': 'hh:ii',
                'datetimeFormat': 'yy-mm-dd hh:ii',
                'stepMinute': 15,
                'tinyConfig': {
                    statusbar: false,
                    menubar: false,
                    plugins: "link",
                    style_formats: [
                        {title: 'Heading', block: 'h2'},
                        {title: 'Subheading', block: 'h3'}
                    ],
                    toolbar: "styleselect | bold italic blockquote | bullist numlist | link"
                }
            };
            o.dashboard.options = $.extend(true, defaults, options);

            o.dashboard.initWidgets(window.document);
            o.dashboard.initForms();

            $(".category-select ul").prev('a').on('click', function(){
                var $this = $(this),
                plus = $this.hasClass('ico_expand');
                if (plus) {
                    $this.removeClass('ico_expand').addClass('ico_contract');
                } else {
                    $this.removeClass('ico_contract').addClass('ico_expand');
                }
                return false;
            });

            // Adds error icon if there are errors in the product update form
            $('[data-behaviour="affix-nav-errors"] .tab-pane').each(function(){
              var productErrorListener = $(this).find('[class*="error"]:not(:empty)').closest('.tab-pane').attr('id');
              $('[data-spy="affix"] a[href="#' + productErrorListener + '"]').append('');
            });

            o.dashboard.filereader.init();
        },
        initWidgets: function(el) {
            /** Attach widgets to form input.
             *
             * This function is called once for the whole page. In that case el is window.document.
             *
             * It is also called when input elements have been dynamically added. In that case el
             * contains the newly added elements.
             *
             * If the element selector refers to elements that may be outside of newly added
             * elements, don't limit to elements within el. Then the operation will be performed
             * twice for these elements. Make sure that that is harmless.
             */
            o.dashboard.initDatePickers(el);
            o.dashboard.initMasks(el);
            o.dashboard.initWYSIWYG(el);
            o.dashboard.initSelects(el);
        },
        initMasks: function(el) {
            $(el).find(':input').inputmask()
        },
        initSelects: function(el) {
            // Adds type/search for select fields
            var $selects = $(el).find('select').not('.no-widget-init select').not('.no-widget-init');
            $selects.select2({width: 'resolve'});
            $(el).find('input.select2').each(function(i, e) {
                var opts = {};
                if($(e).data('ajax-url')) {
                    opts = {
                        'ajax': {
                            'url': $(e).data('ajax-url'),
                            'dataType': 'json',
                            'results': function(data, page) {
                                if((page==1) && !($(e).data('required')=='required')) {
                                    data.results.unshift({'id': '', 'text': '------------'});
                                }
                                return data;
                            },
                            'data': function(term, page) {
                                return {
                                    'q': term,
                                    'page': page
                                };
                            }
                        },
                        'multiple': $(e).data('multiple'),
                        'initSelection': function(e, callback){
                            if($(e).val()) {
                                $.ajax({
                                    'type': 'GET',
                                    'url': $(e).data('ajax-url'),
                                    'data': [{'name': 'initial', 'value': $(e).val()}],
                                    'success': function(data){
                                        if(data.results) {
                                            if($(e).data('multiple')){
                                                callback(data.results);
                                            } else {
                                                callback(data.results[0]);
                                            }
                                        }
                                    },
                                    'dataType': 'json'
                                });
                            }
                        }
                    };
                }
                $(e).select2(opts);
            });
        },
        initDatePickers: function(el) {
            if ($.fn.datetimepicker) {
                var defaultDatepickerConfig = {
                    'format': o.dashboard.options.dateFormat,
                    'autoclose': true,
                    'language': o.dashboard.options.languageCode,
                    'minView': 2
                };
                $dates = $(el).find('[data-oscarWidget="date"]').not('.no-widget-init').not('.no-widget-init *')
                $dates.each(function(ind, ele) {
                    var $ele = $(ele),
                        config = $.extend({}, defaultDatepickerConfig, {
                            'format': $ele.data('dateformat')
                        });
                    $ele.datetimepicker(config);
                    $ele.find('input').css('width', '125px');
                });

                var defaultDatetimepickerConfig = {
                    'format': o.dashboard.options.datetimeFormat,
                    'minuteStep': o.dashboard.options.stepMinute,
                    'autoclose': true,
                    'language': o.dashboard.options.languageCode
                };
                $datetimes = $(el).find('[data-oscarWidget="datetime"]').not('.no-widget-init').not('.no-widget-init *')
                $datetimes.each(function(ind, ele) {
                    var $ele = $(ele),
                        config = $.extend({}, defaultDatetimepickerConfig, {
                          'format': $ele.data('datetimeformat'),
                          'minuteStep': $ele.data('stepminute')
                        });
                    $ele.datetimepicker(config);
                    $ele.find('input').css('width', '125px');
                });

                var defaultTimepickerConfig = {
                    'format': o.dashboard.options.timeFormat,
                    'minuteStep': o.dashboard.options.stepMinute,
                    'autoclose': true,
                    'language': o.dashboard.options.languageCode
                };
                $times = $(el).find('[data-oscarWidget="time"]').not('.no-widget-init').not('.no-widget-init *')
                $times.each(function(ind, ele) {
                    var $ele = $(ele),
                        config = $.extend({}, defaultTimepickerConfig, {
                          'format': $ele.data('timeformat'),
                          'minuteStep': $ele.data('stepminute'),
                          'startView': 1,
                          'maxView': 1,
                          'formatViewType': 'time'
                        });
                    $ele.datetimepicker(config);
                    $ele.find('input').css('width', '125px');
                });
            }
        },
        initWYSIWYG: function(el) {
            // Use TinyMCE by default
            $textareas = $(el).find('textarea').not('.no-widget-init textarea').not('.no-widget-init');
            $textareas.filter('form.wysiwyg textarea').tinymce(o.dashboard.options.tinyConfig);
            $textareas.filter('.wysiwyg').tinymce(o.dashboard.options.tinyConfig);
        },
        initForms: function() {
            // Disable buttons when they are clicked and show a "loading" message taken from the
            // data-loading-text attribute (http://getbootstrap.com/2.3.2/javascript.html#buttons).
            // Do not disable if button is inside a form with invalid fields.
            // This uses a delegated event so that it keeps working for forms that are reloaded
            // via AJAX: https://api.jquery.com/on/#direct-and-delegated-events
            $(document.body).on('click', '[data-loading-text]', function(){
                var form = $(this).parents("form");
                if (!form || $(":invalid", form).length == 0)
                    $(this).button('loading');
            });
        },
        offers: {
            init: function() {
                oscar.dashboard.offers.adjustBenefitForm();
                $('#id_type').change(function() {
                    oscar.dashboard.offers.adjustBenefitForm();
                });
            },
            adjustBenefitForm: function() {
                var type = $('#id_type').val(),
                    $valueContainer = $('#id_value').parents('.control-group');
                if (type == 'Multibuy') {
                    $('#id_value').val('');
                    $valueContainer.hide();
                } else {
                    $valueContainer.show();
                }
            }
        },
        ranges: {
            init: function() {
                $('[data-behaviours~="remove"]').click(function() {
                    $this = $(this);
                    $this.parents('table').find('input').attr('checked', false);
                    $this.parents('tr').find('input').attr('checked', 'checked');
                    $this.parents('form').submit();
                });
            }
        },
        orders: {
            initTabs: function() {
                if (location.hash) {
                    $('.nav-tabs a[href=' + location.hash + ']').tab('show');
                }
            },
            initTable: function() {
                var table = $('form table'),
                    input = $('<input type="checkbox" />').css({
                        'margin-right': '5px',
                        'vertical-align': 'top'
                    });
                $('th:first', table).prepend(input);
                $(input).change(function(){
                    $('tr', table).each(function() {
                        $('td:first input', this).prop("checked", $(input).is(':checked'));
                    });
                });
            }
        },
        reordering: (function() {
            var options = {
                handle: '.btn-handle',
                submit_url: '#'
            },
            saveOrder = function(event, ui) {
                // Get the csrf token, otherwise django will not accept the
                // POST request.
                var serial = $(this).sortable("serialize"),
                    csrf = o.getCsrfToken();
                serial = serial + '&csrfmiddlewaretoken=' + csrf;
                $.ajax({
                    type: 'POST',
                    data: serial,
                    dataType: "json",
                    url: options.submit_url,
                    beforeSend: function(xhr, settings) {
                        xhr.setRequestHeader("X-CSRFToken", csrf);
                    }
                });
            },
            init = function(user_options) {
                options = $.extend(options, user_options);
                $(options.wrapper).sortable({
                    handle: options.handle,
                    stop: saveOrder
                });
            };

            return {
                init: init,
                saveOrder: saveOrder
            };
        }()),
        search: {
            init: function() {
                var searchForm = $(".orders_search"),
                    searchLink = $('.pull_out'),
                    doc = $('document');
                searchForm.each(function(index) {
                    doc.css('height', doc.height());
                });
                searchLink.on('click', function() {
                    searchForm.parent()
                        .find('.pull-left')
                        .toggleClass('no-float')
                        .end().end()
                        .slideToggle("fast");
                    }
                );
            }
        },
        filereader: {
            init: function() {
                // Add local file loader to update image files on change in
                // dashboard. This will provide a preview to the selected
                // image without uploading it. Upload only occures when
                // submitting the form.
                if (window.FileReader) {
                    $('input[type="file"]').change(function(evt) {
                        var reader = new FileReader();
                        var imgId = evt.target.id + "-image";
                        reader.onload = (function() {
                            return function(e) {
                                var imgDiv = $("#"+imgId);
                                imgDiv.children('img').attr('src', e.target.result);
                            };
                        })();
                        reader.readAsDataURL(evt.target.files[0]);
                    });
                }
            }
        }
    };

    return o;

})(oscar || {}, jQuery);
<|endoftext|>


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

  function handler () {
    $.removeNodes('iframe');

    var node = $.$('#continuetoimage > form input');
    if (node) {
      // first pass
      node.click();
      // somehow imgrun.net need to click twice
      node.click();
      return;
    }

    // second pass
    var o = $('img[alt="image"]');
    $.openImage(o.src);
  }

  $.register({
    rule: [
      {
        host: [
          /^img(rill|next|savvy|\.spicyzilla|twyti|xyz|devil|seeds|tzar|ban)\.com$/,
          /^image(corn|picsa)\.com$/,
          /^www\.(imagefolks|imgblow)\.com$/,
          /^img-(zone|planet)\.com$/,
          /^(hosturimage|erimge)\.com$/,
          /^(img(candy|master|-view|run)|imagelaser)\.net$/,
          /^imgcloud\.co$/,
          /^pixup\.us$/,
          /^(www\.)?\.imgult\.com$/,
          /^bulkimg\.info$/,
          /^(image\.adlock|imgspot|teenshot)\.org$/,
          /^img\.yt$/,
          /^vava\.in$/,
          /^55888\.eu$/,
          /^pixxx\.me$/,
          /^(like\.)08lkk\.com$/,
        ],
        path: /^\/img-.*\.html$/,
      },
      {
        host: /^imgking\.co$/,
        path: /^\/img-.*\.htmls$/,
      },
      {
        host: /^imgtwyti\.com$/,
        path: /^\/t\/img-.*\.html$/,
      },
    ],
    ready: handler,
  });

  $.register({
    rule: {
      host: /^08lkk\.com$/,
      path: /^\/\d+\/img-.*\.html$/,
    },
    start: function () {
      // crack the shitty qqc.co visitScript 5440
      $.window.setTimeout = _.nop;

      // this site checks cookie that caculate from session
      // do an AJAX to skip checking
      $.get(window.location.toString()).then(function (data) {
        var a = $.toDOM(data);

        var bbcode = $.$('#imagecodes input', a);
        bbcode = bbcode.value.match(/.+\[IMG\]([^\[]+)\[\/IMG\].+/);
        bbcode = bbcode[1];
        bbcode = bbcode.replace('small', 'big');

        $.openImage(bbcode);
      });
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<commit_msg>imgseeds.com<commit_after>(function () {
  'use strict';

  function handler () {
    $.removeNodes('iframe');

    var node = $.$('#continuetoimage > form input');
    if (node) {
      // first pass
      node.click();
      // somehow imgrun.net need to click twice
      node.click();
      return;
    }

    // second pass
    var o = $('img[alt="image"]');
    $.openImage(o.src);
  }

  $.register({
    rule: [
      {
        host: [
          /^img(rill|next|savvy|\.spicyzilla|twyti|xyz|devil|tzar|ban)\.com$/,
          /^image(corn|picsa)\.com$/,
          /^www\.(imagefolks|imgblow)\.com$/,
          /^img-(zone|planet)\.com$/,
          /^(hosturimage|erimge)\.com$/,
          /^(img(candy|master|-view|run)|imagelaser)\.net$/,
          /^imgcloud\.co$/,
          /^pixup\.us$/,
          /^(www\.)?\.imgult\.com$/,
          /^bulkimg\.info$/,
          /^(image\.adlock|imgspot|teenshot)\.org$/,
          /^img\.yt$/,
          /^vava\.in$/,
          /^55888\.eu$/,
          /^pixxx\.me$/,
          /^(like\.)08lkk\.com$/,
          /imgseeds\.com$/,
        ],
        path: /^\/img-.*\.html$/,
      },
      {
        host: /^imgking\.co$/,
        path: /^\/img-.*\.htmls$/,
      },
      {
        host: /^imgtwyti\.com$/,
        path: /^\/t\/img-.*\.html$/,
      },
    ],
    ready: handler,
  });

  $.register({
    rule: {
      host: /^08lkk\.com$/,
      path: /^\/\d+\/img-.*\.html$/,
    },
    start: function () {
      // crack the shitty qqc.co visitScript 5440
      $.window.setTimeout = _.nop;

      // this site checks cookie that caculate from session
      // do an AJAX to skip checking
      $.get(window.location.toString()).then(function (data) {
        var a = $.toDOM(data);

        var bbcode = $.$('#imagecodes input', a);
        bbcode = bbcode.value.match(/.+\[IMG\]([^\[]+)\[\/IMG\].+/);
        bbcode = bbcode[1];
        bbcode = bbcode.replace('small', 'big');

        $.openImage(bbcode);
      });
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<|endoftext|>


<commit_before>// Properties
var jobs = [];
var lastPushes = [];

// Schedule a job, i.e. a signage item
function scheduleJob(path, schedule, channel) {
  var job = new cronJob(schedule, function(){
    emitContent(path, channel, function () {
      lastPush(path, channel)
    })
  }, null, true, null);
  return job;
}

// Broadcast a signage item
function emitContent(file, channel, callback) {
  fs.readFile(__dirname + file, function (err, buf) {
      logging.log('Broadcasting ' + file + ' to the ' + channel + ' channel (' + Date().toLocaleString() + ')');
      io.sockets.in(channel).emit('content_push', { image: true, buffer: buf });

      if (callback && typeof(callback) === "function"){
        callback();
      }
  });
}

// Iterate through schedule.json, call scheduling and build job array
function load(scheduleFile) {
  if(scheduleFile){
    fs.readFile(scheduleFile, function (err, data) {
      var schedule = JSON.parse(data);
      for (item in schedule) {
        if (schedule.hasOwnProperty(item)) {
          job = scheduleJob(schedule[item].path, schedule[item].schedule, schedule[item].channel);
          jobs.push(job);
        }
      }
      logging.log("Schedule loaded");
    })
  }
}

// Cancel schedule
function cancel(callback) {
  if (jobs){
    try {
      for (i = 0; i < jobs.length; i++) {
        jobs[i].stop();
      }
    } catch (err) {
      logging.log(err);
    }

    if (callback && typeof(callback) === "function"){
      callback();
    }
  }
}

// Watch for schedule changes
function reloadOnChange(scheduleFile){
  fs.watchFile(scheduleFile, function(current, previous){
    logging.log("Schedule changed");
    cancel(function () {
      load(scheduleFile);
    });
  })
}

// Record last push for each channel
function lastPush(path, channel) {
  var channelExits = false;
  try {
    if (lastPushes.length > 0) {
      for (var i = 0; i < lastPushes.length; i++) {
        if (lastPushes[i][1] == channel) {
          channelExits = true;
          lastPushes[i][0] == path
        }
      }

      if (!channelExits) {
        lastPushes.push([path,channel]);
      }
    } else {
      //console.log('adding ' + channel);
      lastPushes.push([path,channel]);
    }
  } catch (err) {
    logging.log(err)
  }
}

// Syncronize a client
function clientSync(channel, clientId) {
  var file;
  if (lastPushes.length > 0) {
    for (var i = 0; i < lastPushes.length; i++) {
      if (lastPushes[i][1] == channel) {
        file = lastPushes[i][0];
        fs.readFile(__dirname + file, function (err, buf) {
            logging.log('Syncronizing client with ' + file + ' on the ' + channel + ' channel (' + Date().toLocaleString() + ')');
            io.to(clientId).emit('content_push', { image: true, buffer: buf });
        });
      }
    }
  }
}

module.exports.load = load;
module.exports.reloadOnChange = reloadOnChange;
module.exports.clientSync = clientSync;
<commit_msg>added new client sync<commit_after>// Properties
var jobs = [];
var lastPushes = [];

// Schedule a job, i.e. a signage item
function scheduleJob(path, schedule, channel) {
  var job = new cronJob(schedule, function(){
    emitContent(path, channel, function () {
      lastPush(path, channel)
    })
  }, null, true, null);
  return job;
}

// Broadcast a signage item
function emitContent(file, channel, callback) {
  fs.readFile(__dirname + file, function (err, buf) {
      logging.log('Broadcasting ' + file + ' to the ' + channel + ' channel (' + Date().toLocaleString() + ')');
      io.sockets.in(channel).emit('content_push', { image: true, buffer: buf });

      if (callback && typeof(callback) === "function"){
        callback();
      }
  });
}

// Iterate through schedule.json, call scheduling and build job array
function load(scheduleFile) {
  if(scheduleFile){
    fs.readFile(scheduleFile, function (err, data) {
      var schedule = JSON.parse(data);
      for (item in schedule) {
        if (schedule.hasOwnProperty(item)) {
          job = scheduleJob(schedule[item].path, schedule[item].schedule, schedule[item].channel);
          jobs.push(job);
        }
      }
      logging.log("Schedule loaded");
    })
  }
}

// Cancel schedule
function cancel(callback) {
  if (jobs){
    try {
      for (i = 0; i < jobs.length; i++) {
        jobs[i].stop();
      }
    } catch (err) {
      logging.log(err);
    }

    if (callback && typeof(callback) === "function"){
      callback();
    }
  }
}

// Watch for schedule changes
function reloadOnChange(scheduleFile){
  fs.watchFile(scheduleFile, function(current, previous){
    logging.log("Schedule changed");
    cancel(function () {
      load(scheduleFile);
    });
  })
}

// Record last push for each channel
function lastPush(path, channel) {
  var channelExits = false;
  try {
    if (lastPushes.length > 0) {
      for (var i = 0; i < lastPushes.length; i++) {
        if (lastPushes[i][1] == channel) {
          channelExits = true;
          lastPushes[i][0] == path
        }
      }

      if (!channelExits) {
        lastPushes.push([path,channel]);
      }
    } else {
      lastPushes.push([path,channel]);
    }
  } catch (err) {
    logging.log(err)
  }
}

// Syncronize a client
function clientSync(channel, clientId) {
  var file;
  if (lastPushes.length > 0) {
    for (var i = 0; i < lastPushes.length; i++) {
      if (lastPushes[i][1] == channel) {
        file = lastPushes[i][0];
        fs.readFile(__dirname + file, function (err, buf) {
            logging.log('Syncronizing client with ' + file + ' on the ' + channel + ' channel (' + Date().toLocaleString() + ')');
            io.to(clientId).emit('content_push', { image: true, buffer: buf });
        });
      }
    }
  }
}

module.exports.load = load;
module.exports.reloadOnChange = reloadOnChange;
module.exports.clientSync = clientSync;
<|endoftext|>


<commit_before>define(
  'ephox.echo.api.AriaRegister',

  [
    'ephox.classify.Type',
    'ephox.compass.Arr',
    'ephox.compass.Obj',
    'ephox.echo.api.Styles',
    'ephox.epithet.Id',
    'ephox.highway.Merger',
    'ephox.peanut.Fun',
    'ephox.sugar.api.Attr',
    'ephox.sugar.api.Class',
    'ephox.sugar.api.Element',
    'ephox.sugar.api.Insert',
    'ephox.sugar.api.InsertAll'
  ],

  function (Type, Arr, Obj, Styles, Id, Merger, Fun, Attr, Class, Element, Insert, InsertAll) {
    var helpStyle = Styles.resolve('aria-help');
    var helpVisibleStyle = Styles.resolve('aria-help-visible');

    var roleDocument = function (element) {
      Attr.set(element, 'role', 'document');
    };

    var presentation = function (element) {
      Attr.setAll(element, {
        'role': 'presentation',
        'aria-hidden': 'true'
      });
    };

    // https://www.w3.org/TR/wai-aria/roles#presentation
    var presentationRole = function (element) {
      Attr.set(element, 'role', 'presentation');
    };

    var editor = function (container, editor, label, ariaHelp, showHelpHint) {
      // Set role=region: https://www.w3.org/TR/wai-aria/roles#region
      // on editor for better user navigation modes, as it is mostly text content.
      // Better than role=application which constrains the reader navigation
      // - https://www.w3.org/TR/wai-aria/roles#application
      Attr.setAll(container, {
        'role': 'region',
        'aria-label': label
      });

      ariaHelp.each(function (helpText) {
        var aria = Element.fromTag('span');
        presentationRole(aria);
        Insert.append(aria, Element.fromText(helpText));
        var labelId = Id.generate('ephox-aria');
        Attr.set(aria, 'id', labelId);
        describedBy(editor, labelId);
        Class.add(aria, helpStyle);
        if (showHelpHint === true) Class.add(aria, helpVisibleStyle);
        Insert.append(container, aria);
      });

      // content attributes - surprisingly helps in both classic and inline
      var attrs = {
        'aria-multiline': 'true',
        'aria-label': label,
        title: label
      };

      Attr.setAll(editor, attrs);

      var destroy = function () {
        var removeFromEditor = Fun.curry(Attr.remove, editor);
        Arr.each(Obj.keys(attrs), removeFromEditor);
        removeFromEditor('aria-describedby');
      };

      return {
        destroy: destroy
      };
    };

    // Set the role 'group'
    var group = function (element) {
      Attr.set(element, 'role', 'group');
    };

    // Sets the role 'group', with a label
    var toolbar = function (element, label) {
      Attr.setAll(element, {
        'role': 'group',
        'aria-label': label
      });
    };

    var menu = function (element, label) {
      Attr.setAll(element, {
        'aria-label': label,
        'role': 'menu'
      });
    };

    var textButton = function (element, contentElement) {
      // Add 'button' roleto a pastry button, and 'presentation' role
      // to the contentElement that contains the button text.
      Attr.set(element, 'role', 'button');
      presentationRole(contentElement);
    };

    // Set the role 'button'
    var toolbarButton = function (element, label, hasPopup, isToggle) {
      Attr.setAll(element, {
        'role': 'button',
        'aria-label': label,
        'aria-haspopup': '' + hasPopup
      });
      if (isToggle) Attr.set(element, 'aria-pressed', 'false');
      if (hasPopup) Attr.set(element, 'aria-expanded', 'false');
    };

    // Set the role 'toolbar' and aria-label if provided
    var toolbarGroup = function (element, label) {
      // TODO: duplicated from 'ephox.polish.alien.Query', consolidate isEmpty();
      var isEmpty = function (val) {
        // TODO: Move to compass Arr and violin Strings
        return (val === null) || (val === undefined) || (val === '') || (Type.isArray(val) && val.length === 0);
      };
      // End TODO

      Attr.set(element, 'role', 'toolbar');

      // customer groups may have empty label, don't use it
      if (!isEmpty(label)) {
        Attr.set(element, 'aria-label', label);
      }
    };

    var menuItem = function (element, label, hasPopup) {
      var labelTxt = label.map(function (txt) {
        return { 'aria-label': txt };
      }).getOr({});

      Attr.setAll(element, Merger.merge(labelTxt, {
        'role': 'menuitem',
        'aria-haspopup': hasPopup.getOr(false)
      }));
    };

    var menuItemCheckbox = function (element) {
      Attr.setAll(element, {
        'role': 'menuitemcheckbox',
        'aria-checked': false
      });
    };

    var checkbox = function (element, label) {
      Attr.setAll(element, {
        'role': 'checkbox',
        'aria-label': label,
        'aria-checked': false
      });
    };

    var dialog = function (element, label) {
      Attr.setAll(element, {
        'role': 'dialog',
        'aria-label': label
      });
    };

    var button = function (element, label) {
      Attr.setAll(element, {
        'aria-label': label,
        'role': 'button'
      });
    };

    // return a container object with methods {element, field} containing an html field and label
    var labelledField = function (field, name, labelText) {
      var container = Element.fromTag('div');
      presentationRole(container);
      var id = name + Id.generate('');
      var label = Element.fromHtml('' + labelText + '');
      Attr.set(label, 'for', id);
      Attr.set(field, 'id', id);
      InsertAll.append(container, [ label, field ]);

      return {
        element: Fun.constant(container),
        field:   Fun.constant(field)
      };
    };

    var textarea = function (element) {
      Attr.setAll(element, {
        'aria-multiline': 'true',
        'role': 'textbox'
      });
    };

    var widget = function (element) {
      Attr.set(element, 'role', 'widget');
    };

    var listBox = function (element) {
      Attr.set(element, 'role', 'listbox');
    };

    var tabList = function (element) {
      Attr.set(element, 'role', 'tablist');
    };

    var tabButton = function (element, label) {
      Attr.setAll(element, {
        'aria-label': label,
        'role': 'tab'
      });
    };

    var tabPanel = function (element) {
      Attr.setAll(element, {
        'role': 'tabpanel'
      });
    };

    var linkTabToPanel = function (tab, panel) {
      var id = Id.generate('ephox-aria');
      Attr.set(panel, 'id', id);
      Attr.setAll(tab, {
        'aria-controls': id
      });
    };

    var describedBy = function (element, id) {
      Attr.set(element, 'aria-describedby', id);
    };

    var labelledBy = function (element, id) {
      Attr.set(element, 'aria-labelledby', id);
    };

    var live = function (element, id, _priority) {
      var priority = _priority ? _priority : 'polite';
      Attr.setAll(element, {
        'aria-live': priority,
        'id': id
      });
    };

    var controls = function (element, id) {
      Attr.set(element, 'aria-controls', id);
    };

    var required = function (element) {
      Attr.set(element, 'aria-required', 'true');
    };

    // TODO: Implement form ARIA support
    // var form = function (element, label) {
    //   throw 'Form ARIA support not implemented yet.';
    // };

    var label = function (element, label) {
      Attr.set(element, 'aria-label', label);
    };

    var option = function (element) {
      Attr.set(element, 'role', 'option');
    };

    // TODO: Implement link ARIA support
    // var link = function (element) {
    //   throw 'Link ARIA support not implemented yet.';
    // };

    // TODO: Implement other ARIA support
    // var other = function () {
    //   throw 'Other ARIA support not implemented yet.';
    // };

    var hidden = function (element, status) {
      Attr.set(element, 'aria-hidden', status);
    };

    return {
      document: roleDocument,
      presentation: presentation,
      presentationRole: presentationRole,
      controls: controls,
      editor: editor,
      group: group,
      toolbar: toolbar,
      toolbarGroup: toolbarGroup,
      toolbarButton: toolbarButton,
      textButton: textButton,
      menu: menu,
      menuItem: menuItem,
      menuItemCheckbox: menuItemCheckbox,
      checkbox: checkbox,
      dialog: dialog,
      button: button,
      labelledField: labelledField,
      textarea: textarea,
      label: label,
      widget: widget,
      option: option,
      listBox: listBox,
      live: live,
      tabList: tabList,
      tabButton: tabButton,
      tabPanel: tabPanel,
      linkTabToPanel: linkTabToPanel,
      describedBy: describedBy,
      labelledBy: labelledBy,
      required: required,
      hidden: hidden
    };
  }
);<commit_msg>TBIO-4293: add comment<commit_after>define(
  'ephox.echo.api.AriaRegister',

  [
    'ephox.classify.Type',
    'ephox.compass.Arr',
    'ephox.compass.Obj',
    'ephox.echo.api.Styles',
    'ephox.epithet.Id',
    'ephox.highway.Merger',
    'ephox.peanut.Fun',
    'ephox.sugar.api.Attr',
    'ephox.sugar.api.Class',
    'ephox.sugar.api.Element',
    'ephox.sugar.api.Insert',
    'ephox.sugar.api.InsertAll'
  ],

  function (Type, Arr, Obj, Styles, Id, Merger, Fun, Attr, Class, Element, Insert, InsertAll) {
    var helpStyle = Styles.resolve('aria-help');
    var helpVisibleStyle = Styles.resolve('aria-help-visible');

    var roleDocument = function (element) {
      Attr.set(element, 'role', 'document');
    };

    var presentation = function (element) {
      // Note: aria-hidden=true says this element and all of its descendents are not percievable
      // https://www.w3.org/TR/wai-aria/states_and_properties#aria-hidden
      Attr.setAll(element, {
        'role': 'presentation',
        'aria-hidden': 'true'
      });
    };

    // https://www.w3.org/TR/wai-aria/roles#presentation
    var presentationRole = function (element) {
      Attr.set(element, 'role', 'presentation');
    };

    var editor = function (container, editor, label, ariaHelp, showHelpHint) {
      // Set role=region: https://www.w3.org/TR/wai-aria/roles#region
      // on editor for better user navigation modes, as it is mostly text content.
      // Better than role=application which constrains the reader navigation
      // - https://www.w3.org/TR/wai-aria/roles#application
      Attr.setAll(container, {
        'role': 'region',
        'aria-label': label
      });

      ariaHelp.each(function (helpText) {
        var aria = Element.fromTag('span');
        presentationRole(aria);
        Insert.append(aria, Element.fromText(helpText));
        var labelId = Id.generate('ephox-aria');
        Attr.set(aria, 'id', labelId);
        describedBy(editor, labelId);
        Class.add(aria, helpStyle);
        if (showHelpHint === true) Class.add(aria, helpVisibleStyle);
        Insert.append(container, aria);
      });

      // content attributes - surprisingly helps in both classic and inline
      var attrs = {
        'aria-multiline': 'true',
        'aria-label': label,
        title: label
      };

      Attr.setAll(editor, attrs);

      var destroy = function () {
        var removeFromEditor = Fun.curry(Attr.remove, editor);
        Arr.each(Obj.keys(attrs), removeFromEditor);
        removeFromEditor('aria-describedby');
      };

      return {
        destroy: destroy
      };
    };

    // Set the role 'group'
    var group = function (element) {
      Attr.set(element, 'role', 'group');
    };

    // Sets the role 'group', with a label
    var toolbar = function (element, label) {
      Attr.setAll(element, {
        'role': 'group',
        'aria-label': label
      });
    };

    var menu = function (element, label) {
      Attr.setAll(element, {
        'aria-label': label,
        'role': 'menu'
      });
    };

    var textButton = function (element, contentElement) {
      // Add 'button' roleto a pastry button, and 'presentation' role
      // to the contentElement that contains the button text.
      Attr.set(element, 'role', 'button');
      presentationRole(contentElement);
    };

    // Set the role 'button'
    var toolbarButton = function (element, label, hasPopup, isToggle) {
      Attr.setAll(element, {
        'role': 'button',
        'aria-label': label,
        'aria-haspopup': '' + hasPopup
      });
      if (isToggle) Attr.set(element, 'aria-pressed', 'false');
      if (hasPopup) Attr.set(element, 'aria-expanded', 'false');
    };

    // Set the role 'toolbar' and aria-label if provided
    var toolbarGroup = function (element, label) {
      // TODO: duplicated from 'ephox.polish.alien.Query', consolidate isEmpty();
      var isEmpty = function (val) {
        // TODO: Move to compass Arr and violin Strings
        return (val === null) || (val === undefined) || (val === '') || (Type.isArray(val) && val.length === 0);
      };
      // End TODO

      Attr.set(element, 'role', 'toolbar');

      // customer groups may have empty label, don't use it
      if (!isEmpty(label)) {
        Attr.set(element, 'aria-label', label);
      }
    };

    var menuItem = function (element, label, hasPopup) {
      var labelTxt = label.map(function (txt) {
        return { 'aria-label': txt };
      }).getOr({});

      Attr.setAll(element, Merger.merge(labelTxt, {
        'role': 'menuitem',
        'aria-haspopup': hasPopup.getOr(false)
      }));
    };

    var menuItemCheckbox = function (element) {
      Attr.setAll(element, {
        'role': 'menuitemcheckbox',
        'aria-checked': false
      });
    };

    var checkbox = function (element, label) {
      Attr.setAll(element, {
        'role': 'checkbox',
        'aria-label': label,
        'aria-checked': false
      });
    };

    var dialog = function (element, label) {
      Attr.setAll(element, {
        'role': 'dialog',
        'aria-label': label
      });
    };

    var button = function (element, label) {
      Attr.setAll(element, {
        'aria-label': label,
        'role': 'button'
      });
    };

    // return a container object with methods {element, field} containing an html field and label
    var labelledField = function (field, name, labelText) {
      var container = Element.fromTag('div');
      presentationRole(container);
      var id = name + Id.generate('');
      var label = Element.fromHtml('' + labelText + '');
      Attr.set(label, 'for', id);
      Attr.set(field, 'id', id);
      InsertAll.append(container, [ label, field ]);

      return {
        element: Fun.constant(container),
        field:   Fun.constant(field)
      };
    };

    var textarea = function (element) {
      Attr.setAll(element, {
        'aria-multiline': 'true',
        'role': 'textbox'
      });
    };

    var widget = function (element) {
      Attr.set(element, 'role', 'widget');
    };

    var listBox = function (element) {
      Attr.set(element, 'role', 'listbox');
    };

    var tabList = function (element) {
      Attr.set(element, 'role', 'tablist');
    };

    var tabButton = function (element, label) {
      Attr.setAll(element, {
        'aria-label': label,
        'role': 'tab'
      });
    };

    var tabPanel = function (element) {
      Attr.setAll(element, {
        'role': 'tabpanel'
      });
    };

    var linkTabToPanel = function (tab, panel) {
      var id = Id.generate('ephox-aria');
      Attr.set(panel, 'id', id);
      Attr.setAll(tab, {
        'aria-controls': id
      });
    };

    var describedBy = function (element, id) {
      Attr.set(element, 'aria-describedby', id);
    };

    var labelledBy = function (element, id) {
      Attr.set(element, 'aria-labelledby', id);
    };

    var live = function (element, id, _priority) {
      var priority = _priority ? _priority : 'polite';
      Attr.setAll(element, {
        'aria-live': priority,
        'id': id
      });
    };

    var controls = function (element, id) {
      Attr.set(element, 'aria-controls', id);
    };

    var required = function (element) {
      Attr.set(element, 'aria-required', 'true');
    };

    // TODO: Implement form ARIA support
    // var form = function (element, label) {
    //   throw 'Form ARIA support not implemented yet.';
    // };

    var label = function (element, label) {
      Attr.set(element, 'aria-label', label);
    };

    var option = function (element) {
      Attr.set(element, 'role', 'option');
    };

    // TODO: Implement link ARIA support
    // var link = function (element) {
    //   throw 'Link ARIA support not implemented yet.';
    // };

    // TODO: Implement other ARIA support
    // var other = function () {
    //   throw 'Other ARIA support not implemented yet.';
    // };

    var hidden = function (element, status) {
      Attr.set(element, 'aria-hidden', status);
    };

    return {
      document: roleDocument,
      presentation: presentation,
      presentationRole: presentationRole,
      controls: controls,
      editor: editor,
      group: group,
      toolbar: toolbar,
      toolbarGroup: toolbarGroup,
      toolbarButton: toolbarButton,
      textButton: textButton,
      menu: menu,
      menuItem: menuItem,
      menuItemCheckbox: menuItemCheckbox,
      checkbox: checkbox,
      dialog: dialog,
      button: button,
      labelledField: labelledField,
      textarea: textarea,
      label: label,
      widget: widget,
      option: option,
      listBox: listBox,
      live: live,
      tabList: tabList,
      tabButton: tabButton,
      tabPanel: tabPanel,
      linkTabToPanel: linkTabToPanel,
      describedBy: describedBy,
      labelledBy: labelledBy,
      required: required,
      hidden: hidden
    };
  }
);<|endoftext|>


<commit_before>import { MDCRippleFoundation } from '@material/ripple'
import { supportsCssVariables, getMatchesProperty } from '@material/ripple/util'

/* global HTMLElement */
const MATCHES = HTMLElement && getMatchesProperty(HTMLElement.prototype)

export class RippleBase extends MDCRippleFoundation {
  constructor (vm, options) {

    super(Object.assign({
      browserSupportsCssVars: () => {
        return supportsCssVariables(window)
      },
      registerResizeHandler: (handler) => {
        return window.addEventListener('resize', handler)
      },
      deregisterResizeHandler: (handler) => {
        return window.removeEventListener('resize', handler)
      },
      getWindowPageOffset: () => {
        return ({x: window.pageXOffset, y: window.pageYOffset})
      },
      isUnbounded: () => {
        return false
      },
      computeBoundingRect: () => {
        return vm.$el.getBoundingClientRect()
      },
      isSurfaceActive: () => {
        return vm.$el[MATCHES](':active')
      },
      isSurfaceDisabled: () => {
        return vm.disabled
      },
      addClass (className) {
        vm.$set(vm.classes, className, true)
      },
      // assumes a data 'classes' property on the root element
      removeClass (className) {
        vm.$delete(vm.classes, className)
      },
      registerInteractionHandler: (evt, handler) => {
        vm.$el.addEventListener(evt, handler)
      },
      deregisterInteractionHandler: (evt, handler) => {
        vm.$el.removeEventListener(evt, handler)
      },
      updateCssVariable: (varName, value) => {
        vm.$set(vm.styles, varName, value)
      }
    }, options))
  }

  static isSurfaceActive (ref) {
    return ref[MATCHES](':active')
  }
}
<commit_msg>fix(util): fix ripple for ssr<commit_after>import { MDCRippleFoundation } from '@material/ripple'
import { supportsCssVariables, getMatchesProperty } from '@material/ripple/util'

export class RippleBase extends MDCRippleFoundation {

  static get MATCHES () {
    /* global HTMLElement */
    return RippleBase._matches ||
      ( RippleBase._matches = getMatchesProperty(HTMLElement.prototype))
  }

  static isSurfaceActive (ref) {
    return ref[RippleBase.MATCHES](':active')
  }

  constructor (vm, options) {
    super(Object.assign({
      browserSupportsCssVars: () => {
        return supportsCssVariables(window)
      },
      registerResizeHandler: (handler) => {
        return window.addEventListener('resize', handler)
      },
      deregisterResizeHandler: (handler) => {
        return window.removeEventListener('resize', handler)
      },
      getWindowPageOffset: () => {
        return ({x: window.pageXOffset, y: window.pageYOffset})
      },
      isUnbounded: () => {
        return false
      },
      computeBoundingRect: () => {
        return vm.$el.getBoundingClientRect()
      },
      isSurfaceActive: () => {
        return vm.$el[RippleBase.MATCHES](':active')
      },
      isSurfaceDisabled: () => {
        return vm.disabled
      },
      addClass (className) {
        vm.$set(vm.classes, className, true)
      },
      // assumes a data 'classes' property on the root element
      removeClass (className) {
        vm.$delete(vm.classes, className)
      },
      registerInteractionHandler: (evt, handler) => {
        vm.$el.addEventListener(evt, handler)
      },
      deregisterInteractionHandler: (evt, handler) => {
        vm.$el.removeEventListener(evt, handler)
      },
      updateCssVariable: (varName, value) => {
        vm.$set(vm.styles, varName, value)
      }
    }, options))
  }
}
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var Game = function(goal) {

    var scoreBulls = function(guess, goal) {
	var bulls = 0;
	for (var i=0;i<guess.length;++i) {
	    if (guess[i] === goal[i])
		bulls++;
	}
	return bulls;
    };

    var scoreCows = function(guess, goal) {
	var cows = 0;
	for (var i=0;i<goal.length;++i) {
	    var desiredChar = goal[i];
	    for (var j=0;j<goal.length;++j) {
		if (j === i) continue;

		if (guess[j] === desiredChar) {
		    cows++;
		}
	    }
	}
	return cows;
    };

    this.score = function(guess) {
	assert(goal.length === guess.length, 'Lengths must be equivalent');

        return {
	    cows: scoreCows(guess,goal),
	    bulls: scoreBulls(guess,goal)
	};
    };

    var finishingScore = function(score) {
	return score.bulls === 4;
    };

    this.play = function(strategy) {
	var turns = 0;

	do {
	    turns++;
	    var guess = strategy.guess();
	    var score = this.score(guess);
	    strategy.update(guess,score);

	} while (!finishingScore(score) && turns < 10002);

	return turns;
    };

    return this;
};

var asString = function(num) {
    var s = '0000' + num;
    return s.substr(s.length - 4);
};

var isValid = function(s) {
    var a = s[0] !== s[1] && s[0] !== s[2] && s[0] !== s[3];
    var b = s[1] !== s[2] && s[1] !== s[3];
    var c = s[2] !== s[3];
    return a && b && c;
};

var fromToWithUnique = function(start,end) {
    var arr = [];
    for (var i=start;i<=end;++i) {
	if (isValid(asString(i))) {
	    arr.push(i);
	}
    }
    return arr;
};

var Player = function() {

    this.possibilities = fromToWithUnique(0,9999);

    this.guess = function() {
	var n = (Math.random() * this.possibilities.length) | 0;
	var guess = asString(this.possibilities[n]);

	return guess;
    };

    this.eliminateMatches = function(guess, fn) {
	for (var i=0;i<guess.length;++i) {
	    var digit = guess[i];
	    for (var k=this.possibilities.length-1;k>=0;--k) {
		var possibility = this.possibilities[k];
		if (fn(asString(possibility),digit)) {
		    this.possibilities.splice(k,1);
		}
	    }
	}
    };

    this.eliminatePartialMatches = function(guess, n) {
	for (var k=this.possibilities.length-1;k>=0;--k) {
	    var poss = asString(this.possibilities[k]);
	    var foundCount = 0;

	    // poss must contain at least n characters from guess
	    for (var i=0;i<4;++i) {
		var goalChar = guess[i];
		for (var j=0;j<4;++j) {
		    if (poss[j] === goalChar) {
			foundCount++;
			poss[j] = -1; // so we don't count it again
			break;
		    }
		}
	    }
	    if (foundCount < n)
		this.possibilities.splice(k,1);
	}
    };

    this.update = function(guess,score) {
	if (score.cows + score.bulls === 0) {
	    // None of the numbers are correct so we can eliminate anything
	    // that contains any of these digits
	    this.eliminateMatches(guess, function(str,digit) {
		return str.indexOf(digit) !== -1;
	    });
	}

	if (score.bulls > 0) {
	    // Any possibility that doesn't contain at least
	    // score.bulls in the same position as guess is wrong
	    for (var i=this.possibilities.length-1; i>=0; --i) {
		var p = asString(this.possibilities[i]);

		var inRightPlace = 0;
		for (var k=0;k<4;++k) {
		    inRightPlace += (p[k] === guess[k]) ? 1 : 0;
		}

		if (inRightPlace < score.bulls) {
		    this.possibilities.splice(i,1);
		}
	    }
	}

	if (score.cows + score.bulls > 0) {
	    // Any possibility that doesn't contain at least
	    // score.cows + score.bulls from guess is wrong
	    this.eliminatePartialMatches(guess, score.cows + score.bulls);
	}
    };

    return this;
};

var Naive = function() {

    this.currentGuess = 0;

    this.guess = function() {
	return asString(this.currentGuess);
    };

    this.update = function(guess, score) {
	this.currentGuess++;
    };

    return this;
};

var createGame = function(goal) {
    return new Game(goal);
};

var containsDuplicates = function(str) {
    for (var i=0;i<str.length;++i) {
	var found = false;
	for (var j=0;j<str.length;++j) {
	    if (i === j) continue;

	    if (str[i] === str[j])
		return true;
	}
    }
    return false;
};

describe("cows and bulls", function() {

    describe('playing naive', function() {
	it('should solve it within 9999 turns', function() {
	    var game = createGame('5555');
	    var turns = game.play(new Naive());

	    assert.equal(5556, turns);
	});
    });

    describe('slightly intelligently playing', function() {

	var generateUniqueGoal = function() {
            var digits = [0,1,2,3,4,5,6,7,8,9];

	    var goal = '';
	    for (var i=0;i<4;++i) {
		var index = Math.random() * digits.length | 0;
		goal += digits[index];
		digits.splice(index,1);
	    }

	    return goal;
        };

	it('should solve the game within 9999 turns', function() {
	    var totalTurns = 0;
	    var count = 100;

	    for (var i=0;i<count;++i) {
		var goal = generateUniqueGoal();
		var game = createGame(goal);
		var turns = game.play(new Player());

		totalTurns += turns;
		assert(turns < 10000, 'Too many turns to solve: ' + goal);
	    }

	    console.log('Average number of turns: ' + totalTurns / count);
	});

	it('initial pool of answers is 10000', function() {
	    var player = new Player();

	    assert.equal(5040, player.possibilities.length);
	});

	it('zero scores eliminate possibilities', function() {
	    var player = new Player();

	    player.update('1111', { cows: 0, bulls: 0 });

	    assert.equal(3024, player.possibilities.length);
	});

	it('correct guesses eliminate possibilities', function() {
	    var player = new Player();

	    player.update('1234', { cows: 4, bulls: 0 });

	    assert.equal(4*3*2*1, player.possibilities.length);
	});

	it('partial bull matches eliminate many possibilities', function() {
	    var player = new Player();

	    player.update('1234', { cows: 0, bulls: 1 });

	    // all possibilities must have at least one in the right position
	    for (var i=0;i<player.possibilities.length;++i) {
		var remaining = asString(player.possibilities[i]);

		assert(remaining[0] === '1' ||
		       remaining[1] === '2' ||
		       remaining[2] === '3' ||
		       remaining[3] === '4');
	    }
	});

	it('partial matches eliminate possibilites', function() {
	    var player = new Player();

	    player.update('1234', { cows: 2, bulls: 0 });

	    for (var i=0;i<player.possibilities.length;++i) {
		var v = asString(player.possibilities[i]);

		var count = 0;
		for (var k=1;k<=4;++k)
		    count += v.indexOf(k + '') !== -1 ? 1 : 0;
		assert(count >= 2);
	    }
	});

	it('partial matches eliminate possibilities (2)', function() {
	    var player = new Player();

	    player.update('1111', { cows: 1, bulls: 0 });
	    for (var i=0;i<player.possibilities.length;++i) {
		assert(-1 != asString(player.possibilities[i]).indexOf('1'));
	    }
	});
    });

    describe('scoring', function() {
	it('should match the example', function() {
	    var game = createGame('8045');
	    var result = game.score('0865');

	    assert.equal(2, result.cows);
	    assert.equal(1, result.bulls);
	});

	it('no matches scores no cows or bulls', function() {
            var game = createGame('1234');

            var r = game.score('5678');
            assert.equal(0,r.cows);
	    assert.equal(0,r.bulls);
	});

	it('all correct is all bulls', function() {
	    var game = createGame('1234');

	    var r = game.score('1234');
	    assert.equal(4, r.bulls);
	    assert.equal(0, r.cows);
	});

	it('all in wrong order is all cows', function() {
	    var game = createGame('1234');

	    var r = game.score('4321');
	    assert.equal(4, r.cows);
	    assert.equal(0, r.bulls);
	});
    });
});
<commit_msg>early morning practice<commit_after><|endoftext|>


<commit_before>// Circular doubly-linked list

var Postion = function (element)
{
    this.next = null;
    this.prev = null;
    this.element = element;
};

var List = function (comparitor)
{
    if(comparitor === undefined)
    {
        comparitor = function (a, b)
        {
            if(a < b) return -1;
            if(a > b) return 1;
            if(a === b) return 0;
        };
    }

    this.comparitor = comparitor;
    this.head = null;
    this.size = 0;
};

List.prototype.add = function (element, position)
{
    var pos = new Position(element);

    if(this.size === 0) // Empty list
    {
        pos.next = pos;
        pos.prev = pos;
        this.head = pos;
    }
    else
    {
        if(position === undefined)
            position = this.head.prev;

        position.next.prev = pos;
        pos.next = position.next;

        position.next = pos;
        pos.prev = position;
    }

    this.size++;
};

List.prototype.remove = function (position)
{
    if(this.size === 0)
        throw new Error("Cannot remove from empty list");

    if(position === this.head)
        this.head = position.next;

    position.prev.next = position.next;
    position.next.prev = position.prev;

    position.next = null;
    position.prev = null;

    this.size--;

    if(this.size === 0)
    {
        this.head = null;
    }
};

List.prototype.at = function (index)
{
    if(i >= this.size)
        throw new Error("Index out of bounds");

    var it = this.Iterator();get
    for(var i = 0; i < index; i++)
    {
        it.next();
    }

    return it.current;
};

List.prototype.find = function (element)
{
    for(var it = this.Iterator(); it.hasNext(); it.next())
    {
        if(this.comparitor(it.current.element, element) === 0)
            return it.current;
    }

    return null;
};

List.Iterator = function (start)
{
    if(start === undefined)
        start = this.head;

    var started = false;

    return {
        current: start,

        next: function () { this.current = this.current.next; started = true; },

        hasNext: function () { return !(started && this.current === start);  }
    };
};

List.ReverseIterator = function (start)
{
    if(start === undefined)
        start = this.head;

    var started = false;

    return {
        current: start,

        next: function () { current = current.prev; started = true; },

        hasNext: function () { return !(started && current === start);  }
    };
};

List.RoundRobinIterator = function (start)
{
    if(start === undefined)
        start = this.head;

    return {
        current: start,

        next: function () { current = current.next; },

        hasNext: function () { return true; }
    };
};

List.ReverseRoundRobinIterator = function (start)
{
    if(start === undefined)
        start = this.head;

    return {
        current: start,

        next: function () { current = current.prev; },

        hasNext: function () { return true; }
    };
};

module.exports = List;
<commit_msg>Fixed some typos in list<commit_after>// Circular doubly-linked list

var Position = function (element)
{
    this.next = null;
    this.prev = null;
    this.element = element;
};

var List = function (comparitor)
{
    if(comparitor === undefined)
    {
        comparitor = function (a, b)
        {
            if(a < b) return -1;
            if(a > b) return 1;
            if(a === b) return 0;
        };
    }

    this.comparitor = comparitor;
    this.head = null;
    this.size = 0;
};

List.prototype.add = function (element, position)
{
    var pos = new Position(element);

    if(this.size === 0) // Empty list
    {
        pos.next = pos;
        pos.prev = pos;
        this.head = pos;
    }
    else
    {
        if(position === undefined)
            position = this.head.prev;

        position.next.prev = pos;
        pos.next = position.next;

        position.next = pos;
        pos.prev = position;
    }

    this.size++;
};

List.prototype.remove = function (position)
{
    if(this.size === 0)
        throw new Error("Cannot remove from empty list");

    if(position === this.head)
        this.head = position.next;

    position.prev.next = position.next;
    position.next.prev = position.prev;

    position.next = null;
    position.prev = null;

    this.size--;

    if(this.size === 0)
    {
        this.head = null;
    }
};

List.prototype.at = function (index)
{
    if(i >= this.size)
        throw new Error("Index out of bounds");

    var it = this.Iterator();
    for(var i = 0; i < index; i++)
    {
        it.next();
    }

    return it.current;
};

List.prototype.find = function (element)
{
    for(var it = this.Iterator(); it.hasNext(); it.next())
    {
        if(this.comparitor(it.current.element, element) === 0)
            return it.current;
    }

    return null;
};

List.prototype.Iterator = function (start)
{
    if(start === undefined)
        start = this.head;

    var started = false;

    return {
        current: start,

        next: function () { this.current = this.current.next; started = true; },

        hasNext: function () { return !(started && this.current === start);  }
    };
};

List.prototype.ReverseIterator = function (start)
{
    if(start === undefined)
        start = this.head;

    var started = false;

    return {
        current: start,

        next: function () { current = current.prev; started = true; },

        hasNext: function () { return !(started && current === start);  }
    };
};

List.RoundRobinIterator = function (start)
{
    if(start === undefined)
        start = this.head;

    return {
        current: start,

        next: function () { current = current.next; },

        hasNext: function () { return true; }
    };
};

List.prototype.ReverseRoundRobinIterator = function (start)
{
    if(start === undefined)
        start = this.head;

    return {
        current: start,

        next: function () { current = current.prev; },

        hasNext: function () { return true; }
    };
};

module.exports = List;
<|endoftext|>


<commit_before>// This file is part of Indico.
// Copyright (C) 2002 - 2022 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

import 'fullcalendar';
import 'fullcalendar/dist/fullcalendar.css';

(function(global) {
  global.setupCategoryCalendar = function setupCategoryCalendar(elementId, categoryURL) {
    const cachedEvents = {};

    $(elementId).fullCalendar({
      firstDay: 1,
      height: 800,
      eventOrder: 'start',
      eventTextColor: '#FFF',
      timeFormat: 'HH:mm',
      nextDayThreshold: '00:00',
      eventLimit: 5,
      buttonText: {
        today: $T.gettext('Today'),
      },
      eventLimitClick(cellInfo) {
        const content = $('<ul>');
        const events = cellInfo.segs.sort((a, b) => {
          const aTitle = a.footprint.eventInstance.def.title.toLowerCase();
          const bTitle = b.footprint.eventInstance.def.title.toLowerCase();
          if (aTitle < bTitle) {
            return -1;
          }
          if (aTitle > bTitle) {
            return 1;
          }
          return 0;
        });
        events.forEach(hiddenSegment => {
          const li = $('<li>');
          const eventLink = $('<a>', {
            href: hiddenSegment.footprint.eventInstance.def.url,
            text: hiddenSegment.footprint.eventInstance.def.title,
          });
          li.append(eventLink);
          content.append(li);
        });
        ajaxDialog({
          dialogClasses: 'all-events-dialog',
          title: $T.gettext('Events happening on {0}').format(cellInfo.date.format('MMMM Do YYYY')),
          content,
        });
      },
      events(start, end, timezone, callback) {
        function updateCalendar(data) {
          callback(data.events);
          const toolbarGroup = $(elementId).find('.fc-toolbar .fc-right');
          const ongoingEventsInfo = $('<a>', {
            href: '#',
            class: 'ongoing-events-info',
            text: $T
              .ngettext(
                '{0} long-lasting event not shown',
                '{0} long-lasting events not shown',
                data.ongoing_event_count
              )
              .format(data.ongoing_event_count),
            on: {
              click: evt => {
                evt.preventDefault();
                ajaxDialog({
                  title: $T.gettext('Long lasting events'),
                  content: $(data.ongoing_events_html),
                  dialogClasses: 'ongoing-events-dialog',
                });
              },
            },
          });

          toolbarGroup.find('.ongoing-events-info').remove();
          toolbarGroup.prepend(ongoingEventsInfo);
        }

        const key = `${start}-${end}`;
        if (cachedEvents[key]) {
          updateCalendar(cachedEvents[key]);
        } else {
          $.ajax({
            url: categoryURL,
            data: {start: start.format('YYYY-MM-DD'), end: end.format('YYYY-MM-DD')},
            dataType: 'json',
            contentType: 'application/json',
            error: handleAjaxError,
            complete: IndicoUI.Dialogs.Util.progress(),
            success(data) {
              updateCalendar(data);
              cachedEvents[key] = data;
            },
          });
        }
      },
    });
  };
})(window);
<commit_msg>Category calendar: do not show "0 ongoing events" msg<commit_after>// This file is part of Indico.
// Copyright (C) 2002 - 2022 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

import 'fullcalendar';
import 'fullcalendar/dist/fullcalendar.css';

(function(global) {
  global.setupCategoryCalendar = function setupCategoryCalendar(elementId, categoryURL) {
    const cachedEvents = {};

    $(elementId).fullCalendar({
      firstDay: 1,
      height: 800,
      eventOrder: 'start',
      eventTextColor: '#FFF',
      timeFormat: 'HH:mm',
      nextDayThreshold: '00:00',
      eventLimit: 5,
      buttonText: {
        today: $T.gettext('Today'),
      },
      eventLimitClick(cellInfo) {
        const content = $('<ul>');
        const events = cellInfo.segs.sort((a, b) => {
          const aTitle = a.footprint.eventInstance.def.title.toLowerCase();
          const bTitle = b.footprint.eventInstance.def.title.toLowerCase();
          if (aTitle < bTitle) {
            return -1;
          }
          if (aTitle > bTitle) {
            return 1;
          }
          return 0;
        });
        events.forEach(hiddenSegment => {
          const li = $('<li>');
          const eventLink = $('<a>', {
            href: hiddenSegment.footprint.eventInstance.def.url,
            text: hiddenSegment.footprint.eventInstance.def.title,
          });
          li.append(eventLink);
          content.append(li);
        });
        ajaxDialog({
          dialogClasses: 'all-events-dialog',
          title: $T.gettext('Events happening on {0}').format(cellInfo.date.format('MMMM Do YYYY')),
          content,
        });
      },
      events(start, end, timezone, callback) {
        function updateCalendar(data) {
          callback(data.events);
          const toolbarGroup = $(elementId).find('.fc-toolbar .fc-right');
          const ongoingEventsInfo = $('<a>', {
            href: '#',
            class: 'ongoing-events-info',
            text: $T
              .ngettext(
                '{0} long-lasting event not shown',
                '{0} long-lasting events not shown',
                data.ongoing_event_count
              )
              .format(data.ongoing_event_count),
            on: {
              click: evt => {
                evt.preventDefault();
                ajaxDialog({
                  title: $T.gettext('Long lasting events'),
                  content: $(data.ongoing_events_html),
                  dialogClasses: 'ongoing-events-dialog',
                });
              },
            },
          });

          toolbarGroup.find('.ongoing-events-info').remove();
          if (data.ongoing_event_count) {
            toolbarGroup.prepend(ongoingEventsInfo);
          }
        }

        const key = `${start}-${end}`;
        if (cachedEvents[key]) {
          updateCalendar(cachedEvents[key]);
        } else {
          $.ajax({
            url: categoryURL,
            data: {start: start.format('YYYY-MM-DD'), end: end.format('YYYY-MM-DD')},
            dataType: 'json',
            contentType: 'application/json',
            error: handleAjaxError,
            complete: IndicoUI.Dialogs.Util.progress(),
            success(data) {
              updateCalendar(data);
              cachedEvents[key] = data;
            },
          });
        }
      },
    });
  };
})(window);
<|endoftext|>


<commit_before>define(
  'ephox.phoenix.wrap.SpanWrap',

  [
    'ephox.bud.Unicode',
    'ephox.compass.Arr',
    'ephox.peanut.Fun',
    'ephox.perhaps.Option',
    'ephox.phoenix.api.data.Spot',
    'ephox.phoenix.api.general.Injection',
    'ephox.phoenix.wrap.Wrapper',
    'ephox.phoenix.wrap.Wraps',
    'ephox.scullion.Struct'
  ],

  function (Unicode, Arr, Fun, Option, Spot, Injection, Wrapper, Wraps, Struct) {
    var point = function (universe, start, soffset, finish, foffset, exclusions) {
      var scanned = scan(universe, start, soffset, finish, foffset, exclusions);
      var cursor = scanned.cursor();
      var range = Spot.points(
        Spot.point(cursor.element(), cursor.offset()),
        Spot.point(cursor.element(), cursor.offset())
      );

      return Option.some({
        range: Fun.constant(range),
        temporary: scanned.temporary,
        wrappers: scanned.wrappers
      });
    };

    var spanCursor = Struct.immutable('span', 'cursor');

    /// TODO this was copied from boss DomUniverse, use that instead
    var isEmptyTag = function (universe, item) {
      return Arr.contains([ 'br', 'img', 'hr', 'input' ], universe.property().name(item));
    };

    var temporary = function (universe, start, soffset, finish, foffset) {
      var doc = start.dom().ownerDocument;
      var span = universe.create().nu('span', doc);

      var cursor = universe.create().text(Unicode.zeroWidth(), doc);
      universe.insert().append(span, cursor);

      /// TODO don't append to empty tags (might be better in Injection.atStartOf)

      /// also need to twiddle the offset
      var injectAt = isEmptyTag(universe, start) ? universe.property().parent(start) : Option.some(start);
      injectAt.each(function (z) {
        Injection.atStartOf(universe, z, soffset, span);
      });

      // Injection.atStartOf(universe, injectAt, soffset, span);
      return {
        cursor: Fun.constant(Spot.point(cursor, 1)),
        wrappers: Fun.constant([ span ]),
        temporary: Fun.constant(true)
      };
    };

    /*
     * The point approach needs to reuse a temporary span (if we already have one) or create one if we don't.
     */
    var scan = function (universe, start, soffset, finish, foffset, exclusions) {
      return universe.property().parent(start).bind(function (parent) {
        var cursor = Spot.point(start, soffset);
        var canReuse = isSpan(universe, exclusions, parent) && universe.property().children(parent).length === 1 && isUnicode(universe, start);
        return canReuse ? Option.some({
          cursor: Fun.constant(cursor),
          temporary: Fun.constant(false),
          wrappers: Fun.constant([ parent ])
        }) : Option.none();
      }).getOrThunk(function () {
        return temporary(universe, start, soffset, finish, foffset);
      });
    };

    var isUnicode = function (universe, element) {
      return universe.property().isText(element) && universe.property().getText(element) === Unicode.zeroWidth();
    };

    var isSpan = function (universe, exclusions, elem) {
      return universe.property().name(elem) === 'span' && exclusions(elem) === false;
    };

    var wrap = function (universe, start, soffset, finish, foffset, exclusions) {
      var doc = start.dom().ownerDocument;
      var nuSpan = function () {
        return Wraps(universe, universe.create().nu('span', doc));
      };

      var wrappers = Wrapper.reuse(universe, start, soffset, finish, foffset, Fun.curry(isSpan, universe, exclusions), nuSpan);
      return Option.from(wrappers[wrappers.length - 1]).map(function (lastSpan) {
        var lastOffset = universe.property().children(lastSpan).length;
        var range = Spot.points(
          Spot.point(wrappers[0], 0),
          Spot.point(lastSpan, lastOffset)
        );

        return {
          wrappers: Fun.constant(wrappers),
          temporary: Fun.constant(false),
          range: Fun.constant(range)
        };
      });
    };

    var isCollapsed = function (universe, start, soffset, finish, foffset) {
      return universe.eq(start, finish) && soffset === foffset;
    };

    var spans = function (universe, start, soffset, finish, foffset, _exclusions) {
      var exclusions = _exclusions !== undefined ? _exclusions : Fun.constant(false);
      var wrapper = isCollapsed(universe, start, soffset, finish, foffset) ? point : wrap;
      return wrapper(universe, start, soffset, finish, foffset, exclusions);
    };

    return {
      spans: spans
    };
  }
);<commit_msg>TBIO-4085: using boss instead of copying<commit_after>define(
  'ephox.phoenix.wrap.SpanWrap',

  [
    'ephox.bud.Unicode',
    'ephox.compass.Arr',
    'ephox.peanut.Fun',
    'ephox.perhaps.Option',
    'ephox.phoenix.api.data.Spot',
    'ephox.phoenix.api.general.Injection',
    'ephox.phoenix.wrap.Wrapper',
    'ephox.phoenix.wrap.Wraps',
    'ephox.scullion.Struct'
  ],

  function (Unicode, Arr, Fun, Option, Spot, Injection, Wrapper, Wraps, Struct) {
    var point = function (universe, start, soffset, finish, foffset, exclusions) {
      var scanned = scan(universe, start, soffset, finish, foffset, exclusions);
      var cursor = scanned.cursor();
      var range = Spot.points(
        Spot.point(cursor.element(), cursor.offset()),
        Spot.point(cursor.element(), cursor.offset())
      );

      return Option.some({
        range: Fun.constant(range),
        temporary: scanned.temporary,
        wrappers: scanned.wrappers
      });
    };

    var temporary = function (universe, start, soffset, finish, foffset) {
      var doc = start.dom().ownerDocument;
      var span = universe.create().nu('span', doc);

      var cursor = universe.create().text(Unicode.zeroWidth(), doc);
      universe.insert().append(span, cursor);

      var isEmptyTag = function (item) {
        return universe.property().isEmptyTag(item);
      };

      var injectAt = isEmptyTag(start) ? universe.property().parent(start) : Option.some(start);
      injectAt.each(function (z) {
        Injection.atStartOf(universe, z, soffset, span);
      });

      return {
        cursor: Fun.constant(Spot.point(cursor, 1)),
        wrappers: Fun.constant([ span ]),
        temporary: Fun.constant(true)
      };
    };

    /*
     * The point approach needs to reuse a temporary span (if we already have one) or create one if we don't.
     */
    var scan = function (universe, start, soffset, finish, foffset, exclusions) {
      return universe.property().parent(start).bind(function (parent) {
        var cursor = Spot.point(start, soffset);
        var canReuse = isSpan(universe, exclusions, parent) && universe.property().children(parent).length === 1 && isUnicode(universe, start);
        return canReuse ? Option.some({
          cursor: Fun.constant(cursor),
          temporary: Fun.constant(false),
          wrappers: Fun.constant([ parent ])
        }) : Option.none();
      }).getOrThunk(function () {
        return temporary(universe, start, soffset, finish, foffset);
      });
    };

    var isUnicode = function (universe, element) {
      return universe.property().isText(element) && universe.property().getText(element) === Unicode.zeroWidth();
    };

    var isSpan = function (universe, exclusions, elem) {
      return universe.property().name(elem) === 'span' && exclusions(elem) === false;
    };

    var wrap = function (universe, start, soffset, finish, foffset, exclusions) {
      var doc = start.dom().ownerDocument;
      var nuSpan = function () {
        return Wraps(universe, universe.create().nu('span', doc));
      };

      var wrappers = Wrapper.reuse(universe, start, soffset, finish, foffset, Fun.curry(isSpan, universe, exclusions), nuSpan);
      return Option.from(wrappers[wrappers.length - 1]).map(function (lastSpan) {
        var lastOffset = universe.property().children(lastSpan).length;
        var range = Spot.points(
          Spot.point(wrappers[0], 0),
          Spot.point(lastSpan, lastOffset)
        );

        return {
          wrappers: Fun.constant(wrappers),
          temporary: Fun.constant(false),
          range: Fun.constant(range)
        };
      });
    };

    var isCollapsed = function (universe, start, soffset, finish, foffset) {
      return universe.eq(start, finish) && soffset === foffset;
    };

    var spans = function (universe, start, soffset, finish, foffset, _exclusions) {
      var exclusions = _exclusions !== undefined ? _exclusions : Fun.constant(false);
      var wrapper = isCollapsed(universe, start, soffset, finish, foffset) ? point : wrap;
      return wrapper(universe, start, soffset, finish, foffset, exclusions);
    };

    return {
      spans: spans
    };
  }
);<|endoftext|>