text:
"""The media player tests for the forked_daapd media player platform."""

from unittest.mock import patch

import pytest

from homeassistant.components.forked_daapd.browse_media import create_media_content_id
from homeassistant.components.forked_daapd.const import (
    CONF_LIBRESPOT_JAVA_PORT,
    CONF_MAX_PLAYLISTS,
    CONF_TTS_PAUSE_TIME,
    CONF_TTS_VOLUME,
    SIGNAL_UPDATE_OUTPUTS,
    SIGNAL_UPDATE_PLAYER,
    SIGNAL_UPDATE_QUEUE,
    SOURCE_NAME_CLEAR,
    SOURCE_NAME_DEFAULT,
    SUPPORTED_FEATURES,
    SUPPORTED_FEATURES_ZONE,
)
from homeassistant.components.media_player import (
    ATTR_INPUT_SOURCE,
    ATTR_MEDIA_ALBUM_ARTIST,
    ATTR_MEDIA_ALBUM_NAME,
    ATTR_MEDIA_ANNOUNCE,
    ATTR_MEDIA_ARTIST,
    ATTR_MEDIA_CONTENT_ID,
    ATTR_MEDIA_CONTENT_TYPE,
    ATTR_MEDIA_DURATION,
    ATTR_MEDIA_ENQUEUE,
    ATTR_MEDIA_POSITION,
    ATTR_MEDIA_SEEK_POSITION,
    ATTR_MEDIA_SHUFFLE,
    ATTR_MEDIA_TITLE,
    ATTR_MEDIA_TRACK,
    ATTR_MEDIA_VOLUME_LEVEL,
    ATTR_MEDIA_VOLUME_MUTED,
    DOMAIN as MP_DOMAIN,
    SERVICE_CLEAR_PLAYLIST,
    SERVICE_MEDIA_NEXT_TRACK,
    SERVICE_MEDIA_PAUSE,
    SERVICE_MEDIA_PLAY,
    SERVICE_MEDIA_PREVIOUS_TRACK,
    SERVICE_MEDIA_SEEK,
    SERVICE_MEDIA_STOP,
    SERVICE_PLAY_MEDIA,
    SERVICE_SELECT_SOURCE,
    SERVICE_SHUFFLE_SET,
    SERVICE_TOGGLE,
    SERVICE_TURN_OFF,
    SERVICE_TURN_ON,
    SERVICE_VOLUME_MUTE,
    SERVICE_VOLUME_SET,
    MediaPlayerEnqueue,
    MediaType,
)
from homeassistant.components.media_source import PlayMedia
from homeassistant.const import (
    ATTR_ENTITY_ID,
    ATTR_FRIENDLY_NAME,
    ATTR_SUPPORTED_FEATURES,
    STATE_ON,
    STATE_PAUSED,
    STATE_UNAVAILABLE,
)

from tests.common import async_mock_signal

TEST_MASTER_ENTITY_NAME = "media_player.owntone_server"
TEST_ZONE_ENTITY_NAMES = [
    "media_player.owntone_output_" + x for x in ("kitchen", "computer", "daapd_fifo")
]

OPTIONS_DATA = {
    CONF_LIBRESPOT_JAVA_PORT: "123",
    CONF_MAX_PLAYLISTS: 8,
    CONF_TTS_PAUSE_TIME: 0,
    CONF_TTS_VOLUME: 0.25,
}

SAMPLE_PLAYER_PAUSED = {
    "state": "pause",
    "repeat": "off",
    "consume": False,
    "shuffle": False,
    "volume": 20,
    "item_id": 12322,
    "item_length_ms": 50,
    "item_progress_ms": 5,
}

SAMPLE_PLAYER_PLAYING = {
    "state": "play",
    "repeat": "off",
    "consume": False,
    "shuffle": False,
    "volume": 50,
    "item_id": 12322,
    "item_length_ms": 50,
    "item_progress_ms": 5,
}

SAMPLE_PLAYER_STOPPED = {
    "state": "stop",
    "repeat": "off",
    "consume": False,
    "shuffle": False,
    "volume": 0,
    "item_id": 12322,
    "item_length_ms": 50,
    "item_progress_ms": 5,
}

SAMPLE_QUEUE = {
    "version": 833,
    "count": 1,
    "items": [
        {
            "id": 12322,
            "position": 0,
            "track_id": 1234,
            "title": "Some song",
            "artist": "Some artist",
            "album": "No album",
            "album_artist": "The xx",
            "artwork_url": "http://art",
            "length_ms": 0,
            "track_number": 1,
            "media_kind": "music",
            "data_kind": "url",
            "uri": "library:track:5",
        }
    ],
}

SAMPLE_QUEUE_TTS = {
    "version": 833,
    "count": 1,
    "items": [
        {
            "id": 12322,
            "position": 0,
            "track_id": 1234,
            "title": "Short TTS file",
            "artist": "Google",
            "album": "No album",
            "album_artist": "The xx",
            "artwork_url": "http://art",
            "length_ms": 0,
            "track_number": 1,
            "media_kind": "music",
            "data_kind": "url",
            "uri": "tts_proxy_somefile.mp3",
        }
    ],
}

SAMPLE_QUEUE_PIPE = {
    "version": 833,
    "count": 1,
    "items": [
        {
            "id": 12322,
            "title": "librespot-java",
            "artist": "some artist",
            "album": "some album",
            "album_artist": "The xx",
            "length_ms": 0,
            "track_number": 1,
            "media_kind": "music",
            "data_kind": "pipe",
            "uri": "pipeuri",
        }
    ],
}

SAMPLE_CONFIG = {
    "websocket_port": 3688,
    "version": "25.0",
    "buildoptions": [
        "ffmpeg",
        "iTunes XML",
        "Spotify",
        "LastFM",
        "MPD",
        "Device verification",
        "Websockets",
        "ALSA",
    ],
}

SAMPLE_CONFIG_NO_WEBSOCKET = {
    "websocket_port": 0,
    "version": "25.0",
    "buildoptions": [
        "ffmpeg",
        "iTunes XML",
        "Spotify",
        "LastFM",
        "MPD",
        "Device verification",
        "Websockets",
        "ALSA",
    ],
}

SAMPLE_OUTPUTS_ON = (
    {
        "id": "123456789012345",
        "name": "kitchen",
        "type": "AirPlay",
        "selected": True,
        "has_password": False,
        "requires_auth": False,
        "needs_auth_key": False,
        "volume": 50,
    },
    {
        "id": "0",
        "name": "Computer",
        "type": "ALSA",
        "selected": True,
        "has_password": False,
        "requires_auth": False,
        "needs_auth_key": False,
        "volume": 19,
    },
    {
        "id": "100",
        "name": "daapd-fifo",
        "type": "fifo",
        "selected": False,
        "has_password": False,
        "requires_auth": False,
        "needs_auth_key": False,
        "volume": 0,
    },
)

SAMPLE_OUTPUTS_UNSELECTED = [
    {
        "id": "123456789012345",
        "name": "kitchen",
        "type": "AirPlay",
        "selected": False,
        "has_password": False,
        "requires_auth": False,
        "needs_auth_key": False,
        "volume": 0,
    },
    {
        "id": "0",
        "name": "Computer",
        "type": "ALSA",
        "selected": False,
        "has_password": False,
        "requires_auth": False,
        "needs_auth_key": False,
        "volume": 19,
    },
    {
        "id": "100",
        "name": "daapd-fifo",
        "type": "fifo",
        "selected": False,
        "has_password": False,
        "requires_auth": False,
        "needs_auth_key": False,
        "volume": 0,
    },
]

SAMPLE_PIPES = [
    {
        "id": 1,
        "title": "librespot-java",
        "media_kind": "music",
        "data_kind": "pipe",
        "path": "/music/srv/input.pipe",
        "uri": "library:track:1",
    }
]

SAMPLE_PLAYLISTS = [{"id": 7, "name": "test_playlist", "uri": "library:playlist:2"}]

@pytest.fixture(name="get_request_return_values")
async def get_request_return_values_fixture():
    """Get request return values we can change later."""
    return {
        "config": SAMPLE_CONFIG,
        "outputs": SAMPLE_OUTPUTS_ON,
        "player": SAMPLE_PLAYER_PAUSED,
        "queue": SAMPLE_QUEUE,
    }

@pytest.fixture(name="mock_api_object")
async def mock_api_object_fixture(hass, config_entry, get_request_return_values):
    """Create mock api fixture."""

    async def get_request_side_effect(update_type):
        if update_type == "outputs":
            return {"outputs": get_request_return_values["outputs"]}
        return get_request_return_values[update_type]

    with patch(
        "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI",
        autospec=True,
    ) as mock_api:
        mock_api.return_value.get_request.side_effect = get_request_side_effect
        mock_api.return_value.full_url.return_value = ""
        mock_api.return_value.get_pipes.return_value = SAMPLE_PIPES
        mock_api.return_value.get_playlists.return_value = SAMPLE_PLAYLISTS
        config_entry.add_to_hass(hass)
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

    mock_api.return_value.start_websocket_handler.assert_called_once()
    mock_api.return_value.get_request.assert_called_once()
    updater_update = mock_api.return_value.start_websocket_handler.call_args[0][2]
    await updater_update(["player", "outputs", "queue"])
    await hass.async_block_till_done()

    async def add_to_queue_side_effect(
        uris, playback=None, position=None, playback_from_position=None, clear=None
    ):
        await updater_update(["queue", "player"])

    # for play_media testing
    mock_api.return_value.add_to_queue.side_effect = add_to_queue_side_effect

    async def pause_side_effect():
        await updater_update(["player"])

    mock_api.return_value.pause_playback.side_effect = pause_side_effect

    return mock_api.return_value

async def test_unload_config_entry(hass, config_entry, mock_api_object):
    """Test the player is set unavailable when the config entry is unloaded."""
    assert hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert hass.states.get(TEST_ZONE_ENTITY_NAMES[0])
    await config_entry.async_unload(hass)
    assert hass.states.get(TEST_MASTER_ENTITY_NAME).state == STATE_UNAVAILABLE
    assert hass.states.get(TEST_ZONE_ENTITY_NAMES[0]).state == STATE_UNAVAILABLE

def test_master_state(hass, mock_api_object):
    """Test master state attributes."""
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == STATE_PAUSED
    assert state.attributes[ATTR_FRIENDLY_NAME] == "Owntone server"
    assert state.attributes[ATTR_SUPPORTED_FEATURES] == SUPPORTED_FEATURES
    assert not state.attributes[ATTR_MEDIA_VOLUME_MUTED]
    assert state.attributes[ATTR_MEDIA_VOLUME_LEVEL] == 0.2
    assert state.attributes[ATTR_MEDIA_CONTENT_ID] == 12322
    assert state.attributes[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC
    assert state.attributes[ATTR_MEDIA_DURATION] == 0.05
    assert state.attributes[ATTR_MEDIA_POSITION] == 0.005
    assert state.attributes[ATTR_MEDIA_TITLE] == "No album"  # reversed for url
    assert state.attributes[ATTR_MEDIA_ARTIST] == "Some artist"
    assert state.attributes[ATTR_MEDIA_ALBUM_NAME] == "Some song"  # reversed
    assert state.attributes[ATTR_MEDIA_ALBUM_ARTIST] == "The xx"
    assert state.attributes[ATTR_MEDIA_TRACK] == 1
    assert not state.attributes[ATTR_MEDIA_SHUFFLE]

async def test_no_update_when_get_request_returns_none(
    hass, config_entry, mock_api_object
):
    """Test when get request returns None."""

    async def get_request_side_effect(update_type):
        return None

    mock_api_object.get_request.side_effect = get_request_side_effect
    updater_update = mock_api_object.start_websocket_handler.call_args[0][2]
    signal_output_call = async_mock_signal(
        hass, SIGNAL_UPDATE_OUTPUTS.format(config_entry.entry_id)
    )
    signal_player_call = async_mock_signal(
        hass, SIGNAL_UPDATE_PLAYER.format(config_entry.entry_id)
    )
    signal_queue_call = async_mock_signal(
        hass, SIGNAL_UPDATE_QUEUE.format(config_entry.entry_id)
    )
    await updater_update(["outputs", "player", "queue"])
    await hass.async_block_till_done()
    assert len(signal_output_call) == 0
    assert len(signal_player_call) == 0
    assert len(signal_queue_call) == 0

async def _service_call(
    hass, entity_name, service, additional_service_data=None, blocking=True
):
    if additional_service_data is None:
        additional_service_data = {}
    return await hass.services.async_call(
        MP_DOMAIN,
        service,
        service_data={ATTR_ENTITY_ID: entity_name, **additional_service_data},
        blocking=blocking,
    )

async def test_zone(hass, mock_api_object):
    """Test zone attributes and methods."""
    zone_entity_name = TEST_ZONE_ENTITY_NAMES[0]
    state = hass.states.get(zone_entity_name)
    assert state.attributes[ATTR_FRIENDLY_NAME] == "Owntone output (kitchen)"
    assert state.attributes[ATTR_SUPPORTED_FEATURES] == SUPPORTED_FEATURES_ZONE
    assert state.state == STATE_ON
    assert state.attributes[ATTR_MEDIA_VOLUME_LEVEL] == 0.5
    assert not state.attributes[ATTR_MEDIA_VOLUME_MUTED]
    await _service_call(hass, zone_entity_name, SERVICE_TURN_ON)
    await _service_call(hass, zone_entity_name, SERVICE_TURN_OFF)
    await _service_call(hass, zone_entity_name, SERVICE_TOGGLE)
    await _service_call(
        hass, zone_entity_name, SERVICE_VOLUME_SET, {ATTR_MEDIA_VOLUME_LEVEL: 0.3}
    )
    await _service_call(
        hass, zone_entity_name, SERVICE_VOLUME_MUTE, {ATTR_MEDIA_VOLUME_MUTED: True}
    )
    await _service_call(
        hass, zone_entity_name, SERVICE_VOLUME_MUTE, {ATTR_MEDIA_VOLUME_MUTED: False}
    )
    zone_entity_name = TEST_ZONE_ENTITY_NAMES[2]
    await _service_call(hass, zone_entity_name, SERVICE_TOGGLE)
    await _service_call(
        hass, zone_entity_name, SERVICE_VOLUME_MUTE, {ATTR_MEDIA_VOLUME_MUTED: True}
    )
    output_id = SAMPLE_OUTPUTS_ON[0]["id"]
    initial_volume = SAMPLE_OUTPUTS_ON[0]["volume"]
    mock_api_object.change_output.assert_any_call(output_id, selected=True)
    mock_api_object.change_output.assert_any_call(output_id, selected=False)
    mock_api_object.set_volume.assert_any_call(output_id=output_id, volume=30)
    mock_api_object.set_volume.assert_any_call(output_id=output_id, volume=0)
    mock_api_object.set_volume.assert_any_call(
        output_id=output_id, volume=initial_volume
    )
    output_id = SAMPLE_OUTPUTS_ON[2]["id"]
    mock_api_object.change_output.assert_any_call(output_id, selected=True)

async def test_last_outputs_master(hass, mock_api_object):
    """Test restoration of _last_outputs."""
    # Test turning on sends API call
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_TURN_ON)
    assert mock_api_object.change_output.call_count == 0
    assert mock_api_object.set_enabled_outputs.call_count == 1
    await _service_call(
        hass, TEST_MASTER_ENTITY_NAME, SERVICE_TURN_OFF
    )  # should have stored last outputs
    assert mock_api_object.change_output.call_count == 0
    assert mock_api_object.set_enabled_outputs.call_count == 2
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_TURN_ON)
    assert mock_api_object.change_output.call_count == 3
    assert mock_api_object.set_enabled_outputs.call_count == 2

async def test_bunch_of_stuff_master(hass, get_request_return_values, mock_api_object):
    """Run bunch of stuff."""
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_TURN_ON)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_TURN_OFF)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_TOGGLE)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_VOLUME_MUTE,
        {ATTR_MEDIA_VOLUME_MUTED: True},
    )
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_VOLUME_MUTE,
        {ATTR_MEDIA_VOLUME_MUTED: False},
    )
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_VOLUME_SET,
        {ATTR_MEDIA_VOLUME_LEVEL: 0.5},
    )
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_PAUSE)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_PLAY)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_STOP)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_PREVIOUS_TRACK)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_NEXT_TRACK)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_MEDIA_SEEK,
        {ATTR_MEDIA_SEEK_POSITION: 35},
    )
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_CLEAR_PLAYLIST)
    await _service_call(
        hass, TEST_MASTER_ENTITY_NAME, SERVICE_SHUFFLE_SET, {ATTR_MEDIA_SHUFFLE: False}
    )
    # stop player and run more stuff
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.attributes[ATTR_MEDIA_VOLUME_LEVEL] == 0.2
    get_request_return_values["player"] = SAMPLE_PLAYER_STOPPED
    updater_update = mock_api_object.start_websocket_handler.call_args[0][2]
    await updater_update(["player"])
    await hass.async_block_till_done()
    # mute from volume==0
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.attributes[ATTR_MEDIA_VOLUME_LEVEL] == 0
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_VOLUME_MUTE,
        {ATTR_MEDIA_VOLUME_MUTED: True},
    )
    # now turn off (stopped and all outputs unselected)
    get_request_return_values["outputs"] = SAMPLE_OUTPUTS_UNSELECTED
    await updater_update(["outputs"])
    await hass.async_block_till_done()
    # toggle from off
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_TOGGLE)
    for output in SAMPLE_OUTPUTS_ON:
        mock_api_object.change_output.assert_any_call(
            output["id"],
            selected=output["selected"],
            volume=output["volume"],
        )
    mock_api_object.set_volume.assert_any_call(volume=0)
    mock_api_object.set_volume.assert_any_call(volume=SAMPLE_PLAYER_PAUSED["volume"])
    mock_api_object.set_volume.assert_any_call(volume=50)
    mock_api_object.set_enabled_outputs.assert_any_call(
        [output["id"] for output in SAMPLE_OUTPUTS_ON]
    )
    mock_api_object.set_enabled_outputs.assert_any_call([])
    mock_api_object.start_playback.assert_called_once()
    assert mock_api_object.pause_playback.call_count == 3
    mock_api_object.stop_playback.assert_called_once()
    mock_api_object.previous_track.assert_called_once()
    mock_api_object.next_track.assert_called_once()
    mock_api_object.seek.assert_called_once()
    mock_api_object.shuffle.assert_called_once()
    mock_api_object.clear_queue.assert_called_once()

async def test_async_play_media_from_paused(hass, mock_api_object):
    """Test async play media from paused."""
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/somefile.mp3",
        },
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == initial_state.state
    assert state.last_updated > initial_state.last_updated

async def test_async_play_media_announcement_from_stopped(
    hass, get_request_return_values, mock_api_object
):
    """Test async play media announcement (from stopped)."""
    updater_update = mock_api_object.start_websocket_handler.call_args[0][2]

    get_request_return_values["player"] = SAMPLE_PLAYER_STOPPED
    await updater_update(["player"])
    await hass.async_block_till_done()
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)

    get_request_return_values["queue"] = SAMPLE_QUEUE_TTS
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/somefile.mp3",
            ATTR_MEDIA_ANNOUNCE: True,
        },
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == initial_state.state
    assert state.last_updated > initial_state.last_updated

async def test_async_play_media_unsupported(hass, mock_api_object):
    """Test async play media on unsupported media type."""
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.TVSHOW,
            ATTR_MEDIA_CONTENT_ID: "wontwork.mp4",
        },
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.last_updated == initial_state.last_updated

async def test_async_play_media_announcement_tts_timeout(hass, mock_api_object):
    """Test async play media announcement with TTS timeout."""
    mock_api_object.add_to_queue.side_effect = None
    with patch("homeassistant.components.forked_daapd.media_player.TTS_TIMEOUT", 0):
        initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
        await _service_call(
            hass,
            TEST_MASTER_ENTITY_NAME,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
                ATTR_MEDIA_CONTENT_ID: "http://example.com/somefile.mp3",
                ATTR_MEDIA_ANNOUNCE: True,
            },
        )
        state = hass.states.get(TEST_MASTER_ENTITY_NAME)
        assert state.state == initial_state.state
        assert state.last_updated > initial_state.last_updated

async def test_use_pipe_control_with_no_api(hass, mock_api_object):
    """Test using pipe control with no api set."""
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_SELECT_SOURCE,
        {ATTR_INPUT_SOURCE: "librespot-java (pipe)"},
    )
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_PLAY)
    assert mock_api_object.start_playback.call_count == 0

async def test_clear_source(hass, mock_api_object):
    """Test changing source to clear."""
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_SELECT_SOURCE,
        {ATTR_INPUT_SOURCE: SOURCE_NAME_CLEAR},
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.attributes[ATTR_INPUT_SOURCE] == SOURCE_NAME_DEFAULT

@pytest.fixture(name="pipe_control_api_object")
async def pipe_control_api_object_fixture(
    hass, config_entry, get_request_return_values, mock_api_object
):
    """Fixture for mock librespot_java api."""
    with patch(
        "homeassistant.components.forked_daapd.media_player.LibrespotJavaAPI",
        autospec=True,
    ) as pipe_control_api:
        hass.config_entries.async_update_entry(config_entry, options=OPTIONS_DATA)
        await hass.async_block_till_done()
    get_request_return_values["player"] = SAMPLE_PLAYER_PLAYING
    updater_update = mock_api_object.start_websocket_handler.call_args[0][2]
    await updater_update(["player"])
    await hass.async_block_till_done()

    async def pause_side_effect():
        await updater_update(["player"])

    pipe_control_api.return_value.player_pause.side_effect = pause_side_effect

    await updater_update(["database"])  # load in sources
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_SELECT_SOURCE,
        {ATTR_INPUT_SOURCE: "librespot-java (pipe)"},
    )

    return pipe_control_api.return_value

async def test_librespot_java_stuff(
    hass, get_request_return_values, mock_api_object, pipe_control_api_object
):
    """Test options update and librespot-java stuff."""
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.attributes[ATTR_INPUT_SOURCE] == "librespot-java (pipe)"
    # call some basic services
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_STOP)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_PREVIOUS_TRACK)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_NEXT_TRACK)
    await _service_call(hass, TEST_MASTER_ENTITY_NAME, SERVICE_MEDIA_PLAY)
    pipe_control_api_object.player_pause.assert_called_once()
    pipe_control_api_object.player_prev.assert_called_once()
    pipe_control_api_object.player_next.assert_called_once()
    pipe_control_api_object.player_resume.assert_called_once()
    # switch away
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_SELECT_SOURCE,
        {ATTR_INPUT_SOURCE: SOURCE_NAME_DEFAULT},
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.attributes[ATTR_INPUT_SOURCE] == SOURCE_NAME_DEFAULT
    # test pipe getting queued externally changes source
    get_request_return_values["queue"] = SAMPLE_QUEUE_PIPE
    updater_update = mock_api_object.start_websocket_handler.call_args[0][2]
    await updater_update(["queue"])
    await hass.async_block_till_done()
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.attributes[ATTR_INPUT_SOURCE] == "librespot-java (pipe)"
    # test title and album not reversed when data_kind not url
    assert state.attributes[ATTR_MEDIA_TITLE] == "librespot-java"
    assert state.attributes[ATTR_MEDIA_ALBUM_NAME] == "some album"

async def test_librespot_java_play_announcement(hass, pipe_control_api_object):
    """Test play announcement with librespot-java pipe."""
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/somefile.mp3",
            ATTR_MEDIA_ANNOUNCE: True,
        },
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == initial_state.state
    assert state.last_updated > initial_state.last_updated

async def test_librespot_java_play_media_pause_timeout(hass, pipe_control_api_object):
    """Test play media with librespot-java pipe."""
    # test media play with pause timeout
    pipe_control_api_object.player_pause.side_effect = None
    with patch(
        "homeassistant.components.forked_daapd.media_player.CALLBACK_TIMEOUT", 0
    ):
        initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
        await _service_call(
            hass,
            TEST_MASTER_ENTITY_NAME,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
                ATTR_MEDIA_CONTENT_ID: "http://example.com/somefile.mp3",
            },
        )
        state = hass.states.get(TEST_MASTER_ENTITY_NAME)
        assert state.state == initial_state.state
        assert state.last_updated > initial_state.last_updated

async def test_unsupported_update(hass, mock_api_object):
    """Test unsupported update type."""
    last_updated = hass.states.get(TEST_MASTER_ENTITY_NAME).last_updated
    updater_update = mock_api_object.start_websocket_handler.call_args[0][2]
    await updater_update(["config"])
    await hass.async_block_till_done()
    assert hass.states.get(TEST_MASTER_ENTITY_NAME).last_updated == last_updated

async def test_invalid_websocket_port(hass, config_entry):
    """Test invalid websocket port on async_init."""
    with patch(
        "homeassistant.components.forked_daapd.media_player.ForkedDaapdAPI",
        autospec=True,
    ) as mock_api:
        mock_api.return_value.get_request.return_value = SAMPLE_CONFIG_NO_WEBSOCKET
        config_entry.add_to_hass(hass)
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()
        assert hass.states.get(TEST_MASTER_ENTITY_NAME).state == STATE_UNAVAILABLE

async def test_websocket_disconnect(hass, mock_api_object):
    """Test websocket disconnection."""
    assert hass.states.get(TEST_MASTER_ENTITY_NAME).state != STATE_UNAVAILABLE
    assert hass.states.get(TEST_ZONE_ENTITY_NAMES[0]).state != STATE_UNAVAILABLE
    updater_disconnected = mock_api_object.start_websocket_handler.call_args[0][4]
    updater_disconnected()
    await hass.async_block_till_done()
    assert hass.states.get(TEST_MASTER_ENTITY_NAME).state == STATE_UNAVAILABLE
    assert hass.states.get(TEST_ZONE_ENTITY_NAMES[0]).state == STATE_UNAVAILABLE

async def test_async_play_media_enqueue(hass, mock_api_object):
    """Test async play media with different enqueue options."""
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/play.mp3",
            ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.PLAY,
        },
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == initial_state.state
    assert state.last_updated > initial_state.last_updated
    mock_api_object.add_to_queue.assert_called_with(
        uris="http://example.com/play.mp3",
        playback="start",
        position=0,
        playback_from_position=0,
    )
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/replace.mp3",
            ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.REPLACE,
        },
    )
    mock_api_object.add_to_queue.assert_called_with(
        uris="http://example.com/replace.mp3", playback="start", clear=True
    )
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/add.mp3",
            ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.ADD,
        },
    )
    mock_api_object.add_to_queue.assert_called_with(
        uris="http://example.com/add.mp3", playback="start", clear=False
    )
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/add.mp3",
            ATTR_MEDIA_ENQUEUE: True,
        },
    )
    mock_api_object.add_to_queue.assert_called_with(
        uris="http://example.com/add.mp3", playback="start", clear=False
    )
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: "http://example.com/next.mp3",
            ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.NEXT,
        },
    )
    mock_api_object.add_to_queue.assert_called_with(
        uris="http://example.com/next.mp3", playback="start", position=1
    )

async def test_play_owntone_media(hass, mock_api_object):
    """Test async play media with an owntone source."""
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
            ATTR_MEDIA_CONTENT_ID: create_media_content_id(
                "some song", "library:track:456"
            ),
            ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.PLAY,
        },
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == initial_state.state
    assert state.last_updated > initial_state.last_updated
    mock_api_object.add_to_queue.assert_called_with(
        uris="library:track:456",
        playback="start",
        position=0,
        playback_from_position=0,
    )

async def test_play_spotify_media(hass, mock_api_object):
    """Test async play media with a spotify source."""
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    await _service_call(
        hass,
        TEST_MASTER_ENTITY_NAME,
        SERVICE_PLAY_MEDIA,
        {
            ATTR_MEDIA_CONTENT_TYPE: "spotify://track",
            ATTR_MEDIA_CONTENT_ID: "spotify://open.spotify.com/spotify:track:abcdefghi",
            ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.PLAY,
        },
    )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == initial_state.state
    assert state.last_updated > initial_state.last_updated
    mock_api_object.add_to_queue.assert_called_with(
        uris="spotify:track:abcdefghi",
        playback="start",
        position=0,
        playback_from_position=0,
    )

async def test_play_media_source(hass, mock_api_object):
    """Test async play media with a spotify source."""
    initial_state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    with patch(
        "homeassistant.components.media_source.async_resolve_media",
        return_value=PlayMedia("http://my_hass/song.m4a", "audio/aac"),
    ):
        await _service_call(
            hass,
            TEST_MASTER_ENTITY_NAME,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_MEDIA_CONTENT_TYPE: "audio/aac",
                ATTR_MEDIA_CONTENT_ID: "media-source://media_source/test_dir/song.m4a",
                ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.PLAY,
            },
        )
    state = hass.states.get(TEST_MASTER_ENTITY_NAME)
    assert state.state == initial_state.state
    assert state.last_updated > initial_state.last_updated
    mock_api_object.add_to_queue.assert_called_with(
        uris="http://my_hass/song.m4a",
        playback="start",
        position=0,
        playback_from_position=0,
    )


text:
import cPickle
import sys
import operator
import itertools

clusters = cPickle.load(open(sys.argv[1]))
by_length = sorted(clusters.items(), key=lambda (cid, data): len(data['queries']), reverse=True)

print '>> Num clusters {}'.format(len(clusters))
print by_length[0]

redpajama_set_name: RedPajamaGithub


text:
layout: post
title: "Internet is suddenly very slow..."
---
Internet is suddenly very slow, wondering if it's a hint that I should shut down and go to bed.


text:
package fr.paris.lutece.util.password;

import fr.paris.lutece.portal.service.admin.AdminUserService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.util.date.DateUtil;

import java.security.SecureRandom;
import java.sql.Timestamp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

/**
 * Utility class used to generate random passwords
 */
public final class PasswordUtil
{
    public static final String PROPERTY_PASSWORD_SIZE = "randomPassword.size";
    public static final int CONSTANT_DEFAULT_RANDOM_PASSWORD_SIZE = 16;
    private static final int CONSTANT_NUMBER_LETTERS = 26;
    private static final int CONSTANT_NUMBER_NUMBERS_BASE10 = 10;
    private static final int CONSTANT_ASCII_CODE_A_UPPERCASE = 65;
    private static final int CONSTANT_ASCII_CODE_A_LOWERCASE = 97;
    private static final int CONSTANT_ASCII_CODE_ZERO = 48;
    private static final char [ ] CONSTANT_SPECIAL_CHARACTERS = {
            '!', ',', ':', '?', '$', '-', '@', '}', '{', '(', ')', '*', '+', '=', '[', ']', '%', '.',
    };
    private static final String CONSTANT_PASSWORD_BEGIN_REGEX = "^";
    private static final String CONSTANT_PASSWORD_REGEX_NUM = "(?=.*[0-9])";
    private static final String CONSTANT_PASSWORD_REGEX_SPECIAL = "(?=.*[^a-zA-Z0-9])";
    private static final String CONSTANT_PASSWORD_REGEX_UPPER_LOWER = "(?=.*[a-z])(?=.*[A-Z])";
    private static final String CONSTANT_PASSWORD_END_REGEX = "(.*)$";
    private static final String PARAMETER_PASSWORD_MINIMUM_LENGTH = "password_minimum_length";

    /** Private Constructor */
    private PasswordUtil( )
    {
    }

    /**
     * Generate a new random password
     *
     * @return the new password
     */
    public static String makePassword( )
    {
        // reinitialize password
        int nPasswordSize = AppPropertiesService.getPropertyInt( PROPERTY_PASSWORD_SIZE, CONSTANT_DEFAULT_RANDOM_PASSWORD_SIZE );
        int nMinPasswordSize = AdminUserService.getIntegerSecurityParameter( PARAMETER_PASSWORD_MINIMUM_LENGTH );

        if ( nMinPasswordSize > nPasswordSize )
        {
            nPasswordSize = nMinPasswordSize;
        }

        return makePassword( nPasswordSize, true, true, true );
    }

    /**
     * Generate a new random password
     *
     * @param nPasswordSize
     *            the password size
     * @param bUpperAndLowerCase
     *            true if the password must contain upper and lower case
     * @param bNumbers
     *            if the password must contain numbers
     * @param bSpecialCaracters
     *            if the password must contain special characters
     *
     * @return the new password
     */
    public static String makePassword( int nPasswordSize, boolean bUpperAndLowerCase, boolean bNumbers, boolean bSpecialCaracters )
    {
        // reinitialize password
        Random r = new SecureRandom( );

        ArrayList<Character> listCharacters = new ArrayList<>( nPasswordSize );

        // No of Big letters
        int nNumCapitalLetters = bUpperAndLowerCase ? ( r.nextInt( nPasswordSize - 3 ) + 1 ) : 0; // choose a number between 1 and CONSTANT_PASSWORD_SIZE -1

        // no on special characters
        int nNumSpecial = bSpecialCaracters ? ( r.nextInt( nPasswordSize - 2 - nNumCapitalLetters ) + 1 ) : 0; // choose a number beetwen 1 and
                                                                                // CONSTANT_PASSWORD_SIZE - a1

        // no of nos
        int nNumNumbers = bNumbers ? ( r.nextInt( nPasswordSize - 1 - nNumCapitalLetters - nNumSpecial ) + 1 ) : 0; // choose a number to complete list of
                                                                                // CONSTANT_PASSWORD_SIZE characters

        // no of small
        int nNumSmallLetters = nPasswordSize - nNumCapitalLetters - nNumSpecial - nNumNumbers; // choose a number to complete list of CONSTANT_PASSWORD_SIZE
                                                                                // characters

        for ( int j = 0; j < nNumCapitalLetters; j++ )
        {
            char c1 = (char) ( r.nextInt( CONSTANT_NUMBER_LETTERS ) + CONSTANT_ASCII_CODE_A_UPPERCASE );
            listCharacters.add( Character.valueOf( c1 ) );
        }

        for ( int j = 0; j < nNumSmallLetters; j++ )
        {
            char c1 = (char) ( r.nextInt( CONSTANT_NUMBER_LETTERS ) + CONSTANT_ASCII_CODE_A_LOWERCASE );
            listCharacters.add( Character.valueOf( c1 ) );
        }

        for ( int j = 0; j < nNumNumbers; j++ )
        {
            char c1 = (char) ( r.nextInt( CONSTANT_NUMBER_NUMBERS_BASE10 - 1 ) + CONSTANT_ASCII_CODE_ZERO );
            listCharacters.add( Character.valueOf( c1 ) );
        }

        for ( int j = 0; j < nNumSpecial; j++ )
        {
            char c1 = CONSTANT_SPECIAL_CHARACTERS [r.nextInt( CONSTANT_SPECIAL_CHARACTERS.length )];
            listCharacters.add( Character.valueOf( c1 ) );
        }

        Collections.shuffle( listCharacters, r );

        StringBuilder sbPassword = new StringBuilder( listCharacters.size( ) );

        for ( Character myChar : listCharacters )
        {
            sbPassword.append( myChar );
        }

        return sbPassword.toString( );
    }

    /**
     * Check whether a password contains upper and lower case letters, special characters and numbers.
     *
     * @param strPassword
     *            The password to check
     * @return True if the password format is correct, false otherwise
     */
    public static boolean checkPasswordFormat( String strPassword )
    {
        return checkPasswordFormat( strPassword, true, true, true );
    }

    /**
     * Check whether a password contains upper and lower case letters, special characters and numbers.
     *
     * @param strPassword
     *            The password to check
     * @param bUpperAndLowerCase
     *            true if the password must contain upper and lower case
     * @param bNumero
     *            if the password must contain numero
     * @param bSpecialCaracters
     *            if the password must contain special characters
     *
     * @return True if the password format is correct, false otherwise
     */
    public static boolean checkPasswordFormat( String strPassword, boolean bUpperAndLowerCase, boolean bNumero, boolean bSpecialCaracters )
    {
        if ( ( strPassword == null ) || strPassword.isEmpty( ) )
        {
            return false;
        }

        StringBuilder sbRegex = new StringBuilder( CONSTANT_PASSWORD_BEGIN_REGEX );

        if ( bUpperAndLowerCase )
        {
            sbRegex.append( CONSTANT_PASSWORD_REGEX_UPPER_LOWER );
        }

        if ( bNumero )
        {
            sbRegex.append( CONSTANT_PASSWORD_REGEX_NUM );
        }

        if ( bSpecialCaracters )
        {
            sbRegex.append( CONSTANT_PASSWORD_REGEX_SPECIAL );
        }

        sbRegex.append( CONSTANT_PASSWORD_END_REGEX );

        return strPassword.matches( sbRegex.toString( ) );
    }

    /**
     * Get the maximum valid date of a password starting from now with the given number of days.
     *
     * @param nNumberDay
     *            The number of days the password is valid
     * @return The maximum valid date of a password
     */
    public static Timestamp getPasswordMaxValidDate( int nNumberDay )
    {
        if ( nNumberDay <= 0 )
        {
            return null;
        }

        long nMilliSeconds = DateUtil.convertDaysInMiliseconds( nNumberDay );
        return new Timestamp( new java.util.Date( ).getTime( ) + nMilliSeconds );
    }
}


text:
package com.oct.sclaav

import java.io.File

import com.sksamuel.scrimage.nio.JpegWriter

trait TestHelpers {
  implicit val writer = JpegWriter.Default
  val bapImagesDir = new File(getClass.getResource("/below-average-photography").getPath)
  val testRootPath = getClass.getResource("/").getPath
  val mosaicBoulderFoothills = new File(getClass.getResource("/assembled/mosaic/boulder-foothills-mosaic.jpeg").getPath)
  val mosaicBoulderFoothillsLowRes = new File(getClass.getResource("/assembled/mosaic/boulder-foothills-mosaic-low-res.jpeg").getPath)
  val blackAndYellowFlag = new File(getClass.getResource("/other/black-yellow-flag.jpg").getPath)

}


text:
import test from 'tape-promise/tape';
import {ScenegraphNode} from '@luma.gl/experimental';
import {Matrix4, Vector3} from '@math.gl/core';

const PROPS = {
  display: true,
  position: new Vector3(1, 1, 1),
  rotation: new Vector3(2, 2, 2),
  scale: new Vector3(3, 3, 3),
  matrix: new Matrix4().scale(4)
};

test('ScenegraphNode#constructor', (t) => {
  const sgNode = new ScenegraphNode(PROPS);
  t.ok(sgNode instanceof ScenegraphNode, 'should construct the object');
  for (const key in PROPS) {
    t.deepEqual(sgNode.props[key], PROPS[key], `prop: ${key} should get set on the object.props`);
    t.deepEqual(sgNode[key], PROPS[key], `prop: ${key} should get set on the object`);
  }
  t.end();
});

test('ScenegraphNode#delete', (t) => {
  const sgNode = new ScenegraphNode();
  t.doesNotThrow(() => sgNode.delete(), 'delete should work');

  t.end();
});

test('ScenegraphNode#setProps', (t) => {
  const sgNode = new ScenegraphNode();
  sgNode.setProps(PROPS);
  for (const key in PROPS) {
    t.deepEqual(sgNode.props[key], PROPS[key], `prop: ${key} should get set on the object.props`);
    t.deepEqual(sgNode[key], PROPS[key], `prop: ${key} should get set on the object`);
  }
  t.end();
});

test('ScenegraphNode#toString', (t) => {
  const sgNode = new ScenegraphNode();
  t.doesNotThrow(() => sgNode.toString(), 'delete should work');

  t.end();
});

test('ScenegraphNode#setMatrix', (t) => {
  const sgNode = new ScenegraphNode();
  const matrix = new Matrix4().scale(1.5);

  sgNode.setMatrix(matrix);
  t.deepEqual(sgNode.matrix, matrix, 'should copy the matrix');

  sgNode.setMatrix(matrix, false);
  t.equal(sgNode.matrix, matrix, 'should asign the matrix');

  t.end();
});

test('ScenegraphNode#setMatrixComponents', (t) => {
  const sgNode = new ScenegraphNode();
  const position = new Vector3(1, 1, 1);
  const rotation = new Vector3(2, 2, 2);
  const scale = new Vector3(3, 3, 3);

  sgNode.setMatrixComponents({update: false});
  t.deepEqual(sgNode.matrix, new Matrix4(), 'should not update the matrix');

  sgNode.setMatrixComponents({position, rotation, scale});
  t.deepEqual(
    sgNode.matrix,
    new Matrix4().translate(position).rotateXYZ(rotation).scale(scale),
    'should update the matrix'
  );

  t.end();
});

test('ScenegraphNode#update', (t) => {
  const sgNode = new ScenegraphNode();
  const position = new Vector3(1, 1, 1);
  const rotation = new Vector3(2, 2, 2);
  const scale = new Vector3(3, 3, 3);

  sgNode.update();
  t.deepEqual(sgNode.matrix, new Matrix4(), 'should update the matrix');

  sgNode.update({position, rotation, scale});
  t.deepEqual(
    sgNode.matrix,
    new Matrix4().translate(position).rotateXYZ(rotation).scale(scale),
    'should update the matrix'
  );

  t.end();
});

test('ScenegraphNode#getCoordinateUniforms', (t) => {
  const sgNode = new ScenegraphNode();

  t.throws(() => sgNode.getCoordinateUniforms(), 'should throw on missing viewMatrix');

  const uniforms = sgNode.getCoordinateUniforms(new Matrix4());
  t.ok(uniforms.viewMatrix, 'should return viewMatrix');
  t.ok(uniforms.modelMatrix, 'should return modelMatrix');
  t.ok(uniforms.objectMatrix, 'should return objectMatrix');
  t.ok(uniforms.worldMatrix, 'should return worldMatrix');
  t.ok(uniforms.worldInverseMatrix, 'should return worldInverseMatrix');
  t.ok(uniforms.worldInverseTransposeMatrix, 'should return worldInverseTransposeMatrix');

  t.end();
});


text:
void write_book(IBookRepository&);

#endif


text:
class MoveSerialIdentificationCategoryToCharacteristicsInQueryTool < ActiveRecord::DataMigration
  def up
    QueryField.find_by(name: 'serial_identification')&.update!(query_category: QueryCategory.find_by(name: 'Characteristics'))
  end
end


text:
/**
 * @output wp-includes/js/customize-base.js
 */

/** @namespace wp */
window.wp = window.wp || {};

(function( exports, $ ){
	var api = {}, ctor, inherits,
		slice = Array.prototype.slice;

	// Shared empty constructor function to aid in prototype-chain creation.
	ctor = function() {};

	/**
	 * Helper function to correctly set up the prototype chain, for subclasses.
	 * Similar to `goog.inherits`, but uses a hash of prototype properties and
	 * class properties to be extended.
	 *
	 * @param object parent      Parent class constructor to inherit from.
	 * @param object protoProps  Properties to apply to the prototype for use as class instance properties.
	 * @param object staticProps Properties to apply directly to the class constructor.
	 * @return child The subclassed constructor.
	 */
	inherits = function( parent, protoProps, staticProps ) {
		var child;

		/*
		 * The constructor function for the new subclass is either defined by you
		 * (the "constructor" property in your `extend` definition), or defaulted
		 * by us to simply call `super()`.
		 */
		if ( protoProps && protoProps.hasOwnProperty( 'constructor' ) ) {
			child = protoProps.constructor;
		} else {
			child = function() {
				/*
				 * Storing the result `super()` before returning the value
				 * prevents a bug in Opera where, if the constructor returns
				 * a function, Opera will reject the return value in favor of
				 * the original object. This causes all sorts of trouble.
				 */
				var result = parent.apply( this, arguments );
				return result;
			};
		}

		// Inherit class (static) properties from parent.
		$.extend( child, parent );

		// Set the prototype chain to inherit from `parent`,
		// without calling `parent`'s constructor function.
		ctor.prototype  = parent.prototype;
		child.prototype = new ctor();

		// Add prototype properties (instance properties) to the subclass,
		// if supplied.
		if ( protoProps ) {
			$.extend( child.prototype, protoProps );
		}

		// Add static properties to the constructor function, if supplied.
		if ( staticProps ) {
			$.extend( child, staticProps );
		}

		// Correctly set child's `prototype.constructor`.
		child.prototype.constructor = child;

		// Set a convenience property in case the parent's prototype is needed later.
		child.__super__ = parent.prototype;

		return child;
	};

	/**
	 * Base class for object inheritance.
	 */
	api.Class = function( applicator, argsArray, options ) {
		var magic, args = arguments;

		if ( applicator && argsArray && api.Class.applicator === applicator ) {
			args = argsArray;
			$.extend( this, options || {} );
		}

		magic = this;

		/*
		 * If the class has a method called "instance",
		 * the return value from the class' constructor will be a function that
		 * calls the "instance" method.
		 *
		 * It is also an object that has properties and methods inside it.
		 */
		if ( this.instance ) {
			magic = function() {
				return magic.instance.apply( magic, arguments );
			};

			$.extend( magic, this );
		}

		magic.initialize.apply( magic, args );
		return magic;
	};

	/**
	 * Creates a subclass of the class.
	 *
	 * @param object protoProps  Properties to apply to the prototype.
	 * @param object staticProps Properties to apply directly to the class.
	 * @return child The subclass.
	 */
	api.Class.extend = function( protoProps, staticProps ) {
		var child = inherits( this, protoProps, staticProps );
		child.extend = this.extend;
		return child;
	};

	api.Class.applicator = {};

	/**
	 * Initialize a class instance.
	 *
	 * Override this function in a subclass as needed.
	 */
	api.Class.prototype.initialize = function() {};

	/*
	 * Checks whether a given instance extended a constructor.
	 *
	 * The magic surrounding the instance parameter causes the instanceof
	 * keyword to return inaccurate results; it defaults to the function's
	 * prototype instead of the constructor chain. Hence this function.
	 */
	api.Class.prototype.extended = function( constructor ) {
		var proto = this;

		while ( typeof proto.constructor !== 'undefined' ) {
			if ( proto.constructor === constructor ) {
				return true;
			}
			if ( typeof proto.constructor.__super__ === 'undefined' ) {
				return false;
			}
			proto = proto.constructor.__super__;
		}
		return false;
	};

	/**
	 * An events manager object, offering the ability to bind to and trigger events.
	 *
	 * Used as a mixin.
	 */
	api.Events = {
		trigger: function( id ) {
			if ( this.topics && this.topics[ id ] ) {
				this.topics[ id ].fireWith( this, slice.call( arguments, 1 ) );
			}
			return this;
		},

		bind: function( id ) {
			this.topics = this.topics || {};
			this.topics[ id ] = this.topics[ id ] || $.Callbacks();
			this.topics[ id ].add.apply( this.topics[ id ], slice.call( arguments, 1 ) );
			return this;
		},

		unbind: function( id ) {
			if ( this.topics && this.topics[ id ] ) {
				this.topics[ id ].remove.apply( this.topics[ id ], slice.call( arguments, 1 ) );
			}
			return this;
		}
	};

	/**
	 * Observable values that support two-way binding.
	 *
	 * @memberOf wp.customize
	 * @alias wp.customize.Value
	 *
	 * @constructor
	 */
	api.Value = api.Class.extend(/** @lends wp.customize.Value.prototype */{
		/**
		 * @param {mixed}  initial The initial value.
		 * @param {Object} options
		 */
		initialize: function( initial, options ) {
			this._value = initial; // @todo Potentially change this to a this.set() call.
			this.callbacks = $.Callbacks();
			this._dirty = false;

			$.extend( this, options || {} );

			this.set = this.set.bind( this );
		},

		/*
		 * Magic. Returns a function that will become the instance.
		 * Set to null to prevent the instance from extending a function.
		 */
		instance: function() {
			return arguments.length ? this.set.apply( this, arguments ) : this.get();
		},

		/**
		 * Get the value.
		 *
		 * @return {mixed}
		 */
		get: function() {
			return this._value;
		},

		/**
		 * Set the value and trigger all bound callbacks.
		 *
		 * @param {Object} to New value.
		 */
		set: function( to ) {
			var from = this._value;

			to = this._setter.apply( this, arguments );
			to = this.validate( to );

			// Bail if the sanitized value is null or unchanged.
			if ( null === to || _.isEqual( from, to ) ) {
				return this;
			}

			this._value = to;
			this._dirty = true;

			this.callbacks.fireWith( this, [ to, from ] );

			return this;
		},

		_setter: function( to ) {
			return to;
		},

		setter: function( callback ) {
			var from = this.get();
			this._setter = callback;
			// Temporarily clear value so setter can decide if it's valid.
			this._value = null;
			this.set( from );
			return this;
		},

		resetSetter: function() {
			this._setter = this.constructor.prototype._setter;
			this.set( this.get() );
			return this;
		},

		validate: function( value ) {
			return value;
		},

		/**
		 * Bind a function to be invoked whenever the value changes.
		 *
		 * @param {...Function} A function, or multiple functions, to add to the callback stack.
		 */
		bind: function() {
			this.callbacks.add.apply( this.callbacks, arguments );
			return this;
		},

		/**
		 * Unbind a previously bound function.
		 *
		 * @param {...Function} A function, or multiple functions, to remove from the callback stack.
		 */
		unbind: function() {
			this.callbacks.remove.apply( this.callbacks, arguments );
			return this;
		},

		link: function() { // values*
			var set = this.set;
			$.each( arguments, function() {
				this.bind( set );
			});
			return this;
		},

		unlink: function() { // values*
			var set = this.set;
			$.each( arguments, function() {
				this.unbind( set );
			});
			return this;
		},

		sync: function() { // values*
			var that = this;
			$.each( arguments, function() {
				that.link( this );
				this.link( that );
			});
			return this;
		},

		unsync: function() { // values*
			var that = this;
			$.each( arguments, function() {
				that.unlink( this );
				this.unlink( that );
			});
			return this;
		}
	});

	/**
	 * A collection of observable values.
	 *
	 * @memberOf wp.customize
	 * @alias wp.customize.Values
	 *
	 * @constructor
	 * @augments wp.customize.Class
	 * @mixes wp.customize.Events
	 */
	api.Values = api.Class.extend(/** @lends wp.customize.Values.prototype */{

		/**
		 * The default constructor for items of the collection.
		 *
		 * @type {object}
		 */
		defaultConstructor: api.Value,

		initialize: function( options ) {
			$.extend( this, options || {} );

			this._value = {};
			this._deferreds = {};
		},

		/**
		 * Get the instance of an item from the collection if only ID is specified.
		 *
		 * If more than one argument is supplied, all are expected to be IDs and
		 * the last to be a function callback that will be invoked when the requested
		 * items are available.
		 *
		 * @see {api.Values.when}
		 *
		 * @param {string} id ID of the item.
		 * @param {...}       Zero or more IDs of items to wait for and a callback
		 *                    function to invoke when they're available. Optional.
		 * @return {mixed} The item instance if only one ID was supplied.
		 *                 A Deferred Promise object if a callback function is supplied.
		 */
		instance: function( id ) {
			if ( arguments.length === 1 ) {
				return this.value( id );
			}

			return this.when.apply( this, arguments );
		},

		/**
		 * Get the instance of an item.
		 *
		 * @param {string} id The ID of the item.
		 * @return {[type]} [description]
		 */
		value: function( id ) {
			return this._value[ id ];
		},

		/**
		 * Whether the collection has an item with the given ID.
		 *
		 * @param {string} id The ID of the item to look for.
		 * @return {boolean}
		 */
		has: function( id ) {
			return typeof this._value[ id ] !== 'undefined';
		},

		/**
		 * Add an item to the collection.
		 *
		 * @param {string|wp.customize.Class} item - The item instance to add, or the ID for the instance to add. When an ID string is supplied, then itemObject must be provided.
		 * @param {wp.customize.Class}        [itemObject] - The item instance when the first argument is a ID string.
		 * @return {wp.customize.Class} The new item's instance, or an existing instance if already added.
		 */
		add: function( item, itemObject ) {
			var collection = this, id, instance;
			if ( 'string' === typeof item ) {
				id = item;
				instance = itemObject;
			} else {
				if ( 'string' !== typeof item.id ) {
					throw new Error( 'Unknown key' );
				}
				id = item.id;
				instance = item;
			}

			if ( collection.has( id ) ) {
				return collection.value( id );
			}

			collection._value[ id ] = instance;
			instance.parent = collection;

			// Propagate a 'change' event on an item up to the collection.
			if ( instance.extended( api.Value ) ) {
				instance.bind( collection._change );
			}

			collection.trigger( 'add', instance );

			// If a deferred object exists for this item,
			// resolve it.
			if ( collection._deferreds[ id ] ) {
				collection._deferreds[ id ].resolve();
			}

			return collection._value[ id ];
		},

		/**
		 * Create a new item of the collection using the collection's default constructor
		 * and store it in the collection.
		 *
		 * @param {string} id    The ID of the item.
		 * @param {mixed}  value Any extra arguments are passed into the item's initialize method.
		 * @return {mixed} The new item's instance.
		 */
		create: function( id ) {
			return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) );
		},

		/**
		 * Iterate over all items in the collection invoking the provided callback.
		 *
		 * @param {Function} callback Function to invoke.
		 * @param {Object}   context  Object context to invoke the function with. Optional.
		 */
		each: function( callback, context ) {
			context = typeof context === 'undefined' ? this : context;

			$.each( this._value, function( key, obj ) {
				callback.call( context, obj, key );
			});
		},

		/**
		 * Remove an item from the collection.
		 *
		 * @param {string} id The ID of the item to remove.
		 */
		remove: function( id ) {
			var value = this.value( id );

			if ( value ) {

				// Trigger event right before the element is removed from the collection.
				this.trigger( 'remove', value );

				if ( value.extended( api.Value ) ) {
					value.unbind( this._change );
				}
				delete value.parent;
			}

			delete this._value[ id ];
			delete this._deferreds[ id ];

			// Trigger removed event after the item has been eliminated from the collection.
			if ( value ) {
				this.trigger( 'removed', value );
			}
		},

		/**
		 * Runs a callback once all requested values exist.
		 *
		 * when( ids*, [callback] );
		 *
		 * For example:
		 *     when( id1, id2, id3, function( value1, value2, value3 ) {} );
		 *
		 * @return $.Deferred.promise();
		 */
		when: function() {
			var self = this,
				ids  = slice.call( arguments ),
				dfd  = $.Deferred();

			// If the last argument is a callback, bind it to .done().
			if ( typeof ids[ ids.length - 1 ] === 'function' ) {
				dfd.done( ids.pop() );
			}

			/*
			 * Create a stack of deferred objects for each item that is not
			 * yet available, and invoke the supplied callback when they are.
			 */
			$.when.apply( $, $.map( ids, function( id ) {
				if ( self.has( id ) ) {
					return;
				}

				/*
				 * The requested item is not available yet, create a deferred
				 * object to resolve when it becomes available.
				 */
				return self._deferreds[ id ] = self._deferreds[ id ] || $.Deferred();
			})).done( function() {
				var values = $.map( ids, function( id ) {
						return self( id );
					});

				// If a value is missing, we've used at least one expired deferred.
				// Call Values.when again to generate a new deferred.
				if ( values.length !== ids.length ) {
					// ids.push( callback );
					self.when.apply( self, ids ).done( function() {
						dfd.resolveWith( self, values );
					});
					return;
				}

				dfd.resolveWith( self, values );
			});

			return dfd.promise();
		},

		/**
		 * A helper function to propagate a 'change' event from an item
		 * to the collection itself.
		 */
		_change: function() {
			this.parent.trigger( 'change', this );
		}
	});

	// Create a global events bus on the Customizer.
	$.extend( api.Values.prototype, api.Events );

	/**
	 * Cast a string to a jQuery collection if it isn't already.
	 *
	 * @param {string|jQuery collection} element
	 */
	api.ensure = function( element ) {
		return typeof element === 'string' ? $( element ) : element;
	};

	/**
	 * An observable value that syncs with an element.
	 *
	 * Handles inputs, selects, and textareas by default.
	 *
	 * @memberOf wp.customize
	 * @alias wp.customize.Element
	 *
	 * @constructor
	 * @augments wp.customize.Value
	 * @augments wp.customize.Class
	 */
	api.Element = api.Value.extend(/** @lends wp.customize.Element */{
		initialize: function( element, options ) {
			var self = this,
				synchronizer = api.Element.synchronizer.html,
				type, update, refresh;

			this.element = api.ensure( element );
			this.events = '';

			if ( this.element.is( 'input, select, textarea' ) ) {
				type = this.element.prop( 'type' );
				this.events += ' change input';
				synchronizer = api.Element.synchronizer.val;

				if ( this.element.is( 'input' ) && api.Element.synchronizer[ type ] ) {
					synchronizer = api.Element.synchronizer[ type ];
				}
			}

			api.Value.prototype.initialize.call( this, null, $.extend( options || {}, synchronizer ) );
			this._value = this.get();

			update = this.update;
			refresh = this.refresh;

			this.update = function( to ) {
				if ( to !== refresh.call( self ) ) {
					update.apply( this, arguments );
				}
			};
			this.refresh = function() {
				self.set( refresh.call( self ) );
			};

			this.bind( this.update );
			this.element.on( this.events, this.refresh );
		},

		find: function( selector ) {
			return $( selector, this.element );
		},

		refresh: function() {},

		update: function() {}
	});

	api.Element.synchronizer = {};

	$.each( [ 'html', 'val' ], function( index, method ) {
		api.Element.synchronizer[ method ] = {
			update: function( to ) {
				this.element[ method ]( to );
			},
			refresh: function() {
				return this.element[ method ]();
			}
		};
	});

	api.Element.synchronizer.checkbox = {
		update: function( to ) {
			this.element.prop( 'checked', to );
		},
		refresh: function() {
			return this.element.prop( 'checked' );
		}
	};

	api.Element.synchronizer.radio = {
		update: function( to ) {
			this.element.filter( function() {
				return this.value === to;
			}).prop( 'checked', true );
		},
		refresh: function() {
			return this.element.filter( ':checked' ).val();
		}
	};

	$.support.postMessage = !! window.postMessage;

	/**
	 * A communicator for sending data from one window to another over postMessage.
	 *
	 * @memberOf wp.customize
	 * @alias wp.customize.Messenger
	 *
	 * @constructor
	 * @augments wp.customize.Class
	 * @mixes wp.customize.Events
	 */
	api.Messenger = api.Class.extend(/** @lends wp.customize.Messenger.prototype */{
		/**
		 * Create a new Value.
		 *
		 * @param {string} key     Unique identifier.
		 * @param {mixed}  initial Initial value.
		 * @param {mixed}  options Options hash. Optional.
		 * @return {Value} Class instance of the Value.
		 */
		add: function( key, initial, options ) {
			return this[ key ] = new api.Value( initial, options );
		},

		/**
		 * Initialize Messenger.
		 *
		 * @param {Object} params  - Parameters to configure the messenger.
		 *        {string} params.url          - The URL to communicate with.
		 *        {window} params.targetWindow - The window instance to communicate with. Default window.parent.
		 *        {string} params.channel      - If provided, will send the channel with each message and only accept messages a matching channel.
		 * @param {Object} options - Extend any instance parameter or method with this object.
		 */
		initialize: function( params, options ) {
			// Target the parent frame by default, but only if a parent frame exists.
			var defaultTarget = window.parent === window ? null : window.parent;

			$.extend( this, options || {} );

			this.add( 'channel', params.channel );
			this.add( 'url', params.url || '' );
			this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
				var urlParser = document.createElement( 'a' );
				urlParser.href = to;
				// Port stripping needed by IE since it adds to host but not to event.origin.
				return urlParser.protocol + '//' + urlParser.host.replace( /:(80|443)$/, '' );
			});

			// First add with no value.
			this.add( 'targetWindow', null );
			// This avoids SecurityErrors when setting a window object in x-origin iframe'd scenarios.
			this.targetWindow.set = function( to ) {
				var from = this._value;

				to = this._setter.apply( this, arguments );
				to = this.validate( to );

				if ( null === to || from === to ) {
					return this;
				}

				this._value = to;
				this._dirty = true;

				this.callbacks.fireWith( this, [ to, from ] );

				return this;
			};
			// Now set it.
			this.targetWindow( params.targetWindow || defaultTarget );

			/*
			 * Since we want jQuery to treat the receive function as unique
			 * to this instance, we give the function a new guid.
			 *
			 * This will prevent every Messenger's receive function from being
			 * unbound when calling $.off( 'message', this.receive );
			 */
			this.receive = this.receive.bind( this );
			this.receive.guid = $.guid++;

			$( window ).on( 'message', this.receive );
		},

		destroy: function() {
			$( window ).off( 'message', this.receive );
		},

		/**
		 * Receive data from the other window.
		 *
		 * @param {jQuery.Event} event Event with embedded data.
		 */
		receive: function( event ) {
			var message;

			event = event.originalEvent;

			if ( ! this.targetWindow || ! this.targetWindow() ) {
				return;
			}

			// Check to make sure the origin is valid.
			if ( this.origin() && event.origin !== this.origin() ) {
				return;
			}

			// Ensure we have a string that's JSON.parse-able.
			if ( typeof event.data !== 'string' || event.data[0] !== '{' ) {
				return;
			}

			message = JSON.parse( event.data );

			// Check required message properties.
			if ( ! message || ! message.id || typeof message.data === 'undefined' ) {
				return;
			}

			// Check if channel names match.
			if ( ( message.channel || this.channel() ) && this.channel() !== message.channel ) {
				return;
			}

			this.trigger( message.id, message.data );
		},

		/**
		 * Send data to the other window.
		 *
		 * @param {string} id   The event name.
		 * @param {Object} data Data.
		 */
		send: function( id, data ) {
			var message;

			data = typeof data === 'undefined' ? null : data;

			if ( ! this.url() || ! this.targetWindow() ) {
				return;
			}

			message = { id: id, data: data };
			if ( this.channel() ) {
				message.channel = this.channel();
			}

			this.targetWindow().postMessage( JSON.stringify( message ), this.origin() );
		}
	});

	// Add the Events mixin to api.Messenger.
	$.extend( api.Messenger.prototype, api.Events );

	/**
	 * Notification.
	 *
	 * @class
	 * @augments wp.customize.Class
	 * @since 4.6.0
	 *
	 * @memberOf wp.customize
	 * @alias wp.customize.Notification
	 *
	 * @param {string}  code - The error code.
	 * @param {object}  params - Params.
	 * @param {string}  params.message=null - The error message.
	 * @param {string}  [params.type=error] - The notification type.
	 * @param {boolean} [params.fromServer=false] - Whether the notification was server-sent.
	 * @param {string}  [params.setting=null] - The setting ID that the notification is related to.
	 * @param {*}       [params.data=null] - Any additional data.
	 */
	api.Notification = api.Class.extend(/** @lends wp.customize.Notification.prototype */{

		/**
		 * Template function for rendering the notification.
		 *
		 * This will be populated with template option or else it will be populated with template from the ID.
		 *
		 * @since 4.9.0
		 * @var {Function}
		 */
		template: null,

		/**
		 * ID for the template to render the notification.
		 *
		 * @since 4.9.0
		 * @var {string}
		 */
		templateId: 'customize-notification',

		/**
		 * Additional class names to add to the notification container.
		 *
		 * @since 4.9.0
		 * @var {string}
		 */
		containerClasses: '',

		/**
		 * Initialize notification.
		 *
		 * @since 4.9.0
		 *
		 * @param {string}   code - Notification code.
		 * @param {Object}   params - Notification parameters.
		 * @param {string}   params.message - Message.
		 * @param {string}   [params.type=error] - Type.
		 * @param {string}   [params.setting] - Related setting ID.
		 * @param {Function} [params.template] - Function for rendering template. If not provided, this will come from templateId.
		 * @param {string}   [params.templateId] - ID for template to render the notification.
		 * @param {string}   [params.containerClasses] - Additional class names to add to the notification container.
		 * @param {boolean}  [params.dismissible] - Whether the notification can be dismissed.
		 */
		initialize: function( code, params ) {
			var _params;
			this.code = code;
			_params = _.extend(
				{
					message: null,
					type: 'error',
					fromServer: false,
					data: null,
					setting: null,
					template: null,
					dismissible: false,
					containerClasses: ''
				},
				params
			);
			delete _params.code;
			_.extend( this, _params );
		},

		/**
		 * Render the notification.
		 *
		 * @since 4.9.0
		 *
		 * @return {jQuery} Notification container element.
		 */
		render: function() {
			var notification = this, container, data;
			if ( ! notification.template ) {
				notification.template = wp.template( notification.templateId );
			}
			data = _.extend( {}, notification, {
				alt: notification.parent && notification.parent.alt
			} );
			container = $( notification.template( data ) );

			if ( notification.dismissible ) {
				container.find( '.notice-dismiss' ).on( 'click keydown', function( event ) {
					if ( 'keydown' === event.type && 13 !== event.which ) {
						return;
					}

					if ( notification.parent ) {
						notification.parent.remove( notification.code );
					} else {
						container.remove();
					}
				});
			}

			return container;
		}
	});

	// The main API object is also a collection of all customizer settings.
	api = $.extend( new api.Values(), api );

	/**
	 * Get all customize settings.
	 *
	 * @alias wp.customize.get
	 *
	 * @return {Object}
	 */
	api.get = function() {
		var result = {};

		this.each( function( obj, key ) {
			result[ key ] = obj.get();
		});

		return result;
	};

	/**
	 * Utility function namespace
	 *
	 * @namespace wp.customize.utils
	 */
	api.utils = {};

	/**
	 * Parse query string.
	 *
	 * @since 4.7.0
	 * @access public
	 *
	 * @alias wp.customize.utils.parseQueryString
	 *
	 * @param {string} queryString Query string.
	 * @return {Object} Parsed query string.
	 */
	api.utils.parseQueryString = function parseQueryString( queryString ) {
		var queryParams = {};
		_.each( queryString.split( '&' ), function( pair ) {
			var parts, key, value;
			parts = pair.split( '=', 2 );
			if ( ! parts[0] ) {
				return;
			}
			key = decodeURIComponent( parts[0].replace( /\+/g, ' ' ) );
			key = key.replace( / /g, '_' ); // What PHP does.
			if ( _.isUndefined( parts[1] ) ) {
				value = null;
			} else {
				value = decodeURIComponent( parts[1].replace( /\+/g, ' ' ) );
			}
			queryParams[ key ] = value;
		} );
		return queryParams;
	};

	/**
	 * Expose the API publicly on window.wp.customize
	 *
	 * @namespace wp.customize
	 */
	exports.customize = api;
})( wp, jQuery );


text:
sudoku_solver
=============
Trabajo final de la asignatura Inteligencia Artificial 2 de la Universidad de Sevilla.

End work for Artificial intelligence 2 lecture of the University of Sevilla.


text:
% This code is called at the beginning of "RegPSO_main" to ensure that
% the parameters selected are consistent with each other, make corrections
% as necessary, and either display notices of changes made or terminate with
% an error message indicating what data is inconsistent.

%   Copyright 2008, 2009, 2010, 2011 George I. Evers (moved from "RegPSO_main.m" on May 3, 2009).

disp('AUTOMATIC INPUT VALIDATION')
fprintf('\r')
auto_changes_made = false;
    % If this is still false at the end of this file, a message will be
        %displayed confirming that no changes have been made.
TableParams_num_tables = 1;
TableParams_min_num_unique_columns = 1;
TableParams_OnOff_num_columns_fixed = true;
TableParams_OnOff_calculate_min_median_per_table = true;
if min(min(range_IS0)) <= 0
    error(['You have set at least one dimension of "range_IS0" less than '...
        'or equal to zero.  For each dimension of the search space, '...
        'there is a center and a '...
        'range.  Particles are initialized within half the range to the '...
        'left of center and half the range to the right of center.  Some '...
        'portions of the program expect a positive range and will '...
        'malfunction in the presence of a nonsensical input.'])
end
if OnOff_SuccessfulUnsuccessful
    if ~exist('thresh_for_succ', 'var')
        error(['No threshold for success has yet been defined '...
            'for dim = ', num2str(dim), ' and the ', ...
            objective, ' objective.  '...
            'Please check the literature and add a common '...
            'threshold to "Objectives.m" for the particular '...
            'objective and problem dimensionality you are '...
            'testing.  If no common threshold exists for the '...
            'case you are testing, please ensure that the '...
            'threshold you specify makes sense when considering '...
            'threshold values that have been used in other cases.  '...
            'Since higher dimensionality generally '...
            'produces higher function values, it would be '...
            'nonsensical to use the same threshold regardless '...
            'of problem dimensionality or objective.'])
    end
end
if OnOff_lbest
    if OnOff_GCPSO
        error('You have activated switches "OnOff_lbest" and "OnOff_GCPSO" concurrently: since lbest PSO does not have knowledge of the global best, the two seem conceptually incompatible and have not been overlaid in the code.  Please de-activate one switch or the other.')
    end
	if OnOff_Cauchy_mutation_of_global_best
        error('You have activated switches "OnOff_lbest" and "OnOff_Cauchy_mutation_of_global_best" concurrently: since lbest PSO does not have knowledge of the global best, the two seem conceptually incompatible and have not been overlaid in the code.  Please de-activate one switch or the other.')
	end
end
if OnOff_position_clamping && OnOff_v_reset
    disp(['Velocity reset is a special case of position clamping.  They '...
    	'should not both be active at once.'])
    error('OnOff_v_reset == true && OnOff_position_clamping == true')
end
if (isequal(objective, 'Schaffers_f6') && (dim ~= 2))
    disp(['Please set "dim" = 2 in "Control_Panel.m." '...
    	'(This message has been generated to ensure the user understands that Schaffer''s f6 is only a two-dimensional function.)'])
    error('You have selected Schafer''s f6 function which is two-dimensional, but the dimensionality selected is other than two.')
end
if OnOff_lbest == 1
    if lbest_neighb_size > np
        error('You have selected a neighborhood size larger than the entire swarm.  That is, (i) OnOff_lbest == true, and (ii) lbest_neighb_size > np.')
    end
end
if OnOff_graphs
    if (~OnOff_fghist)
        if (OnOff_graph_fg)
            OnOff_fghist = true;
            disp(['Since switch "OnOff_graph_fg" is active, which indicates the desire to '...
                'plot the function value produced by the global best '...
                'versus time, switch "OnOff_fghist" has '...
                'automatically been activated in order to maintain the '...
                'necessary history, "fghist," from which to generate the desired graph.'])
            fprintf('\r') %Insert a carriage return before future outputs.
            auto_changes_made = true;
        end
        if OnOff_graph_fg_mean
            if (num_trials > 1)
                OnOff_fghist = true;
                disp(['Since switch "OnOff_graph_fg_mean" is active, which indicates '...
                    'the desire to plot the mean function value produced '...
                    'by the global best versus time, switch '...
                    '"OnOff_fghist" has automatically been activated in order to maintain '...
                    'the necessary history, "fghist_over_all_trials", from which to compute "fg_mean".'])
                fprintf('\r') %Insert a carriage return before future outputs.
                auto_changes_made = true;
                if ~OnOff_Autosave_Workspace_Per_Trial
                    OnOff_Autosave_Workspace_Per_Trial = true;
                    disp(['Since switch "OnOff_graph_fg_mean" is active, switch "OnOff_Autosave_Workspace_Per_Trial" '...
                        'has automatically been activated so that the necessary history, "fghist_over_all_trials," can be '...
                        'constructed within "Load_trial_data_for_stats.m" using the "fghist" of each trial''s workspace: '...
                        '"fghist_over_all_trials" is necessary to compute "fg_mean".'])
                    disp(['Note: It is also generally a good idea to concurrently activate switch "OnOff_Autodelete_Trial_Data" '...
                        'to regulate the sizes of saved workspaces.  It is recommended that you do this before execution.'])
                    fprintf('\r') %Insert a carriage return before future outputs.
                    auto_changes_made = true;
                end
            elseif (num_trials == 1)
                disp(['Switch "OnOff_graph_fg_mean" is active, but "num_trials" == 1.  In other words, you have chosen '...
                	'to graph the mean function value per iteration over multiple trials, but no mean will be generated since only one trial is to be conducted.  '...
                	'The graph of mean behavior will not take effect.  If your intention was to graph the function value '...
                    'of the global best over one trial, please activate switch "OnOff_graph_fg" instead.'])
                fprintf('\r') %Insert a carriage return before future outputs.
                auto_changes_made = true;
            end
        end
    end
    if (OnOff_graph_ObjFun_f_vs_2D || OnOff_swarm_trajectory || OnOff_phase_plot) && (isequal(objective, 'NN') || isequal(objective, 'Quartic_Noisy') || isequal(objective, 'Rosenbrock') || isequal(objective, 'Schaffers_f6') || isequal(objective, 'Weighted_Sphere'))
        OnOff_graph_ObjFun_f_vs_2D = false;
        OnOff_swarm_trajectory = false;
        OnOff_phase_plot = false;
        disp(['Any of graphing switches "OnOff_graph_ObjFun_f_vs_2D", "OnOff_swarm_trajectory", '...
            'or "OnOff_phase_plot" which were active have been de-activated since they are not '...
            'yet compatible with the ' objective ' objective.  You may subscribe to updates at '...
            'www.georgeevers.org/pso_research_toolbox.htm '...
            'to be notified when this functionality becomes available.'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
    if OnOff_graph_f && (num_trials == 1) && ~OnOff_fhist %If the function value of each
           %particle is to be graphed (instead of only the function value
           %of the global best),
        OnOff_fhist = true; %matrix "fhist," which maintains in each
             %row the function value of the corresponding particle, must be
             %maintained.
        disp(['Because you have activated "OnOff_graph_f," which graphs'...
            ' the function value versus iteration for every '...
            'single particle, matrix "fhist" must be maintained; '...
            'therefore, "OnOff_fhist" has been activated automatically."'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
    if OnOff_graph_g && (num_trials == 1) && ~OnOff_ghist
        OnOff_ghist = true;
        disp(['Because you have activated "OnOff_graph_g," which graphs the position of the global best versus iteration, '...
        	'matrix "ghist" must be maintained; therefore, "OnOff_ghist" has been activated automatically."'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
    if OnOff_graph_p && (num_trials == 1) && ~OnOff_phist
        OnOff_phist = true;
        disp(['Because you have activated "OnOff_graph_p," which graphs the function values of the global best versus iteration, '...
        	'matrix "phist" must be maintained; therefore, "OnOff_phist" has been activated automatically."'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
    if OnOff_graph_v && (num_trials == 1) && ~OnOff_vhist
        OnOff_vhist = true;
        disp(['Because you have activated "OnOff_graph_v," which graphs the function values of the global best versus iteration, '...
        	'matrix "vhist" must be maintained; therefore, "OnOff_vhist" has been activated automatically."'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
    if OnOff_swarm_trajectory
        if dim == 2
            if Reg_Method == 1
                if (OnOff_plot_box_4_new_search_space) && (~OnOff_g_after_each_grouping)
                    OnOff_g_after_each_grouping = true;
                    disp(['Since you have selected via "OnOff_plot_box_4_new_search_space" to plot a box showing the new search '...
                    	'space of each regrouping, "OnOff_g_after_each_grouping" has been activated automatically to allow access '...
                    	'to the global best prior to the occurrence of each regrouping.'])
                    fprintf('\r') %Insert a carriage return before future outputs.
                    auto_changes_made = true;
                end
            end
            if (OnOff_mark_personal_bests) && (~OnOff_phist)
                OnOff_phist = true;
                disp('"OnOff_phist" has been activated for you in order to mark the personal bests on the contour map since "OnOff_mark_personal_bests" is active.')
                fprintf('\r') %Insert a carriage return before future outputs.
                auto_changes_made = true;
            end
            if (OnOff_mark_global_best_always || OnOff_mark_global_best_on_zoomed_graph) && (~OnOff_ghist)
                OnOff_ghist = true;
                disp('"OnOff_ghist" has been activated for you in order to mark the global best on the contour map since "OnOff_mark_global_best_always" is active.')
                fprintf('\r') %Insert a carriage return before future outputs.
                auto_changes_made = true;
            end
        else %i.e. dim ~= 2
            disp(['You have activated graphs of the swarm trajectory, but this cannot be done since the number '...
                'of dimensions selected is other than 2.'])
            fprintf('\r') %Insert a carriage return before future outputs.
            auto_changes_made = true;
        end
    end
    if OnOff_phase_plot
        if dim ~= 2
            disp(['You have activated the phase plot, but this cannot be done since the number '...
                'of dimensions selected is other than 2.'])
            fprintf('\r') %Insert a carriage return before future outputs.
            auto_changes_made = true;
        end
    end
    if ~OnOff_xhist && (((dim == 2) && (OnOff_swarm_trajectory || (OnOff_phase_plot && num_trials == 1))) || (OnOff_graph_x && num_trials == 1))
        OnOff_xhist = true;
        disp(['Since "OnOff_swarm_trajectory," "OnOff_phase_plot," or "OnOff_graph_x" is active, '...
        '"OnOff_xhist" has been activated automatically so that "xhist" will be maintained from '...
        'which to generate the desired graph(s).'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
end
if Reg_Method ~= 0 %i.e. regrouping is active.
    if Reg_Method == 1
        if OnOff_NormR_stag_det == 0
            disp('You have selected Reg_Method 1 but have not activated "OnOff_NormR_stag_det."')
            error('Please activate "OnOff_NormR_stag_det" and ensure that "stag_thresh" is to your liking.')
        end
        if max_num_groupings < 2
            disp(['If you wish to use Regrouping Method 1, set "max_num_groupings" to either: (i) a very large number '...
            	'so that either "max_iter_over_all_groupings" (if ~OnOff_func_evals) or "max_FEs_over_all_groupings" '...
            	'(if OnOff_func_evals) will terminate each trial, or (ii) the exact # of groupings desired, in which '...
            	'case "max_iter_over_all_groupings" should be set larger than "max_iter_per_grouping"*"max_num_groupings" to ensure that '...
            	'the desired number of groupings are carried out.  The # of groupings is the initial grouping plus all regroupings.'])
            error('"Reg_Method" = 1, but "max_num_groupings" < 2.')
        end
        if OnOff_num_gs_identical_b4_refinement
            if (~OnOff_g_after_each_grouping) && (num_gs_identical_b4_refinement ~= 0) %latter variable only defined when previous line is active
                OnOff_g_after_each_grouping = true;
                disp(['"OnOff_num_gs_identical_b4_refinement" is active expressing the desire to reduce the regrouping '...
                	'factor after "num_gs_identical_b4_refinement" global bests at groupings'' end return the same '...
                	'rounded values.  Since "num_gs_identical_b4_refinement" is not zero, this requires that '...
                	'"OnOff_g_after_each_grouping" also be active, so it has been activated for you.'])
                fprintf('\r') %Insert a carriage return before future outputs.
                auto_changes_made = true;
            end
        end
    elseif Reg_Method == 2 %Reduce workspace clutter by generating the variables below only when they will be used.
        if max_num_groupings < 2
            disp(['If you wish to use Regrouping Method 2, set "max_num_groupings" to the total # of groupings desired. '...
            	'The total # of groupings is the initial grouping plus all regroupings.  Each grouping consists of '...
            	'"num_runs_b4_reduction" runs, after which the search space becomes the region between each run''s "g."'])
            error('"Reg_Method" = 2, but "max_num_groupings" < 2.')
        elseif max_num_groupings > 50
            disp(['Regrouping method 2 runs "max_num_groupings" groupings, records the global best of each, and regroups '...
                'within the max and min per dimension of those bests.  It may not be necessary to use such a large '...
            	'value for "max_num_groupings."'])
            disp(['Currently, max_num_groupings = ', num2str(max_num_groupings), '.'])
            fprintf('\r') %Insert a carriage return before future outputs.
            auto_changes_made = true;
        end
    end
else %(i.e. if Reg_Method == 0)
    max_num_groupings = 1; %Automatically set "max_num_groupings" to 1 for case "Reg_Method" == 0.
                           %It is used only internally for filenames saved to in "reg_main.m"
                           %and was not set by the user for the standard case.
    if OnOff_NormR_stag_det
        disp(['Warning: You are running standard PSO with NormR stagnation detection and search termination. '...
        	'This is not a problem unless you intend to generate standard data for comparison, in which '...
        	'case it should not be used at all since it is not a standard feature.'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
end
if OnOff_MPSO
    if ~OnOff_GCPSO
        disp(['MPSO was designed to be used with GCPSO at its core.  '...
            'Mr. Evers''s PSO Research Toolbox allows for the '...
            'multi-start of other algorithms as well.  This message is '...
            'generated to be sure you are aware that you are utilizing '...
            'the multi-start concept with another algorithm at the core.'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
end
if OnOff_func_evals && (Reg_Method ~= 0) %if only FE's selected
    if max_FEs_over_all_groupings < max_FEs_per_grouping
        disp(['"max_FEs_over_all_groupings" is set lower than "max_FEs_per_grouping." '...
        	'If you are running standard PSO without regrouping, please set "max_FEs_per_grouping" to determine '...
        	'the # of function eval''s since "max_FEs_over_all_groupings" is considered irrelevant to the standard '...
        	'case.  If you are using PSO with regrouping, please set "max_FEs_per_grouping" '...
        	'to be the maximum # of function eval''s per grouping and "max_FEs_over_all_groupings" to be the '...
        	'maximum # of function evaluations over all groupings.'])
        fprintf('\r') %Insert a carriage return before future outputs.
        auto_changes_made = true;
    end
end
if OnOff_Tricias_NN_training
    if OnOff_func_evals
		OnOff_func_evals = false;
        	disp(['Since Tricia''s ANN training is designed to work with '...
                'iterations rather than function evaluations, switch "OnOff_func_evals" '...
                'has been de-activated automatically.  If you add compatibility with '...
                'function evaluations, please email george@georgeevers.org the updated '...
                'code for the benefit of the research community.'])
	        fprintf('\r') %Insert a carriage return before future outputs.
    end
    if OnOff_graphs && OnOff_graph_ObjFun_f_vs_2D
		OnOff_graph_ObjFun_f_vs_2D = false;
        	disp(['Since ANN training is being conducted instead of a benchmark, '...
                'switch "OnOff_graph_ObjFun_f_vs_2D" has been de-activated automatically.'])
	        fprintf('\r') %Insert a carriage return before future outputs.
    end
else %i.e. if ~OnOff_Tricias_NN_training
    if auto_changes_made == false
        disp('No automatic changes have been made.')
        fprintf('\r')
    end
end
clear auto_changes_made
    %Keep workspace organized by clearing this variable, which will not
        %be used again beyond this point.
Display_Settings