text:
'use strict';

function singleSellecktSpecs(SingleSelleckt, templateUtils, $, _){
    return describe('SingleSelleckt', function(){
        var selleckt,
            elHtml =
                '<select>' +
                    '<option selected value="1">foo</option>' +
                    '<option value="2" data-meh="whee" data-bah="oink">bar</option>' +
                    '<option value="3">baz</option>' +
                '</select>',
            $testArea,
            $el,
            sandbox;

        before(function(){
            sandbox = sinon.sandbox.create();

            $testArea = $('
', {
                'class': 'testArea',
                css: {
                    position: 'absolute',
                    left: '-999px'
                }
            }).appendTo($('body'));
        });

        beforeEach(function(){
            $el = $(elHtml).appendTo($testArea);
        });

        afterEach(function(){
            $el.remove();
            $el = undefined;

            if(selleckt){
                selleckt.destroy();
                selleckt = undefined;
            }

            $testArea.empty();
            sandbox.restore();
        });

        describe('Instantiation', function(){
            describe('invalid instantiation', function(){
                it('pukes if instantiated with an invalid template format', function(){
                    var err;

                    try{
                        selleckt = new SingleSelleckt({
                            mainTemplate : {template: '
'},
                            $selectEl : $el,
                            className: 'selleckt',
                            selectedClass: 'selected',
                            selectedTextClass: 'selectedText',
                            itemsClass: 'items',
                            itemClass: 'item',
                            selectedClassName: 'isSelected',
                            highlightClassName: 'isHighlighted'
                        });
                    } catch(e){
                        err = e;
                    }

                    expect(err).toBeDefined();
                    expect(err.message).toEqual('Please provide a valid mustache template.');
                });

            });

            describe('valid instantation', function(){
                var template =
                '
' +
                    '
' +
                        '{{selectedItemText}}' +
                    '
' +
                    '
' +
                        '{{#showSearch}}' +
                        '
' +
                            '<input class="search"></input>' +
                        '
' +
                        '{{/showSearch}}' +
                        '{{#items}}' +
                            '{{> item}}' +
                        '{{/items}}' +
                    '
' +
                '
',
                itemTemplate = '
' +
                    '{{label}}' +
                '
',
                popupTemplate =
                '
' +
                    '{{#showSearch}}' +
                    '
' +
                        '<input class="{{searchInputClass}}"></input>' +
                    '
' +
                    'No items' +
                    '{{/showSearch}}' +
                    '
' +
                        '{{#items}}' +
                            '{{> item}}' +
                        '{{/items}}' +
                    '
' +
                '
';

                beforeEach(function(){
                    selleckt = new SingleSelleckt({
                        mainTemplate: template,
                        itemTemplate: itemTemplate,
                        popupTemplate: popupTemplate,
                        mainTemplateData: {foo: 'bar'},
                        popupTemplateData: {meh: 'boo'},
                        $selectEl : $el,
                        className: 'selleckt',
                        selectedClass: 'selected',
                        selectedTextClass: 'selectedText',
                        itemsClass: 'items',
                        itemClass: 'item',
                        selectedClassName: 'isSelected',
                        highlightClass: 'isHighlighted',
                        hideSelectedItem: true
                    });
                });

                it('stores the selectedClass as this.selectedClass', function(){
                    expect(selleckt.selectedClass).toEqual('selected');
                });

                it('stores the selectedTextClass as this.selectedClass', function(){
                    expect(selleckt.selectedTextClass).toEqual('selectedText');
                });

                it('stores the itemsClass as this.itemsClass', function(){
                    expect(selleckt.itemsClass).toEqual('items');
                });

                it('stores the itemClass as this.itemClass', function(){
                    expect(selleckt.itemClass).toEqual('item');
                });

                it('stores options.mainTemplate as this.template', function(){
                    expect(selleckt.mainTemplate).toEqual(template);
                });

                it('stores options.itemTemplate as this.itemTemplate', function(){
                    expect(selleckt.itemTemplate).toEqual(itemTemplate);
                });

                it('stores options.popupTemplate as this.popupTemplate', function(){
                    expect(selleckt.popupTemplate).toEqual(popupTemplate);
                });

                it('stores options.mainTemplateData as this.mainTemplateData', function(){
                    expect(selleckt.mainTemplateData).toEqual({foo: 'bar'});
                });

                it('stores options.popupTemplateData as this.popupTemplateData', function(){
                    expect(selleckt.popupTemplateData).toEqual({meh: 'boo'});
                });

                it('stores options.selectEl as this.originalSelectEl', function(){
                    expect(selleckt.$originalSelectEl).toEqual($el);
                });

                it('stores options.className as this.className', function(){
                    expect(selleckt.className).toEqual('selleckt');
                });

                it('stores options.highlightClass as this.highlightClass', function(){
                    expect(selleckt.highlightClass).toEqual('isHighlighted');
                });

                it('stores options.hideSelectedItem as this.hideSelectedItem', function(){
                    expect(selleckt.hideSelectedItem).toEqual(true);
                });

                describe('items', function(){
                    it('instantiates this.items as an based on the options in the original select', function(){
                        expect(selleckt.items.length).toEqual(3);
                    });
                    it('stores the option text as "label"', function(){
                        expect(selleckt.items[0].label).toEqual('foo');
                        expect(selleckt.items[1].label).toEqual('bar');
                    });
                    it('stores the option value as "value"', function(){
                        expect(selleckt.items[0].value).toEqual('1');
                        expect(selleckt.items[1].value).toEqual('2');
                    });
                    it('stores all the option data attributes in "data"', function(){
                        expect(selleckt.items[0].data).toBeDefined();
                        expect(_.size(selleckt.items[0].data)).toEqual(0);

                        expect(selleckt.items[1].data).toBeDefined();
                        expect(_.size(selleckt.items[1].data)).toEqual(2);
                        expect(selleckt.items[1].data).toEqual({
                            meh: 'whee',
                            bah: 'oink'
                        });
                    });
                    it('stores the selected option as this.selectedItem', function(){
                        expect(selleckt.selectedItem).toBeDefined();
                        expect(selleckt.selectedItem).toEqual({
                            value: '1',
                            label: 'foo',
                            data: {}
                        });
                    });
                    it('ignores empty options', function(){
                        var selectHtml = '<select>' +
                            '<option></option>' +
                            '<option value="2">bar</option>' +
                            '<option value="3">baz</option>' +
                            '</select>';

                        selleckt.destroy();

                        var $newEl = $(selectHtml).appendTo($testArea);

                        selleckt = new SingleSelleckt({
                            $selectEl : $newEl
                        });

                        expect(selleckt.items.length).toEqual(2);

                        expect(selleckt.items[0].value).toEqual('2');
                        expect(selleckt.items[0].label).toEqual('bar');

                        expect(selleckt.items[1].value).toEqual('3');
                        expect(selleckt.items[1].label).toEqual('baz');
                    });

                    describe('when there is no selected item already', function(){
                        var $newEl;

                        beforeEach(function(){
                            var selectHtml = '<select>' +
                            '<option value="1">foo</option>' +
                            '<option value="2">bar</option>' +
                            '<option value="3">baz</option>' +
                            '</select>';

                            selleckt.destroy();

                            $newEl = $(selectHtml).appendTo($testArea);

                            selleckt = new SingleSelleckt({
                                mainTemplate: template,
                                $selectEl : $newEl,
                                className: 'selleckt',
                                selectedClass: 'selected',
                                selectedTextClass: 'selectedText',
                                itemsClass: 'items',
                                itemClass: 'item',
                                selectedClassName: 'isSelected',
                                highlightClass: 'isHighlighted'
                            });
                        });

                        afterEach(function(){
                            $newEl.remove();
                            $newEl = undefined;
                        });

                        it('does not select an item', function(){
                            expect(selleckt.selectedItem).toBeUndefined();
                        });
                    });
                });

                describe('template caching', function(){
                    var cacheStub;

                    beforeEach(function(){
                        cacheStub = sinon.stub(templateUtils, 'cacheTemplate');

                        selleckt = new SingleSelleckt({
                            mainTemplate: template,
                            itemTemplate: itemTemplate,
                            $selectEl : $el,
                            className: 'selleckt',
                            selectedClass: 'selected',
                            selectedTextClass: 'selectedText',
                            itemsClass: 'items',
                            itemClass: 'item',
                            selectedClassName: 'isSelected',
                            highlightClass: 'isHighlighted'
                        });
                    });

                    afterEach(function(){
                        cacheStub.restore();
                    });

                    it('caches the main template', function(){
                        expect(cacheStub.calledWith(template)).toEqual(true);
                    });
                });

                describe('events', function(){
                    it('does not trigger change event when instantiated on select with selected option', function(){
                        var onChangeStub = sinon.stub();
                        $el.on('change', onChangeStub);

                        selleckt = new SingleSelleckt({
                            mainTemplate: template,
                            $selectEl : $el,
                            className: 'selleckt',
                            selectedClass: 'selected',
                            selectedTextClass: 'selectedText',
                            itemsClass: 'items',
                            itemClass: 'item',
                            selectedClassName: 'isSelected',
                            highlightClass: 'isHighlighted'
                        });

                        expect(onChangeStub.called).toEqual(false);
                        $el.off('change', onChangeStub);
                    });
                });
            });
        });

        describe('rendering', function(){
            beforeEach(function(){
                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });

                selleckt.render();
            });

            it('renders the selected element based on this.template', function(){
                expect(selleckt.$sellecktEl.find('.selected').length).toEqual(1);
            });

            it('renders the selected text element based on this.template', function(){
                expect(selleckt.$sellecktEl.find('.selectedText').length).toEqual(1);
                expect(selleckt.$sellecktEl.find('.selectedText').text()).toEqual(selleckt.selectedItem.label);
            });

            it('hides the original Select element', function(){
                expect(selleckt.$originalSelectEl.css('display')).toEqual('none');
            });

            it('adds a class of "closed" to the element', function(){
                expect(selleckt.$sellecktEl.hasClass('closed')).toEqual(true);
            });

            it('replaces custom template tags with template data', function(){
                var customTemplate =
                    '
' +
                        '{{#selectLabel}}{{selectLabel}}{{/selectLabel}}' +
                        '{{#required}}*{{/required}}' +
                        '
' +
                            '{{selectedItemText}}' +
                        '
' +
                        '
' +
                            '{{#items}}' +
                            '
' +
                                '{{label}}' +
                            '
' +
                            '{{/items}}' +
                        '
' +
                    '
';

                selleckt.destroy();
                selleckt = new SingleSelleckt({
                    $selectEl : $el,
                    mainTemplate: customTemplate,
                    mainTemplateData: {
                        selectLabel: 'Please selleckt',
                        required: false
                    }
                });
                selleckt.render();

                expect(selleckt.$sellecktEl.find('label').length).toEqual(1);
                expect(selleckt.$sellecktEl.find('label').text()).toEqual('Please selleckt');
                expect(selleckt.$sellecktEl.find('.required').length).toEqual(0);
            });
        });

        describe('Adding items', function(){
            var item;

            beforeEach(function(){
                item = {
                    label: 'new',
                    value: 'new value'
                };

                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });

                selleckt.render();
            });

            afterEach(function(){
                selleckt.destroy();
                selleckt = undefined;
            });

            describe('using addItem to add a single item', function(){
                it('adds an item to this.items', function(){
                    expect(selleckt.items.length).toEqual(3);

                    selleckt.addItem(item);

                    expect(selleckt.items.length).toEqual(4);
                    expect(selleckt.items[3]).toEqual(item);
                });

                it('appends a new option to the original select', function(){
                    var $originalSelectEl = selleckt.$originalSelectEl;

                    expect($originalSelectEl.children().length).toEqual(3);

                    selleckt.addItem(item);

                    expect($originalSelectEl.children().length).toEqual(4);

                    var newOption = $originalSelectEl.find('option').eq(3);

                    expect(newOption.text()).toEqual('new');
                    expect(newOption.val()).toEqual('new value');
                });

                describe('and the new item has selected:true', function(){
                    var originalSelection;

                    beforeEach(function(){
                        originalSelection = selleckt.$originalSelectEl.find('option:selected');
                        item.isSelected = true;
                    });

                    it('selects the new item in the original select', function(){
                        expect(originalSelection.val()).toEqual('1');

                        selleckt.addItem(item);

                        var newSelection = selleckt.$originalSelectEl.find('option:selected');

                        expect(newSelection.length).toEqual(1);
                        expect(newSelection.val()).toEqual('new value');
                    });

                    it('displays the item text in the selleckt element', function(){
                        selleckt.addItem(item);

                        expect(selleckt.$sellecktEl.find('.'+selleckt.selectedTextClass).text()).toEqual(item.label);
                    });
                });
            });

            describe('using addItems to add an array of items', function(){
                var items;

                beforeEach(function(){
                    items = [
                        { label: 'new 1', value: 'new value 1' },
                        { label: 'new 2', value: 'new value 2' },
                        { label: 'new 3', value: 'new value 3' }
                    ];
                });

                afterEach(function(){
                    items = undefined;
                });

                it('adds the items to this.items', function(){
                    expect(selleckt.items.length).toEqual(3);

                    selleckt.addItems(items);

                    expect(selleckt.items.length).toEqual(6);
                    expect(selleckt.items[3]).toEqual(items[0]);
                    expect(selleckt.items[4]).toEqual(items[1]);
                    expect(selleckt.items[5]).toEqual(items[2]);
                });

                it('appends new options to the original select', function(){
                    var $originalSelectEl = selleckt.$originalSelectEl;

                    expect($originalSelectEl.children().length).toEqual(3);

                    selleckt.addItems(items);

                    expect($originalSelectEl.children().length).toEqual(6);

                    var newOption1 = $originalSelectEl.find('option').eq(3);
                    expect(newOption1.text()).toEqual('new 1');
                    expect(newOption1.val()).toEqual('new value 1');

                    var newOption2 = $originalSelectEl.find('option').eq(4);
                    expect(newOption2.text()).toEqual('new 2');
                    expect(newOption2.val()).toEqual('new value 2');

                    var newOption3 = $originalSelectEl.find('option').eq(5);
                    expect(newOption3.text()).toEqual('new 3');
                    expect(newOption3.val()).toEqual('new value 3');
                });

                describe('and a new item has selected:true', function(){
                    var originalSelection;

                    beforeEach(function(){
                        originalSelection = selleckt.$originalSelectEl.find('option:selected');
                        items[0].isSelected = true;
                    });

                    it('selects the new item in the original select', function(){
                        expect(originalSelection.val()).toEqual('1');

                        selleckt.addItems(items);

                        var newSelection = selleckt.$originalSelectEl.find('option:selected');

                        expect(newSelection.length).toEqual(1);
                        expect(newSelection.val()).toEqual('new value 1');
                    });

                    it('displays the item text in the selleckt element', function(){
                        selleckt.addItems(items);

                        expect(selleckt.$sellecktEl.find('.'+selleckt.selectedTextClass).text()).toEqual(items[0].label);
                    });
                });
            });
        });

        describe('Removing items', function(){
            var removeItemValue;

            beforeEach(function(){
                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });

                selleckt.render();
            });

            afterEach(function(){
                selleckt.destroy();
                selleckt = undefined;
            });

            describe('and the removed item is not selected', function(){
                beforeEach(function(){
                    removeItemValue = selleckt.items[2].value;
                });

                it('removes the item from this.items', function(){
                    expect(selleckt.items.length).toEqual(3);
                    expect(selleckt.findItem(removeItemValue)).toBeDefined();

                    selleckt.removeItem(removeItemValue);

                    expect(selleckt.items.length).toEqual(2);
                    expect(selleckt.findItem(removeItemValue)).toBeUndefined();
                });

                it('removes the option with the corresponding value from the original select', function(){
                    var $originalSelectEl = selleckt.$originalSelectEl;

                    expect($originalSelectEl.children().length).toEqual(3);
                    expect($originalSelectEl.find('option[value="' + removeItemValue + '"]').length).toEqual(1);

                    selleckt.removeItem(removeItemValue);

                    expect($originalSelectEl.children().length).toEqual(2);
                    expect($originalSelectEl.find('option[value="' + removeItemValue + '"]').length).toEqual(0);
                });
            });

            describe('and the removed item is selected', function(){
                beforeEach(function(){
                    removeItemValue = selleckt.selectedItem.value;
                });

                it('sets this.selectedItem to undefined if it has the value of the item being removed', function(){
                    expect(selleckt.selectedItem).toBeDefined();

                    selleckt.removeItem(removeItemValue);

                    expect(selleckt.selectedItem).toBeUndefined();
                });

                it('sets the placeholder text back', function(){
                    expect(selleckt.$sellecktEl.find('.'+selleckt.selectedTextClass).text()).toEqual(selleckt.selectedItem.label);

                    selleckt.removeItem(removeItemValue);

                    expect(selleckt.$sellecktEl.find('.'+selleckt.selectedTextClass).text()).toEqual(selleckt.placeholderText);
                });
            });

        });

        describe('showing the popup', function(){
            var $selectedItem,
                makePopupStub;

            beforeEach(function(){
                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });

                makePopupStub = sandbox.stub(selleckt, '_makePopup');

                selleckt.render();

                $selectedItem = selleckt.$sellecktEl.find('.'+selleckt.selectedClass);
            });

            afterEach(function(){
                selleckt._close();

                $selectedItem = undefined;
            });

            it('shows the popup on click on the selected item', function(){
                $selectedItem.trigger('click');

                expect(makePopupStub.calledOnce).toEqual(true);
            });

            it('does not call _makePopup when the popup is already showing', function(){
                $selectedItem.trigger('click');

                expect(makePopupStub.calledOnce).toEqual(true);

                makePopupStub.reset();

                $selectedItem.trigger('click');

                expect(makePopupStub.called).toEqual(false);
            });

            it('calls "_close" when the body is clicked', function(){
                var closeSpy = sandbox.spy(selleckt, '_close');

                selleckt._open();

                $(document).trigger('click');

                expect(closeSpy.calledOnce).toEqual(true);
            });

            it('triggers a "close" event when _close is called', function(){
                var listener = sinon.stub();

                selleckt.bind('close', listener);
                selleckt._close();

                expect(listener.calledOnce).toEqual(true);

                selleckt.unbind('close', listener);
            });

            it('adds a class of "open" to this.$sellecktEl when the selleckt is opened', function(){
                selleckt._open();

                expect(selleckt.$sellecktEl.hasClass('open')).toEqual(true);
            });

            it('removes the class of "closed" from this.$sellecktEl when the selleckt is closed', function(){
                expect(selleckt.$sellecktEl.hasClass('closed')).toEqual(true);

                selleckt._open();

                expect(selleckt.$sellecktEl.hasClass('closed')).toEqual(false);
            });

            it('removes the  "open" class from this.$sellecktEl when the selleckt is closed', function(){
                selleckt._open();

                expect(selleckt.$sellecktEl.hasClass('open')).toEqual(true);

                selleckt._close();

                expect(selleckt.$sellecktEl.hasClass('open')).toEqual(false);
            });

            it('adds a class of "closed" to this.$sellecktEl when the selleckt is closed', function(){
                selleckt._open();

                expect(selleckt.$sellecktEl.hasClass('closed')).toEqual(false);

                selleckt._close();

                expect(selleckt.$sellecktEl.hasClass('closed')).toEqual(true);
            });

            it('binds to click event on document when options are shown', function(){
                var eventsData;

                selleckt._open();

                eventsData = $._data(document, 'events');

                expect(eventsData.click).toBeDefined();
                expect(eventsData.click.length).toEqual(1);
                expect(eventsData.click[0].namespace).toEqual('selleckt-' + selleckt.id);
            });
        });

        describe('when the popup closes', function(){
            var closeSpy;

            beforeEach(function(){

                closeSpy = sandbox.spy(SingleSelleckt.prototype, '_close');

                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });

                selleckt.render();
            });

            it('calls selleckt._close if selleckt is open', function(){
                selleckt._open();

                selleckt.popup.trigger('close');

                expect(closeSpy.calledOnce).toEqual(true);
            });

            it('sets tabindex to -1 on the selleckt element if selleckt is open', function(){
                selleckt._open();

                selleckt.popup.trigger('close');

                expect(selleckt.$sellecktEl.attr('tabindex')).toEqual('-1');
            });
        });

        describe('popup options', function(){
            var popup;
            var outerWidthStub;
            var cssStub;
            var dummyWidth;

            beforeEach(function(){
                dummyWidth = 100;
                outerWidthStub = sandbox.stub($.fn, 'outerWidth').returns(dummyWidth);
                cssStub = sandbox.stub($.fn, 'css');

                selleckt = new SingleSelleckt({
                    $selectEl : $el,
                    itemsClass: 'items',
                    itemslistClass: 'itemslist',
                    itemClass: 'item',
                    itemTextClass: 'itemText',
                    searchInputClass: 'search',
                    showSearch: true
                });

                selleckt.render();
                selleckt._open();

                popup = selleckt.popup;
            });

            afterEach(function(){
                selleckt._close();
            });

            it('passes this.popupTemplate to the popup', function(){
                expect(popup.template).toEqual(selleckt.popupTemplate);
            });

            it('passes this.popupTemplateData to the popup', function(){
                expect(popup.templateData).toEqual(selleckt.popupTemplateData);
            });

            it('passes this.itemTemplate to the popup', function(){
                expect(popup.itemTemplate).toEqual(selleckt.itemTemplate);
            });

            it('passes this.itemsClass to the popup', function(){
                expect(popup.itemsClass).toEqual(selleckt.itemsClass);
            });

            it('passes this.itemslistClass to the popup', function(){
                expect(popup.itemslistClass).toEqual(selleckt.itemslistClass);
            });

            it('passes this.itemClass to the popup', function(){
                expect(popup.itemClass).toEqual(selleckt.itemClass);
            });

            it('passes this.itemTextClass to the popup', function(){
                expect(popup.itemTextClass).toEqual(selleckt.itemTextClass);
            });

            it('passes this.searchInputClass to the popup', function(){
                expect(popup.searchInputClass).toEqual(selleckt.searchInputClass);
            });

            it('passes this.showSearch to the popup', function(){
                expect(popup.showSearch).toEqual(selleckt.showSearch);
            });

            it('passes the outer width of the selleckt element to the popup as options.css', function(){
                expect(outerWidthStub.calledOnce).toEqual(true);
                expect(outerWidthStub.thisValues[0].is(selleckt.$sellecktEl)).toEqual(true);

                expect(cssStub.thisValues[1].is(popup.$popup));
                expect(cssStub.args[0][0]).toEqual({minWidth: dummyWidth + 'px'});
            });
        });

        describe('item selection', function(){
            var popup;

            beforeEach(function(){
                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });

                selleckt.render();
                selleckt._open();

                popup = selleckt.popup;
            });

            afterEach(function(){
                selleckt._close();
            });

            it('allows an item to be selected by value', function(){
                var dummyItem = {value: 100};
                var options = {foo: 'bar'};
                var selectItemStub = sandbox.stub(SingleSelleckt.prototype, 'selectItem');

                sandbox.stub(SingleSelleckt.prototype, 'findItem').returns(dummyItem);

                selleckt.selectItemByValue(100, options);

                expect(selectItemStub.calledOnce).toEqual(true);
                expect(selectItemStub.args[0][0]).toEqual(dummyItem);
                expect(selectItemStub.args[0][1]).toEqual(options);
            });

            it('does nothing if the selectItemByValue is called with a value that does not exist', function () {
                var selectItemStub = sandbox.stub(SingleSelleckt.prototype, 'selectItem');

                sandbox.stub(SingleSelleckt.prototype, 'findItem').returns(undefined);

                selleckt.selectItemByValue(100);

                expect(selectItemStub.called).toEqual(false);
            });

            it('does not allow multiple items to be selected', function(){
                popup.trigger('valueSelected', '2');

                expect(selleckt.selectedItem).toEqual({
                    value: '2',
                    label: 'bar',
                    data: {
                        bah: 'oink',
                        meh: 'whee'
                    }
                });

                popup.trigger('valueSelected', '1');

                expect(selleckt.selectedItem).toEqual({
                    value: '1',
                    label: 'foo',
                    data: {}
                });
            });

            it('updates the text of the selected item container with the selectedItem\'s label', function(){
                popup.trigger('valueSelected', '2');

                expect(selleckt.$sellecktEl.find('.'+selleckt.selectedTextClass).text()).toEqual('bar');
            });

            it('triggers an "itemSelected" event with this.selectedItem', function(){
                var spy = sandbox.spy();

                selleckt.bind('itemSelected', spy);

                popup.trigger('valueSelected', '2');

                expect(spy.calledOnce).toEqual(true);
                expect(spy.args[0][0]).toEqual(selleckt.selectedItem);
            });

            it('does not trigger an event when the selected item is clicked, were it to be unhidden', function(){
                var spy = sinon.spy();

                popup.trigger('valueSelected', '1');

                selleckt.bind('itemSelected', spy);

                popup.trigger('valueSelected', '1');
                expect(spy.called).toEqual(false);
            });

            it('updates the original select element with the new value', function(){
                popup.trigger('valueSelected', '2');

                expect(selleckt.$originalSelectEl.val()).toEqual('2');
            });

            it('updates selleckt when change is triggered on original select', function(){
                selleckt.$originalSelectEl.val('2').change();

                expect(selleckt.getSelection().value).toEqual('2');
            });

            it('updates selleckt when change is triggered on original select with no value', function(){
                selleckt.$originalSelectEl.val('').change();

                expect(selleckt.getSelection().value).toBeUndefined();
            });

            it('does not update selleckt when change on original select is triggered by selleckt itself', function(){
                selleckt.$originalSelectEl.val('2').trigger('change', {origin: 'selleckt'});

                expect(selleckt.getSelection().value).toEqual('1');
            });

            it('triggers a change event on original select when item is selected', function(){
                var changeHandler = sinon.spy();

                selleckt.$originalSelectEl.on('change', changeHandler);

                popup.trigger('valueSelected', '2');

                expect(changeHandler.calledOnce).toEqual(true);
                expect(changeHandler.args[0].length).toEqual(2);
                expect(changeHandler.args[0][1].origin).toEqual('selleckt');

                selleckt.$originalSelectEl.off('change', changeHandler);
            });

            describe('with an empty option', function(){
                it('displays the placeholder when the change event is triggered on ' +
                        'the original select and its value is the empty string', function(){

                    selleckt.$originalSelectEl.append('<option></option>');

                    selleckt.$originalSelectEl.val('').trigger('change');

                    var emptyOptionDisplayedText = selleckt.$sellecktEl.find('.selectedText').text();

                    expect(emptyOptionDisplayedText).toEqual(selleckt.placeholderText);
                });
            });

            describe('hiding the selected item', function(){
                it('hides the selected item from the list if this.hideSelectedItem == true', function(){
                    expect(selleckt.getItemsForPopup().length).toEqual(3);

                    selleckt.hideSelectedItem = true;

                    expect(selleckt.getItemsForPopup().length).toEqual(2);
                });
                it('does not hide the selected item from the list if this.hideSelectedItem == false', function(){
                    expect(selleckt.getItemsForPopup().length).toEqual(3);

                    selleckt.hideSelectedItem = false;

                    expect(selleckt.getItemsForPopup().length).toEqual(3);
                });
            });
        });

        describe('Keyboard input', function(){
            var $selectedItem,
                KEY_CODES = {
                    DOWN: 40,
                    UP: 38,
                    ENTER: 13,
                    ESC: 27
                };

            beforeEach(function(){
                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });

                selleckt.render();

                $selectedItem = selleckt.$sellecktEl.find('.'+selleckt.selectedClass);

                selleckt.$sellecktEl.focus();
            });

            afterEach(function(){
                selleckt._close();
                $selectedItem = undefined;
            });

            it('opens the items list when enter is pressed on a closed selleckt', function(){
                expect(selleckt.$sellecktEl.hasClass('open')).toEqual(false);

                var makePopupStub = sandbox.stub(selleckt,  '_makePopup');

                $selectedItem.trigger($.Event('keydown', { which : KEY_CODES.ENTER }));

                expect(selleckt.$sellecktEl.hasClass('open')).toEqual(true);

                expect(makePopupStub.calledOnce).toEqual(true);
            });

            it('resets focus to selleckt after item is selected', function(){
                selleckt._open();
                selleckt.popup.trigger('itemSelected', '2');

                var focusStub = sandbox.stub($.fn, 'focus');
                selleckt.popup.close();

                expect(focusStub.callCount).toEqual(1);
                expect(focusStub.thisValues[0].is(selleckt.$sellecktEl)).toEqual(true);
            });
        });

        describe('search', function(){
            var selectHtml = '<select>' +
                    '<option value>Empty</option>' +
                    '<option value="foo">foo</option>' +
                    '<option value="bar">bar</option>' +
                    '<option value="baz">baz</option>' +
                    '<option value="foofoo">foofoo</option>' +
                    '<option value="foobaz">foobaz</option>' +
                    '</select>';

            var $searchInput;

            afterEach(function(){
                selleckt._close();
                $searchInput = undefined;
            });

            describe('rendering', function(){
                it('shows the search input if settings.enableSearch is true and ' +
                    'there are more items than options.searchThreshold', function(){
                    selleckt = new SingleSelleckt({
                        $selectEl : $(selectHtml),
                        enableSearch: true,
                        searchThreshold: 0
                    });

                    selleckt.render();
                    selleckt._open();

                    expect(selleckt.popup.$popup.find('.' + selleckt.searchInputClass).length).toEqual(1);
                });

                it('does not display a searchbox if settings.enableSearch is true and ' +
                        'there are fewer items than options.searchThreshold', function(){
                    selleckt = new SingleSelleckt({
                        $selectEl : $(selectHtml),
                        enableSearch: true,
                        searchThreshold: 100
                    });

                    selleckt.render();
                    selleckt._open();

                    expect(selleckt.popup.$popup.find('.' + selleckt.searchInputClass).length).toEqual(0);
                });

                it('does not display a searchbox if settings.enableSearch is false', function(){
                    selleckt = new SingleSelleckt({
                        $selectEl : $(selectHtml),
                        enableSearch: false
                    });

                    selleckt.render();
                    selleckt._open();

                    expect(selleckt.popup.$popup.find('.' + selleckt.searchInputClass).length).toEqual(0);
                });
            });
        });

        describe('filtering', function(){
            it('filters out options with empty values', function(){
                var selleckt = new SingleSelleckt({
                    $selectEl: $('<select>')
                });

                selleckt.items = [
                    {label: 'Empty'},
                    {label: 'Foo', value: '1'},
                ];

                var filteredItems = selleckt._filterItems(selleckt.items, 'foo');

                expect(filteredItems.length).toEqual(1);
                expect(filteredItems[0]).toEqual({ label: 'Foo', value: '1', matchStart: 0, matchEnd: 2 });
            });

            it('can annotate the items with matchIndexes', function(){
                var selleckt = new SingleSelleckt({
                    $selectEl: $('<select>')
                });

                selleckt.items = [
                    {label: 'foo', value: 'foo'},
                    {label: 'bar', value: 'bar'},
                    {label: 'baz', value: 'baz'},
                    {label: 'foofoo', value: 'foofoo'},
                    {label: 'foobaz', value: 'foobaz'}
                ];

                var filteredItems = selleckt._filterItems(selleckt.items, 'ba');

                expect(filteredItems).toEqual([
                    { label: 'bar', value: 'bar', matchStart: 0, matchEnd: 1 },
                    { label: 'baz', value: 'baz', matchStart: 0, matchEnd: 1 },
                    { label: 'foobaz', value: 'foobaz', matchStart: 3, matchEnd: 4 }
                ]);
            });

            it('performs a case-insensitive search', function(){
                var selleckt = new SingleSelleckt({
                    $selectEl: $('<select>')
                });

                selleckt.items = [
                    {label: 'foo', value: 'foo'},
                    {label: 'bar', value: 'bar'},
                    {label: 'baz', value: 'baz'},
                    {label: 'foofoo', value: 'foofoo'},
                    {label: 'foobaz', value: 'foobaz'}
                ];

                var filteredItems = selleckt._filterItems(selleckt.items, 'BA');

                expect(filteredItems).toEqual([
                    { label: 'bar', value: 'bar', matchStart: 0, matchEnd: 1 },
                    { label: 'baz', value: 'baz', matchStart: 0, matchEnd: 1 },
                    { label: 'foobaz', value: 'foobaz', matchStart: 3, matchEnd: 4 }
                ]);
            });

            it('does not refresh the popup with this.selectedItem, if this.hideSelectedItem === true', function() {
                selleckt = new SingleSelleckt({
                    $selectEl : $('<select>' +
                        '<option value="foo">foo</option>' +
                        '<option value="bar">bar</option>' +
                        '<option value="baz">baz</option>' +
                        '</select>'),
                    enableSearch: true,
                    searchThreshold: 0,
                    hideSelectedItem: true
                });

                selleckt.selectItemByValue('bar');

                selleckt.render();
                selleckt._open();

                selleckt._refreshPopupWithSearchHits('ba');

                expect(selleckt.popup.$popup.find('.item').length).toEqual(1);
                expect(selleckt.popup.$popup.find('.item[data-value=bar]').length).toEqual(0);
                expect(selleckt.popup.$popup.find('.item[data-value=baz]').length).toEqual(1);
            });

            it('triggers an "optionsFiltered" event after filtering, passing the filter term', function(){
                var spy = sandbox.spy();

                selleckt = new SingleSelleckt({
                    $selectEl : $('<select><option value="foo">foo</option><option value="bar">bar</option></select>'),
                    enableSearch: true,
                    searchThreshold: 0
                });

                selleckt.render();
                selleckt._open();

                selleckt.bind('optionsFiltered', spy);

                selleckt._refreshPopupWithSearchHits('ba');

                expect(spy.callCount).toEqual(1);
                expect(spy.args[0][0]).toEqual('ba');

                selleckt._close();
                selleckt.destroy();
            });
        });

        describe('removal', function(){
            beforeEach(function(){
                selleckt = new SingleSelleckt({
                    $selectEl : $el
                });
                selleckt.render();
            });
            afterEach(function(){
                selleckt = undefined;
            });

            it('removes change event from original select element', function(){
                var eventsData = $._data(selleckt.$originalSelectEl[0], 'events');

                expect(eventsData.change).toBeDefined();
                expect(eventsData.change.length).toEqual(1);
                expect(eventsData.change[0].namespace).toEqual('selleckt');

                selleckt.destroy();

                expect(eventsData.change).toEqual(undefined);
            });

            it('removes selleckt data from original select element', function(){
                $el.data('selleckt', selleckt);

                selleckt.destroy();

                expect($el.data('selleckt')).toEqual(undefined);
            });

            it('shows original select element', function(){
                expect($el.css('display')).toEqual('none');

                selleckt.destroy();

                expect($el.css('display')).toEqual('inline-block');
            });

            it('stops observing mutation events', function(){
                var stopObservingMutationsSpy = sinon.spy(selleckt, '_stopObservingMutations');

                selleckt.destroy();

                expect(stopObservingMutationsSpy.calledOnce).toEqual(true);
            });

        });
    });
}

(function (root, factory) {
    if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like enviroments that support module.exports,
        // like Node.
        var selleckt = require('../../lib/selleckt');

        factory(exports = singleSellecktSpecs,
                selleckt.SingleSelleckt,
                selleckt.templateUtils,
                require('jquery'),
                require('underscore')
            );
    } else {
        // Browser globals
        factory(
            root.singleSellecktSpecs,
            root.selleckt.SingleSelleckt,
            root.selleckt.templateUtils,
            root.$,
            root._
        );
    }
}(this, function (exports, SingleSelleckt, templateUtils, $, _) {
    return singleSellecktSpecs(SingleSelleckt, templateUtils, $, _);
}));


JUAN MATA is a January target for La Liga side Sevilla.
The 26-year-old Spaniard has struggled to break into Manchester United's starting 11 this term despite putting in a number of good performances.
Speculation has been growing over Mata's future with Juventus, Valencia and Atletico Madrid all said to be interested in the former Chelsea man.
The Mirror report that United are reluctant to lose Mata in January but with defensive recruitments a priority for Louis van Gaal they could be tempted to cash in.
Van Gaal is not short of options in the middle of the park but they would rather keep hold of Mata until the summer when a move for Kevin Strootman look to be a priority.
The Roma midfielder is proving his fitness following a lengthy lay off with injury and Van Gaal is said to be monitoring his situation extremely closely.
Mata moved to Old Trafford in January for a then club-record fee of £37.5m but United are not expecting to be able to fetch that kind of money for him this time around.


text:
customer journeys per year
Transdev is at the heart of keeping communities moving, providing public transport services in six locations in Australia and New Zealand.
We pride ourselves on leading the way in public transport through the collaboration of our teams and a shared commitment to excellence in all that we do. We specialise in the operation and maintenance of a number of transport modes, including passenger trains, light rail, ferries, buses, coaches, on demand transport and autonomous shuttles.
Transdev Network
INTERCITY NETWORKS
PRIVATE ACTIVITIES & AIRPORTS
URBAN NETWORKS
MARITIME & FLUVIAL TRANSPORTATION
{{desc_reseau}}
{{modes_reseau}}
{{link_reseau}}
Our locations in Australasia
Our Solutions in Australia and New Zealand
Transdev operates metropolitan bus services on behalf of TransLink, providing urban, school and charter services to the local community. Our Brisbane Capalaba depot also houses our Engineering Centre for Excellence and hub for zero emissions technology development.
More on Brisbane bus
Transdev operates Sydney Ferries, Sydney's Light Rail network, and bus services in South Sydney, South West Sydney and Sydney's North Shore on behalf of Transport for NSW.
More on Sydney bus
More on Sydney light rail
More on Sydney ferry
Transdev provides bus services for a third of Melbourne's bus network on behalf of Public Transport Victoria. Our team of more than 1,200 employees operates 47 routes, with a fleet in excess of 500 vehicles. Both urban and school services are covered by Transdev, including orbital services connecting Melbourne's suburbs.
More on Melbourne bus
Transdev is one of Perth's largest bus operators, providing metropolitan bus services on behalf of Transperth. We operate services in the Rockingham, Mandurah, Fremantle and Perth areas including the free Central Area Transit (CAT) buses.
More on Perth bus
Transdev is proud to have operated the Auckland Rail Franchise between 2004 and 2022 helping to grow patronage and connect Aucklanders every day.
Together we worked with Auckland Transport and our many stakeholders to make the city a better place, of which we are extremely proud.
In Auckland, our team operate Howick and Eastern Buses.
More on Auckland buses
In Wellington we work in partnership with Hyundai Rotem to operate and maintain the city's passenger train network on behalf of Greater Wellington Regional Council. We run more than 2,100 services each week facilitated by our team of more than 430 people. Since 2019, we have proudly delivered more than 3 million bus journeys with Mana Coach Services, a Transdev company.
More on Wellington trains
More on Wellington buses
Transdev operated its first autonomous shuttle service in Australia in partnership with the Armidale Regional Council in 2019, as part of Transport for NSW's connected and automated vehicle trials.
vehicles and vessels
modes of transport
first year in Australia
Living•Lab
Become a member of the Living Lab Club
We are excited to say creating greener connections in Sydney's CBD and Eastern Suburbs will be a key focus for [...]
YouTube makes the playback of its videos conditional on the deposit of tracers in order to offer you targeted advertising based on your navigation.
By clicking on "authorize", the trackers will be deposited and you will be able to view the video. You can withdraw your consent at any time.
Transdev, the mobility company
Are you looking for more information about driving and ferry master roles, mechanical and maintenance roles, customer service roles, office based roles, opportunities for graduates and interns
Transdev is offering you the opportunity to move forward in an exciting and changing world of transport
Experience a day in the life of Transdev as we connect communities across Australia and New Zealand.
As an operator and global integrator of mobility, Transdev gives people the freedom to move wherever and however they choose. Transdev is proud to move 11 million people around the world every day thanks to efficient, easy to use and environmentally-friendly transportation services that connect people and communities. Locally, Transdev is the largest provider of multi-modal public transport, operating services across Australia and New Zealand since 1998. Our team of 5,800 employees move 130 million people a year across our seven modes – heavy rail, light rail, bus, coach, ferry, on demand and autonomous shuttles – in Armidale, Brisbane, Darwin, Melbourne, Perth, Sydney, Auckland and Wellington.
Our approach is rooted in long-term partnerships with businesses and public authorities, and in the relentless pursuit of the safest and most innovative mobility solutions. At Transdev, we are Journey Makers. We believe public transport plays an important part in how a city comes to life. Our day-today work influences our families, friends and future generations where they live, work and play.

redpajama_set_name: RedPajamaCommonCrawl


Sign-Up Here and Get a Free Holiday Letter from the Christmas Markets in Vienna!
Library of Congress recognizes our consortium members for improving access to reading for children with physical disabilities.
Our team discusses the importance of global education, storytelling and more on Washington DC's WPFW 89.3 District Timba. Hear the audio below. January 2018.
Chance Academy Executive Director Anna Bernanke's Keynote Speech on Education as Social Justice at the Gateway CDC 20th Anniversary Gala. At the event, Global Sleepover and Chance Academy officially announced a partnership to open a school and global learning space in 2018.
Global Sleepover is proud to have been nominated for a 2017 UNESCO Literacy Prize.


text:
Play For Me Tour and Giveaway!
Play For Me
The Balefire Series Book 1
by Tam Derudder Jackson
All I wanted was a chance. Now I need a second one.
When I made my deal with the devil, I thought I was on my way to my rock 'n' roll dream. Too bad I didn't read the fine print. Having it all meant giving up the only girl I knew I'd ever love. Five years later, I'm drumming in the hottest rock band in the country, but I live like a monk.
Fate hands me an opportunity to reconnect with my perfect girl, giving me one glorious night with Clio Barnes. Our chemistry is off the charts. Too bad fate plays by her own rules. When Clio hears my bandmate's idea of a joke, she believes I've used her, dissolved our love into a one-night stand, and she blows out of my life. When our tour ends, I'm determined to find her again, no matter how well she hides from me.
All my life, I've been invisible. For a brief moment five years ago, Jack Whitehorse saw me. And he made me feel like the center of his universe. But that was an illusion. Music was Jack's only love. A chance encounter after a Balefire concert allows us to reconnect, but once again, I'm playing second fiddle to his rock 'n' roll muse.
When the pregnancy test comes back positive, I decide to keep our baby secret. I can't force Jack to play for me—I wouldn't want to. Then he shows up unexpectedly one day, knocking on my door and demanding to be let in. He leaves me no choice but to tell him about the baby. Turns out, I wasn't the only one with a secret. But the one he's been keeping might end us for good.
Amazon * B&N * Kobo
Tam DeRudder Jackson is the author of the paranormal romance Talisman Series and the contemporary romance Balefire Series. Her favorite "room" in her house is her back patio where she dreams up stories of romance and risk. When she's not writing her latest paranormal or contemporary romance, you can usually find her driving around with the top down in her convertible or carving turns on the slopes of the local ski hill. The mom of two grown sons, Tam likes to travel, attend rock concerts, watch football and soccer, and visit old car shows with her husband. She lives in the mountains of northwest Wyoming where she spends most of her free time trying to read all the books. Her TBR piles are threatening to take over her office, and she's fine with that.
Website * Facebook * Instagram * Bookbub * Amazon * Goodreads
Follow the tour HERE for special content and a giveaway!
$25 Amazon giftcard (WW),
Guitar Spoon (winner's choice of color, US only)
- 1 winner
Posted by DanielleDuncan at 16:11 1 comment:
Hazelhearth Hires Heroes REVEAL
Fantasy Adventure/Fantasy Humor
Welcome to Hazelhearth: our picturesque city is nestled in a tranquil corner of the empire. Fitness lovers enjoy vigorous nature walks in the surrounding forest (don't forget your sword!) Foodies savor rich, robust walnut-based cuisine. Or visit the gnome quarter for a walk on the wild side! Local mines and orchards beckon with plentiful employment opportunities, while workers sleep safe knowing that stout city walls keep mythic monsters at bay. A select few may even be chosen for exciting quest opportunities.
The onslaught of subterranean hordes? Oh, that's happening miles away. And the elves have it completely under control.
Inquire today at the Hazelhearth board of tourism, employment, and heroics!
How could Sam and Lee say no? Lee is bored to tears as a telegrapher. His only excitement in life is the revolutionary new board game he's creating. And of course constant disruptions at work by Sam, whose high voltage experiments wreak havoc with nearby electric systems. These two best buddies… colleagues... acquaintances are ready to escape from 19th century America into a more exciting world!
DH Willison is a reader, writer, game enthusiast and developer, engineer, and history buff. He has lived around the world, absorbing history, culture, and food. Actually, he has eaten the food. It has been verified that he is a complex, multicellular life form. Fascinated by nature, technology, and history, and especially anything that can put all three of these together, he has an annoying habit of dragging his wife to the most unromantic destinations imaginable, including outdoor museums, authentic castle dungeons, the holds of tall ships, and even the tunnels of the Maginot Line.
Posted by DanielleDuncan at 16:06 No comments:
Debt Bomb Release #Blitz
Thriller/Suspense/Spy Fiction/Political Fiction
Date Published: July 1, 2021
Publisher: BQB Publishing
China hungers to take the United States' place as the global hegemon.
And it is plotting to use America's $40 trillion national debt to do it.
Only one person stands in China's way: suburban accountant Andrea Gartner.
For years she has dreaded the day of America's reckoning about its national debt. She's gotten involved in local politics. She's run for Congress. But the debt marches remorselessly higher.
Rejected by her party in her congressional race, she joins the insurgent presidential campaign of Congressman Earl Murray. When he wins in an upset, he defies all Washington convention and names Andrea his Director of the Office of Management and Budget. The Washington rookie finally has her chance to solve America's debt addition.
But China has other plans, engineering financial crises and military confrontations designed to bankrupt and collapse the United States. Wars rage overseas as America's health care system, schools, and social fabric disintegrate. Desperately coping with these existential threats to America's very existence, Andrea finds herself enmeshed in vicious Washington infighting with belligerent military brass and ruthless politicians, including the powerful and complicated Congressman Lewis Mason and his chief of staff Frank Palmer. Chinese agents lurk in the shadows, threatening Andrea's life and family, as she struggles to keep the country afloat.
No aspect of American life is spared as the country teeters on the brink of financial collapse. Can Andrea stave off China's assault and ensure the United States survives? Or will the Red Chinese flag fly over the American Capitol?
Debt Bomb is a sobering fictional account of a future facing the United States if it fails to control its debt and get its financial house in order.
Michael E. Ginsberg is an attorney in Washington, DC practicing in the field of national security law. He spent a decade in private practice at Arnold & Porter LLP in Washington, DC and then worked several years in the U.S. government as a Senior Associate General Counsel in the Office of the Director of National Intelligence (ODNI), where he served as legal counsel for the Intelligence Advanced Research Projects Activity (IARPA). He currently is Vice President and Deputy General Counsel at a Virginia-based defense contractor.
Ginsberg has also served in senior leadership positions in the Republican Party of Virginia and is the co-founder of the Suburban Virginia Republican Coalition.
A 1997 graduate of Harvard College and 2002 graduate of Harvard Law School, he also holds a master's in aeronautics and astronautics from Stanford University (1999). A native of Baltimore, Maryland, Ginsberg lives in Virginia with his wife and two children.
BQB Publishing
The Prophecy #Blitz
When Darkness Falls, Book 3
Paranormal Romance, Fantasy Romance, Vampire Romance
The truce between humans and vampires has stabilized as the relationship between Alyssa and Lord Damien deepens. When a desperate group of refugees arrive at the city, bringing tales of a barbaric horde overrunning the lands to the west, the city's resources are strained to assimilate them.
Just as life is settling back to normal, the worst of news arrives from scouts sent out to spy on the horde. The massive army is gearing up with plans to brave the hundreds of miles of stark desert to attack Al Khair itself, and Lord Damien must decide whether to follow their long code of non-involvement of human affairs, or to work with the humans to save their city.
*Please Note, this is a trilogy, with one sweeping story arc divided into three volumes. The books are not meant to be read alone, or out of order. If you prefer, you can buy all 3 volumes of the trilogy together in a boxed eBook set, When Darkness Falls: The Trilogy – Amazon
Want the Whole Trilogy in One Book?
When Darkness Falls: The Trilogy
Ruled by a gracious, wise Sultana, the humans of the great desert city of Al Khair dwell in uneasy peace with the vampires and demons who claim the lands as their ancestral homelands under the leadership of an ancient, powerful vampire. Their shaky truce becomes strained when a young human woman arrives from distant lands.
Orphaned since childhood and outcast, Alyssa joins a caravan to the fabled Al Khair where she seeks only to make a new life for herself. A life that quickly becomes complicated when she draws the attention of the Dark Lord himself.
A thousand years ago, Lord Damien permitted the humans to build their city. When he senses a new, immensely powerful magical being in the land, Damien suspects the humans of plotting to overthrow him. Furious, he searches for the source of this power, but he cannot stop thinking of the young woman in the tower who had seen through his glamour spell that cloaks him from humans.
When he discovers that Alyssa is the mysterious being he has been seeking, his determination to have her for his own threatens to pit the two races, human and vampire, against each other in all-out war.
A former career medical transcriptionist and disabled Veteran, Allie McCormack is now writing from home full-time. Allie has traveled quite a bit and lived many places all over the U.S., and also a year in Cairo, Egypt as an exchange student, and a year in Riyadh, Saudi Arabia under contract to a hospital there, plus a short stint with NATO while she was in the Army. Allie now lives in the beautiful southern California with her family and her two rescue cats.
Allie says: "A writer is who and what I am… a romance writer. I write what I know, and what I know is romance. Dozens of story lines and literally hundreds of characters live and breathe within the not-so-narrow confines of my imagination, and it is my joy and privilege to bring them to life, to share them with others by writing their stories."
Paintings & Enemies by Ella Todd #CoverReveal
Paintings & Enemies
Ella Todd
She didn't know he only left her to protect her…
Super-model Aubrey Duncan was excited when her father asked her to be the family company's spokesperson—until she met the new head of marketing. Eric Juárez was sexy as hell, yet he ended up being the first man to break her heart.
Years later, Eric believes he left his feelings for Aubrey in the past. The hardest thing he ever had to do was leave her—but he did it for her own good. When he's forced to see her again, though, he realizes just how wrong he was. But after their meeting, he understands Aubrey's hatred for him runs deep. Now, for the second time, he's forced to dismiss his love for his beautiful girl.
Consumed by bitterness but unwilling to disappoint her father, Aubrey bites the bullet and agrees to work with Eric, even though she can't get past her anger at him for how their relationship ended. But little does she know, Aubrey isn't the only one out for his blood. Eric's return also brings back his mistakes, which forces the unwilling pair to stick together… if only to survive the psychopath intent on killing them both.
Add to Goodreads / Pre-order
Ella Todd is the contemporary romance pen name for USA Today Bestselling Author D.H. Gibbs. Both personalities are complete Starbucks and book addict who binge-watches TV series like Lucifer, Carnival Row, and Warrior. They are Trinidadian natives, who currently live and create new worlds in Japan.
Website / Goodreads / Instagram / Amazon
Circumvent #Blitz
Clean Read Mystery
Publisher: TouchPoint Press
Only $.99 July 1st - 14th!!!
When perfection turns to panic an isolated couple must learn to walk by faith.
Imagine living in a quaint, beach-front cottage on the Hawaiian island of Maui. You have an amazing job, combined with the pleasure of working from home. Lunch breaks become a daily picnic on the sand. Dessert is always included because of your marriage to a famous pastry chef. Life could not be any better. Or so it seems…
French-born, Nikki Sabine Moueix travels to Hawaii for a special work assignment, but the job of writing an article about a famous Swiss pastry chef generates more than a magazine piece. They fall in love, get married, and Nikki Moueix becomes Mrs. Ruggiero Delémont.
When another assignment calls for Nikki to spend three weeks in France, Ruggiero's schedule prevents him from joining her. She travels alone, advancing straight into danger. After a threatening confrontation, Nikki wakes up in a French hospital with no knowledge of her past. After she fails to check in, Ruggiero panics and pushes for an immediate investigation. But as he closes in, Nikki's new found friend moves her to another city. It becomes a game of hide and seek with Nikki as the prize.
CIRCUMVENT allows readers to form a bond with Nikki as they yearn for her to remember. They will cheer for Ruggiero and his relentless determination to locate his beloved wife. This is a story about two people who never lose their faith in God, and find amazing friends to help them along the way.
S.K. Derban resides with her husband in Southern California. Although born in the United States she moved to London within the first three months, and remained in England until the age of five. Her father, an American citizen, was a decorated veteran of the Second World War. Her British mother was involved with the London Royal Ballet Company, and a great fan of the arts. After returning to the United States, Derban's life remained filled with a love of the theatre, and a passion for British murder mysteries.
S.K. Derban's personal travel and missionary escapades are readily apparent as they shine through into her characters. Readers are often transported virtually across the globe. She has traveled to Hong Kong on five separate occasions to smuggle Bibles into China, and has been to Israel on seven missionary trips. Derban's other adventures include visits to Bangkok, Greece, Egypt, Italy, and the Caribbean.
Beginning with her faith in the Lord, S.K. Derban relies on all aspects of her life when writing. She hopes her books will allow readers to go on holiday without having to pack!
The Last Stop #Blitz
Publisher: Acorn Publishing
Date Published: June 29
The true story of a son's battle with addiction and a mother's struggle with loss.
David is only fifteen years old when he first feels morphine flow through his veins after his foot is crushed in the hydraulics of a Bobcat. From that moment on he chases the feeling for the rest of his life. Alcohol, marijuana, cocaine – he goes through drugs like candy, but it isn't until he finds heroin that he is satisfied.
Through his personal correspondence and essays, David's story unfolds as he goes from being an average American kid who loves sports, racing around on his skateboard, and writing stories, to being a heroin addict. His heartbreaking journey deepens as he takes his family with him down the dark and dangerous road of heroin addiction.
In 2014, David loses the battle, leaving his mother, Pat, to cope. Grieving a death from addiction is two-fold. After already losing her son to addiction, Pat has to find a way to grieve his death.
The Last Stop reveals intimate and detailed scenes of living the life of an addict and explores the mistakes and ways for families who love the addict to cope. David's story gives hope for families immersed in the life-altering aspects of active addiction and empathy for those left behind when recovery stops being a choice.
In 2002, Pat graduated from George Mason University with a bachelor's degree in International Legal Studies. When her graduate writing project won her college's highest award, she realized how much she liked to write.
In late 1999, Pat learned that her son, David, who was 25, had become addicted to heroin. Her life was changed forever. For the next fifteen years, David rotated in and out of active addiction, recovery, and relapse. In August of 2013, David was diagnosed with vertebrae osteomyelitis caused by his drug use, and at the age of 39, he lost his battle with addiction.
Wanting to help other moms who are living the nightmare of addiction with a loved one, Pat gathered the emotional courage to compile her son's story, The Last Stop, with his short stories, poetry, and essays.
Addiction changes the addict and those who love the addict. Pat is a different person today, but she still enjoys a good book, a lively tennis match, the clicking of Mah Jongg tiles, weaving baby blankets, and long walks with her little terrier mix who rescued her two years ago.
How To Rope A Loyal Cowboy by Anya Summers #Cover Reveal
How To Rope A Loyal Cowboy
Anya Summers
(Silver Springs Ranch, #4)
Publication date: July 27th 2021
Widowed single dad Noah needs help in the worst way. He's desperate to find a new live-in nanny to care for his four-year-old twins while he's at work in the stables. Ever since his wife died, he has lived like a monk. What with raising two boys solo and working as the horse master for Silver Springs Ranch, there hasn't been time in his life for things like finding a willing bed partner to slake his dark needs.
When the achingly beautiful Morgan appears on his doorstep inquiring about the job, he doesn't think twice about hiring her. He snaps her up before she discovers his boys are little hellions who have driven the last few nannies away over their antics.
And yet, for the first time in three years, since he buried his heart in the ground, Noah is entranced by naughty visions of the new nanny. She's young, full of enthusiasm, and stirs up every wicked fantasy in his arsenal.
He prays he has the fortitude to resist her delectable charms because she's forbidden. At his age, he can't sleep with, let alone crave, a woman fresh out of college. But she keeps casting sexy glances suffused with desire in his direction, battering his resolve to stay away. She's headstrong, and he aches to exert his dominance.
Will he wave the white flag, and surrender to her naughty whispered pleas?
Born in St. Louis, Missouri, Anya grew up listening to Cardinals baseball and reading anything she could get her hands on. She remembers her mother saying if only she would read the right type of books instead binging her way through the romance aisles at the bookstore, she'd have been a doctor. While Anya never did get that doctorate, she graduated cum laude from the University of Missouri-St. Louis with an M.A. in History.
Anya is a bestselling and award-winning author published in multiple fiction genres. She also writes urban fantasy, paranormal romance, and contemporary romance under the name Maggie Mae Gallagher. A total geek at her core, when she is not writing, she adores attending the latest comic con or spending time with her family. She currently lives in the Midwest with her two furry felines.
Website / Goodreads / Facebook / Twitter / Instagram / Amazon / Bookbub / Newsletter
Flawless by Ivy Nelson #Cover Reveal
Ivy Nelson
(A Diamond Doms Novel, #8)
Matthew Bruce has a lot of secrets. He's legally married to royalty, he's in love with his wife's little sister, and he's not really dead like everyone thinks. To top it all off, it turns out his recently deceased grandfather was part of the international underground organization his friends at Club Solitaire have been tracking down.
Faking his death hadn't been part of the plan, and having Kendall Livingston, his wife's sister, track him down most definitely wasn't in the plans.
Now he has to keep them both safe and keep Kendall out of his bed.
Ivy Nelson is an emerging contemporary romance author, hopeful romantic, and passionate advocate who is versed in all things steamy, sultry, and sensual. It all started back when she read her first steamy romance novel at the age of fourteen. From that point forward, it became her favorite genre--one she wanted to write in herself someday. Sylvia Day's writing style cemented that passion, and gave her just the inspiration she needed to be an author herself. In December of 2018, Ivy published her debut novel, Power Desired at the age of 32.
Most recently, Ivy completed the "D.C. Power Games" series and the prequel to her forthcoming "Diamond Doms series" titled "Hard" (currently available for pre-order). In a not-so-distant past, she was a student affairs professional at a university and earned her political science degree, which explains her politically-driven romance debut.
When she isn't penning steamy scenes or attending writing conferences, you can find this contest-winning karaoke singer and bookworm passionately supporting human rights or growing her Sims 4 empire. She is also a wine aficionado and certified whiskey taster (no really, she has the certificate to prove it). All that aside, Ivy loves spending quality time with her amazing son and husband of three years at their home in Houston, TX.
Girl Who Was Forgotten Tour and Giveaway!
The Girl Who Was Forgotten
The Shee McQueen Series Book 2
by Amy Vasant
Genre: Mystery, Thriller
"If thrills, twists, turns, suspense, fast-paced books, and humor are your cup of tea, this series is for you!"
Action-adventure from USA Today and Wall Street Journal bestselling author Amy Vansant - a novel packed with thrills, fun, romance and heartfelt family intrigue.
Life was supposed to start feeling like a permanent vacation.
After years on the run from a vengeful killer, Shee McQueen is home at her father's beach hotel. The Loggerhead Inn doubles as a retreat for sunburned tourists and a haven for recovering ex-military --- men and women who help right wrongs for people in need of their particular skills.
What could be more relaxing?
Unless...
...Shee's estranged boyfriend --- the only man she's ever loved --- has discovered her darkest secret and the reason she left him so many years ago...
...or her first job for her father has ended in a double homicide...
...or that her very presence is driving the hotel's regulars to prove their worth by starting dangerous covert missions of their own...
Wait. It couldn't be a botched kidnapping is started looking more like the work of a deranged serial killer?
Maybe hold the tanning lotion.
This might take a minute.
The Girl Who Was Forgotten is the second explosive mystery-thriller in the Shee McQueen series, but can be read as a standalone. While the book has all the pulse-pounding action of a thriller, language, romance and violence is rated PG.
The unique female lead's funny, irreverent and all-too-human asides will have you rooting for her — and her whole pack of wild, wonderful misfit friends — until the breathless end.
Fans of Harlan Coban, Carl Hiaasen, Tim Dorsey, Sue Grafton, Kathy Reichs and Janet Evanovich will love this exhilarating page-turner.
Readers love Amy Vansant & Shee McQueen:
"Great book. I could not put it down until finished with THE END. Highly recommended!" - Amazon Reader ⭐⭐⭐⭐⭐
"I find it hard to express how much this book affected me, not only the story line, but the mastery of the writing itself." - Amazon Reader ⭐⭐⭐⭐⭐
"Well written and a certain must-read for any thriller/suspense lover. I can hardly wait for the next book. Amy Vansant nailed it!" - Amazon Reader ⭐⭐⭐⭐⭐
"This book was absolutely spellbinding. As a fan of Vansant, I pre-order and read everything she writes." - Goodreads Reader ⭐⭐⭐⭐⭐
**On Sale Now! Only $2.99 for June!!**
The Girl Who Wants
NEW SERIES! A wildly entertaining, wholly unique tour de force of action, psychological drama and wit from USA Today and Wall Street Journal bestselling author Amy Vansant.
Shee wants a home.
Shee McQueen grew up skip tracing and hunting military criminals with her father, Mick, until someone put a bounty on her head, forcing her underground. Resurfacing years later, she returns to her family's hotel in Jupiter Beach, FL, to find Mick in a coma, shot in the head by an unknown sniper.
Shee wants answers.
The Loggerhead Inn has everything Shee could want in a beach hotel---sea turtle wall art, a tiny Yorkshire terrier mascot who thinks she's a pit bull, and her father's staff of deadly, damaged military veterans, looking to redeem their troubled souls by helping others. Not to mention--- Hold on...
How did Mason Connelly, the SEAL she fell for decades ago, just appear in the lobby? Why did he have to show up now demanding answers to secrets long buried?
Shee wants it all back.
But someone wants her dead.
From the moment Shee McQueen appears, The Girl Who Wants straps the reader into a twisting roller coaster ride of heart-stopping action, snappy dialog and intrigue. Shee's quest to recover the life and loves she's lost brings a depth of emotion rare in such a page-turning suspense. The unique female lead's funny, irreverent and all-too-human asides will have you rooting for her — and her whole pack of wild, wonderful misfit friends — until the breathless end.
Fans of Liane Moriarty, Carl Hiaasen, Donald E. Westlake, Janet Evanovich and John Grisham (without so many lawyers!) will love this exhilarating page-turner.
**Get it FREE June 4, 5, 8, 9, 15, 22 & 30!!!**
USA Today and Wall Street Journal bestselling author Amy Vansant has written over 20 books, including the fun, thrilling Shee McQueen series, the rollicking, twisty Pineapple Port Mysteries, and the action-packed Kilty urban fantasies. Throw in a couple romances and a YA fantasy for her nieces... Amy specializes in fun, exciting reads with plenty of laughs and action -- she tried to write serious books, but they always ended up full of jokes, so she gave up.
Amy lives in Jupiter, Florida with her muse/husband a goony Bordoodle named Archer.
Website * Facebook * Twitter * Instagram * Bookbub * Amazon * Goodreads
Win a Kindle Reader!
https://www.amazon.com/dp/B07978J597
How To Rope A Loyal Cowboy by Anya Summers #Cover ...
Hate Notes by Gracie Graham #Blitz
Vodka and Pop Rocks #CoverReveal for #HeatherLaure...
American Valor #Blitz
Dandelion Dreams Tour and Giveaway!
Sinful Secrets by L G Campbell is #NowLive
Pretty Savage by T.A. Kunz #Cover Reveal
Tears of Change #Blitz
★.•°`☆ NEW RELEASE ☆`°•.★➜ #NewRelease for
Dance with Me #Blitz
Harry Harambee's Kenyan Sundowner #Blitz
Debt Bomb Teaser Tuesday
Salt Kisses Series by Josie Demuth #Blitz
Born in Salt TOUR
The Paranormals complete collection, books 1-4 is ...
Wrapped Up in You: A Second Chance Romance Antholo...
Applecross Saga Tour and Giveaway!
The Trophy Room #Blitz
The Girls of Cemetery Road #Blitz
Bluebonnets in the Spring Tour and Giveaway!
Do You Know Dorothy? Blitz
Red Card #Blitz
THE INTROVERT'S GUIDE TO SPEED DATING BY EMMA HART...
Perfect Play by Cookie O'Gorman #Cover Reveal
Utopia Falls Tour and Giveaway!
Poisoned Jungle #Blitz
Maya Loop #Blitz
Confessions of a Sophomore Prankster by Danielle J...
Destroying Angel Tour and Giveaway!
Earth Shattering #Blitz
Pickoff #Blitz
𝐓𝐇𝐄 𝐕𝐄𝐍𝐆𝐄𝐀𝐍𝐂𝐄 𝐘𝐎𝐔 𝐂𝐑𝐀𝐕𝐄 𝐈𝐒 ...
Taken Tour and Giveaway!
Holding Week #Blitz
Margaritas at the Beach House Hotel #Blitz
Other People's Butterflies #Blitz
Third Time's the Harm REVEAL
Keeper of Souls by Harper Ray #Blitz
The Shadow Queen by K. Rea #Cover Reveal
Coffee and Crushes at the Cat Café #Blitz
Unscheduled Murder Trip #Blitz
The Buzz Boys #Blitz
American Bourbon Tour and Giveaway!
Hottest Summer Ever Tour and Giveaway!
Summer Camp March #Blitz
Mimic by C.L. Denault #blitz
Cruel Summer Tour and Giveaway!
The Hellion is Tamed #Blitz
A Sea for Summer #Blitz
Paranormals complete collection #Cover Reveal
Heirs of the Aristocracy Tour and Giveaway!
Blood Moon #Blitz
Accident Among Vampires #Blitz
Game Over Tour and Giveaway!
The House on Camp Ruby Road #Blitz
The Darkness #Blitz
MY CONE AND ONLY #CoverReveal
My Mum and Me book tour
As Long as it Takes #Blitz
The Awakening of Rae #Blitz
CHEATERS: A Dark Romance Anthology ♡ COVER REVEAL ...
On DestinyAileen Erin(Aunare Chr...
Alone With You (Book #1 in the Broken Trust series...
Encounter Tour and Giveaway!
I Hear the Black Raven #Blitz
In the Eye of the Beholder #Blitz
The Dark Lord #Blitz
Blood Orphan (Book #1 in the Tom Grant series) by ...
Persephone Plus Tour and Giveaway!
Clothilde Tour and Giveaway!
The Forget-Me Knot #Blitz
Wraith by Mere Joyce blitz with Xpresso Book Tours
The Message on the 13th Floor #Blitz
Sunshine Escape (Book #1 in the Tenerife Duet) by ...
Allmother Rising Tour and Giveaway!
Alaska Inferno #Blitz
Monet & Oscar #Blitz
Confessions of a Sophomore Prankster #Coming Soon
#currently Reading
Training Tracey Tour and Giveaway!
Into Africa Tour and Giveaway!
Sailing to Byzantium #Blitz
Zinger In The Woods #Blog Tour
Everything To Lose Tour and Giveaway!
Mushroom Honeymoon #Blitz
Fairview Chronicles Tour and Giveaway!
Darkness Within #Blitz
Death Opens a Window TOUR


A while back wrote a post on how I made a display for some of my special jewelry. It's one of my absolute favorite projects! Everyday I get to see heirlooms and special jewelry from my wedding day. It was super cheap and easy too and you know that's right up my alley!
I updated the pictures a bit and I figured, why not revisit that post today? I'll give you the super simple step-by-step process so you can display your special jewelry too. If you don't have any, you may want to go out and by some! Ebay and Etsy are great for it!