<commit_before>/***************************************************************************
   Copyright 2015 OSIsoft, LLC.
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 ***************************************************************************/

// Ajax request with kerberos authentication
var getAjax = function (url, method, callback) {
    $.ajax({
        url: encodeURI(url),
        method: method,
        success: callback,
        error: function (xhr) {
            console.log(xhr.responseText);
        },
        xhrFields: {
            withCredentials: true
        }
    });
}

function populateDropdown() {
    var sources_url = "https://localhost/piwebapi/search/sources";

    getAjax(sources_url, "GET", function (obj) {
        console.log(obj);
        console.log(obj.Items);
        try {
            for (index in obj.Items) {
                    var name = obj.Items[index].Name
                    console.log(name);
                    $('ul').append('
' + name + '
');
            }

            $('a').on('click', function () {
                $(".btn:first-child").text($(this).text());
                sourceChanged($(this).text());
            });
        }
        catch (e) {
            console.log("Exception caught: " + e);
        }

    });
}

function sourceChanged(source) {
    var query_url = "https://localhost/piwebapi/search/query?q=gas" + "&scope=" + source;

    getAjax(query_url, "GET", function (obj) {
        console.log(obj);
        console.log(obj.Items);
        console.log(obj.Items[0].Name);
        try {
            displayTable(obj, undefined);
            $(".btn-default").unbind("click");
            $(".btn-default").click( function () {
                buttonClicked($(this)[0].defaultValue, obj);
            });
        }
        catch (e) {
        }
    });
}

function buttonClicked(button_type, previous_query){
    console.log(button_type + " " + previous_query);

    var query_url = "";

    switch (button_type) {
        case "Next":
            query_url = previous_query.Links.Next;
            break;
        case "Previous":
            break;
        case "First":
            query_url = previous_query.Links.First;
            break;
        case "Last":
            query_url = previous_query.Links.Last;
            break;
    }

    console.log(query_url);
    query_url = (query_url.replace(/%3A/g, ":")).replace(/%5C/g, "\\");
    console.log(query_url);

    if (query_url != "") {
        getAjax(query_url, "GET", function (obj) {
            console.log(obj);
            try {
                displayTable(obj, undefined);

                //reset buttons to new query.
                $(".btn-default").unbind("click");
                $(".btn-default").click(function () {
                    buttonClicked($(this)[0].defaultValue, obj);
                    return false;
                });
            }
            catch (e) {
            }
        });
    }
}

function initializeTable() {
    $('#table-results tbody').remove()
};

function displayTable(data, page) {
    // Reset Table
    initializeTable();

    // Rebuild Table
    $('#table-results').append("
");

    for (index in data.Items) {
        var my_table = "
" +
            "" + data.Items[index].Name + "	" +
            "" + data.Items[index].Description + "	" +
            "" + data.Items[index].Score + "	" +
            "" + "TBD" + "	" +
            "
";
        $('#table-results tbody').append(my_table);
    }
    $('#table-results').append("
");
}

$(document).ready(function () {
    populateDropdown();     // get sources
    initializeTable();      // make sure table is cleared for initial dispaly
});
<commit_msg>Update index.js<commit_after>/***************************************************************************
   Copyright 2015 OSIsoft, LLC.
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 ***************************************************************************/
/********************************************************
 getAjax
 Helper function for handling CORS API requests with
 kerberos authentication via Ajax.

 NOTE: To successfully use CORS for API requests you
 need to set up the following in PI System Explorer.
 // //OSIsoft/PI WebAPI/YourPIWebAPIHost/SystemConfiguration
 and set CorsSupportsCredentials = true and
 set your Cors settings as appropriate.

 In addition this needs to be run from a web server for
 CORS to work properly. This was originally written as
 an ASP .NET Website and security was set up there.
********************************************************/
var getAjax = function (url, method, callback) {
    $.ajax({
        url: encodeURI(url),
        method: method,
        success: callback,
        error: function (xhr) {
            console.log(xhr.responseText);
        },
        xhrFields: {
            withCredentials: true
        }
    });
}

// Populates the dropdown menus with available sources on ready
function populateDropdown() {
    var sources_url = "https://localhost/piwebapi/search/sources";

    getAjax(sources_url, "GET", function (obj) {
        try {
            // on ASync response, populate the dropdown with returned sources.
            for (index in obj.Items) {
                    var name = obj.Items[index].Name
                    $('ul').append('
' + name + '
');
            }

            // On click, update button to selected source and signal a source change.
            $('a').on('click', function () {
                $(".btn:first-child").text($(this).text());
                sourceChanged($(this).text());
            });
        }
        catch (e) {
            console.log("Exception caught: " + e);
        }

    });
}

// On source change, resend the query to populate the table.
function sourceChanged(source) {
    var query_url = "https://localhost/piwebapi/search/query?q=gas" + "&scope=" + source;

    indexedSearchQuery(query_url);
}

// Used to reduce duplication.
// Calls the Ajax helper function with the passed query
// and updates the Webpage with the given results.
// Errors are logged to console.
function indexedSearchQuery(query) {
    if (query != "") {
        getAjax(query, "GET", function (obj) {
            try {
                // On response, update and log.
                displayTable(obj);
                updateButtons(obj);
                logErrors(obj.Errors);
            }
            catch (e) {
                Console.log("Exception caught in indexedSearchQuery: " + e);
            }
        });
    }
    else {
        console.log("Error: No query supplied to indexedSearchQuery.");
    }
}

// Used to wipe stale date from webpage.
function initializeTable() {
    $('#table-results tbody').remove()
};

// Called on response with
function displayTable(data) {
    // Reset Table
    initializeTable();

    // Rebuild Table
    $('#table-results').append("
");

    for (index in data.Items) {
        var my_table = "
" +
            "" + data.Items[index].Name + "	" +
            "" + data.Items[index].Description + "	" +
            "" + data.Items[index].Score + "	" +
            "
";
        $('#table-results tbody').append(my_table);
    }
    $('#table-results').append("
");
}

// Unbinds the click event on buttons and sets it to an updated json_obj
// based on last query.
function updateButtons(json_obj) {
    $(".btn-default").unbind("click");
    $(".btn-default").click(function () {
        buttonClicked($(this)[0].defaultValue, json_obj);
        return false;
    });
}

// Logs Errors in error_array to console.
function logErrors(error_array) {
    for (index in error_array) {
        console.log("Error #: " + error_array[index].ErrorCode);
        console.log("- Source: " + error_array[index].Source);
        console.log("- Message: " + error_array[index].Message);
    }
}

// Shim to implement previous page functionality.
function linkPrevious(next_link) {
    var previous_link = "";
    var next_page = 0;

    // grab the next page start index
    var start_index = next_link.substring((next_link.search(/&start=*/)), (next_link.length));
    previous_link = next_link.substring(0, (next_link.search(/&start=*/)));
    start_index = start_index.substring((start_index.search(/=/) + 1), start_index.length);

    // previous page is (next_link.start - (2 * count)). One step forward, 2 steps back.
    var start_field = Number(start_index) - (2 * (10));

    // If the start field is greater than 0, then there is a previous page,
    //otherwise leave alone as a link to first page.
    if (start_field >= 10) {
        previous_link += "&start=" + start_field;
    }

    return previous_link;
}

// On button click, see which button was pressed and perform the appropriate action.
function buttonClicked(button_type, previous_query){
    var query_url = "";

    switch (button_type) {
        case "Next":
            query_url = previous_query.Links.Next;
            break;
        case "Previous":
            query_url = linkPrevious(previous_query.Links.Next);
            break;
        case "First":
            query_url = previous_query.Links.First;
            break;
        case "Last":
            query_url = previous_query.Links.Last;
            break;
    }

    //replace on the supplied link to clean up the url
    query_url = decodeURIComponent(query_url);
    indexedSearchQuery(query_url);
}

// Main starting point of the code.
$(document).ready(function () {
    populateDropdown();     // get sources
    initializeTable();      // make sure table is cleared for initial dispaly
});
<|endoftext|>


<commit_before>var dateUtils = require("../src/utils/date-utils.js");
var assert = require("assert");
var _privateDateUtils = dateUtils._private;

describe('Verify generateShortMonths rotates months', function() {
    it('should rotate months with starting month being first', function() {
        const _months = _privateDateUtils.getMonths();

        for (var i=0; i<10; i++) {
            let shortMonths = dateUtils.generateShortMonths(i);
            assert.equal(shortMonths.length, 12);
            assert.equal(shortMonths[0], _months[i]);
        }
    });
});

describe('Verify getIntValAsString', function() {
    it('should prepend a 0 for single digit numbers', function() {
        for (var i=1; i<10; i++) {
            let valAsString = _privateDateUtils.getIntValAsString(i.toString());
            assert.equal(valAsString[0], '0');
            assert.equal(valAsString.length, 2);
        }
    });

    it('should not modify number if double digits', function() {
        for (var i=10; i<32; i++) {
            let valAsString = _privateDateUtils.getIntValAsString(i.toString());
            assert.equal(valAsString, i.toString());
        }
    });
});

describe('Verify generateDatesMonth', function() {
    it('should return an array with the correct number of items', function() {
        let year = 2015;
        const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
        const expected = {'01': 31, '02': 28, '03': 31, '04': 30, '05': 31, '06': 30, '07': 31, '08': 31, '09': 30, '10': 31, '11': 30, '12': 31};

        for (var month of months) {
            for (var i=1; i<32; i++) {
                let dates = _privateDateUtils.generateDatesMonth(year, month, i);
                if (dates.length == 0) {
                    assert.ok(expected[month] < 31);
                } else {
                    assert.equal(dates.length, Math.min(expected[month] - i + 1, expected[month]));
                }
            }
        }
    });
});

describe('Verify getMonthsAndYear', function() {
    it('should return an array with 11 elements', function() {
        let startingYear = 2014;

        for (var i=1; i<13; i++) {
            let months = _privateDateUtils.getMonthsAndYear(i, startingYear);
            assert.equal(months.length, 11);
        }
    });
});

describe('Verify getNextMonthAndYear', function() {
    it('should return the first month of next year', function() {
        let [nextMonth, nextYear] = _privateDateUtils.getNextMonthAndYear('12', '2014');
        assert.equal(nextMonth, '01');
        assert.equal(nextYear, '2015');
    });

    it('should return the next month and the same year', function() {
        const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];

        for (var i=0; i<months.length-1; i++) {
            let [nextMonth, nextYear] = _privateDateUtils.getNextMonthAndYear(months[i], '2014');
            assert.equal(nextMonth, months[i+1]);
            assert.equal(nextYear, '2014');
        }
    });
});

describe('Verify generateAllDates', function() {
    it('should return dates belonging to 12 different months in order', function() {
        let startingYear = '2014';
        let endYear = '2015';
        const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];

        for (let i=1; i<32; i++) {
            for (var month of months) {
                let startingDate = startingYear + '-' + month + '-' + _privateDateUtils.getIntValAsString(i.toString());
                let endDate = endYear + '-' + month + '-' + _privateDateUtils.getIntValAsString(i.toString());
                let dates = dateUtils.generateAllDates(startingDate, endDate);
                if (dates.length < 365) {
                    console.log(startingDate, endDate);
                    console.log(dates);
                }
                assert.ok(dates.length >= 365);
            }
        }
    });
});
<commit_msg>fix tests<commit_after>var dateUtils = require("../src/utils/date-utils.js");
var assert = require("assert");
var _privateDateUtils = dateUtils._private;

describe('Verify generateShortMonths rotates months', function() {
    it('should rotate months with starting month being first', function() {
        const _months = _privateDateUtils.getMonths();

        for (var i=0; i<10; i++) {
            let shortMonths = dateUtils.generateShortMonths(i);
            assert.equal(shortMonths.length, 12);
            assert.equal(shortMonths[0], _months[i]);
        }
    });
});

describe('Verify getIntValAsString', function() {
    it('should prepend a 0 for single digit numbers', function() {
        for (var i=1; i<10; i++) {
            let valAsString = _privateDateUtils.getIntValAsString(i.toString());
            assert.equal(valAsString[0], '0');
            assert.equal(valAsString.length, 2);
        }
    });

    it('should not modify number if double digits', function() {
        for (var i=10; i<32; i++) {
            let valAsString = _privateDateUtils.getIntValAsString(i.toString());
            assert.equal(valAsString, i.toString());
        }
    });
});

describe('Verify generateDatesMonth', function() {
    it('should return an array with the correct number of items', function() {
        let year = 2015;
        const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
        const expected = {'01': 31, '02': 28, '03': 31, '04': 30, '05': 31, '06': 30, '07': 31, '08': 31, '09': 30, '10': 31, '11': 30, '12': 31};

        for (var month of months) {
            for (var i=1; i<32; i++) {
                let dates = _privateDateUtils.generateDatesMonth(year, month, i);
                if (dates.length == 0) {
                    assert.ok(expected[month] < 31);
                } else {
                    assert.equal(dates.length, Math.min(expected[month] - i + 1, expected[month]));
                }
            }
        }
    });
});

describe('Verify getMonthsAndYear', function() {
    it('should return an array with 11 elements', function() {
        let startingYear = 2014;

        for (var i=1; i<13; i++) {
            let months = _privateDateUtils.getMonthsAndYear(i, startingYear);
            assert.equal(months.length, 11);
        }
    });
});

describe('Verify getNextMonthAndYear', function() {
    it('should return the first month of next year', function() {
        let [nextMonth, nextYear] = _privateDateUtils.getNextMonthAndYear('12', '2014');
        assert.equal(nextMonth, '01');
        assert.equal(nextYear, '2015');
    });

    it('should return the next month and the same year', function() {
        const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];

        for (var i=0; i<months.length-1; i++) {
            let [nextMonth, nextYear] = _privateDateUtils.getNextMonthAndYear(months[i], '2014');
            assert.equal(nextMonth, months[i+1]);
            assert.equal(nextYear, '2014');
        }
    });
});

describe('Verify generateAllDates', function() {
    it('should return dates belonging to 12 different months in order', function() {
        let startingYear = '2014';
        let endYear = '2015';
        const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];

        for (let i=1; i<32; i++) {
            for (var month of months) {
                if (month === '02' && i > 29) {
                    console.log('date not available');
                } else {
                    let startingDate = startingYear + '-' + month + '-' + _privateDateUtils.getIntValAsString(i.toString());
                    let endDate = endYear + '-' + month + '-' + _privateDateUtils.getIntValAsString(i.toString());
                    let dates = dateUtils.generateAllDates(startingDate, endDate);
                    assert.ok(dates.length === 365);
                }
            }
        }
    });
});
<|endoftext|>


<commit_before>const LOCALSTORAGE_KEY = 'githubGoals';

export const save = (data) => {
  console.log('Saving data to localStorage', data);
  localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(data));
};

export const load = () => {
  const data = localStorage.getItem(LOCALSTORAGE_KEY);
  const parsedData = JSON.parse(data);
  console.log('Retrieving data from localStorage', data, parsedData);
  return parsedData;
};
<commit_msg>Added function to reset localStorage<commit_after>const LOCALSTORAGE_KEY = 'githubGoals';

export const save = (data) => {
  console.log('Saving data to localStorage', data);
  localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(data));
};

export const load = () => {
  const data = localStorage.getItem(LOCALSTORAGE_KEY);
  const parsedData = JSON.parse(data);
  console.log('Retrieving data from localStorage', data, parsedData);
  return parsedData;
};

export const reset = () => {
  const data = localStorage.getItem(LOCALSTORAGE_KEY);
  const parsedData = JSON.parse(data);
  console.log('Clearing data from localStorage', data, parsedData);
  localStorage.removeItem(LOCALSTORAGE_KEY);
};
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {
  require('time-grunt')(grunt);
  require('jit-grunt')(grunt);

  grunt.loadNpmTasks('grunt-composer');

  var settings = {
    config: {
      src: ['grunt/*.js']
    }
  };
  grunt.initConfig(require('load-grunt-configs')(grunt, settings));

  grunt.registerTask('qa', ['phplint', 'phpcs', 'phpmd', 'phpcpd']);
  grunt.registerTask('test', ['phpunit']);
  grunt.registerTask('security', ['composer:outdated:outdated', 'security_checker']);

<% if (project.type === 'project') { -%>
  grunt.registerTask('serve', function() {
    grunt.task.run([<% if (!control.homestead) { -%>'php', <% } -%>'browserSync', 'watch']);

  });
<% } -%>

  grunt.task.registerTask('build', 'Project build', function() {
    grunt.log.writeln('Task ready to be implemented');
  });

  grunt.registerTask('default', ['qa', 'test']);
};
<commit_msg>only direct requirements<commit_after>'use strict';

module.exports = function(grunt) {
  require('time-grunt')(grunt);
  require('jit-grunt')(grunt);

  grunt.loadNpmTasks('grunt-composer');

  var settings = {
    config: {
      src: ['grunt/*.js']
    }
  };
  grunt.initConfig(require('load-grunt-configs')(grunt, settings));

  grunt.registerTask('qa', ['phplint', 'phpcs', 'phpmd', 'phpcpd']);
  grunt.registerTask('test', ['phpunit']);
  grunt.registerTask('security', ['composer:outdated:direct', 'security_checker']);

<% if (project.type === 'project') { -%>
  grunt.registerTask('serve', function() {
    grunt.task.run([<% if (!control.homestead) { -%>'php', <% } -%>'browserSync', 'watch']);

  });
<% } -%>

  grunt.task.registerTask('build', 'Project build', function() {
    grunt.log.writeln('Task ready to be implemented');
  });

  grunt.registerTask('default', ['qa', 'test']);
};
<|endoftext|>


<commit_before>/*======================================================
************   Notifications   ************
======================================================*/
var _tempNotificationElement;
app.addNotification = function (params) {
    if (!params) return;

    if (typeof params.media === 'undefined') params.media = app.params.notificationMedia;
    if (typeof params.title === 'undefined') params.title = app.params.notificationTitle;
    if (typeof params.subtitle === 'undefined') params.subtitle = app.params.notificationSubtitle;
    if (typeof params.closeIcon === 'undefined') params.closeIcon = app.params.notificationCloseIcon;
    if (typeof params.hold === 'undefined') params.hold = app.params.notificationHold;
    if (typeof params.closeOnClick === 'undefined') params.closeOnClick = app.params.notificationCloseOnClick;

    if (!_tempNotificationElement) _tempNotificationElement = document.createElement('div');

    var container = $('.notifications');
    if (container.length === 0) {
        $('body').append('

');
        container = $('.notifications');
    }
    var list = container.children('ul');

    var itemHTML;
    if (params.custom) {
        itemHTML = '
' + params.custom + '
';
    }
    else {
        itemHTML = '

' +
                        (params.media ?
                        '
' +
                            params.media +
                        '
' : '') +
                        '
' +
                            '
' +
                                (params.title ? '
' + params.title + '
' : '') +
                                (params.closeIcon ? '

' : '') +
                            '
' +
                            (params.subtitle ? '
' + params.subtitle + '
' : '') +
                            (params.message ? '
' + params.message + '
' : '') +
                        '
' +
                    '

';
    }
    _tempNotificationElement.innerHTML = itemHTML;

    var item = $(_tempNotificationElement).children();

    item.on('click', function (e) {
        var close = false;
        if ($(e.target).is('.close-notification') || $(e.target).parents('.close-notification').length > 0) {
            close = true;
        }
        else {
            if (params.onClick) params.onClick(e, item[0]);
            if (params.closeOnClick) close = true;
        }
        if (close) app.closeNotification(item[0]);
    });
    if (params.onClose) {
        item.data('f7NotificationOnClose', function () {
            params.onClose(item[0]);
        });
    }
    if (params.additionalClass) {
        item.addClass(params.additionalClass);
    }
    if (params.hold) {
        setTimeout(function () {
            if (item.length > 0) app.closeNotification(item[0]);
        }, params.hold);
    }

    list.prepend(item[0]);
    container.show();

    var itemHeight = item.height();
    item.css('marginTop', -itemHeight + 'px');
    item.transition(0);

    var clientLeft = item[0].clientLeft;
    item.transition('');
    item.css('marginTop', '0px');

    container.transform('translate3d(0, 0,0)');
    item.removeClass('notification-hidden');

    return item[0];
};
app.closeNotification = function (item) {
    item = $(item);
    if (item.length === 0) return;
    if (item.hasClass('notification-item-removing')) return;
    var container = $('.notifications');

    var itemHeight = item.height();
    item.css('height', itemHeight + 'px').transition(0);
    var clientLeft = item[0].clientLeft;

    item.css('height', '0px').transition('').addClass('notification-item-removing');
    if (item.data('f7NotificationOnClose')) item.data('f7NotificationOnClose')();

    if (container.find('.notification-item:not(.notification-item-removing)').length === 0) {
        container.transform('');
    }

    item.addClass('notification-hidden').transitionEnd(function () {
        item.remove();
        if (container.find('.notification-item').length === 0) {
            container.hide();
        }
    });
};<commit_msg>Change height to outerHeight<commit_after>/*======================================================
************   Notifications   ************
======================================================*/
var _tempNotificationElement;
app.addNotification = function (params) {
    if (!params) return;

    if (typeof params.media === 'undefined') params.media = app.params.notificationMedia;
    if (typeof params.title === 'undefined') params.title = app.params.notificationTitle;
    if (typeof params.subtitle === 'undefined') params.subtitle = app.params.notificationSubtitle;
    if (typeof params.closeIcon === 'undefined') params.closeIcon = app.params.notificationCloseIcon;
    if (typeof params.hold === 'undefined') params.hold = app.params.notificationHold;
    if (typeof params.closeOnClick === 'undefined') params.closeOnClick = app.params.notificationCloseOnClick;

    if (!_tempNotificationElement) _tempNotificationElement = document.createElement('div');

    var container = $('.notifications');
    if (container.length === 0) {
        $('body').append('

');
        container = $('.notifications');
    }
    var list = container.children('ul');

    var itemHTML;
    if (params.custom) {
        itemHTML = '
' + params.custom + '
';
    }
    else {
        itemHTML = '

' +
                        (params.media ?
                        '
' +
                            params.media +
                        '
' : '') +
                        '
' +
                            '
' +
                                (params.title ? '
' + params.title + '
' : '') +
                                (params.closeIcon ? '

' : '') +
                            '
' +
                            (params.subtitle ? '
' + params.subtitle + '
' : '') +
                            (params.message ? '
' + params.message + '
' : '') +
                        '
' +
                    '

';
    }
    _tempNotificationElement.innerHTML = itemHTML;

    var item = $(_tempNotificationElement).children();

    item.on('click', function (e) {
        var close = false;
        if ($(e.target).is('.close-notification') || $(e.target).parents('.close-notification').length > 0) {
            close = true;
        }
        else {
            if (params.onClick) params.onClick(e, item[0]);
            if (params.closeOnClick) close = true;
        }
        if (close) app.closeNotification(item[0]);
    });
    if (params.onClose) {
        item.data('f7NotificationOnClose', function () {
            params.onClose(item[0]);
        });
    }
    if (params.additionalClass) {
        item.addClass(params.additionalClass);
    }
    if (params.hold) {
        setTimeout(function () {
            if (item.length > 0) app.closeNotification(item[0]);
        }, params.hold);
    }

    list.prepend(item[0]);
    container.show();

    var itemHeight = item.outerHeight();
    item.css('marginTop', -itemHeight + 'px');
    item.transition(0);

    var clientLeft = item[0].clientLeft;
    item.transition('');
    item.css('marginTop', '0px');

    container.transform('translate3d(0, 0,0)');
    item.removeClass('notification-hidden');

    return item[0];
};
app.closeNotification = function (item) {
    item = $(item);
    if (item.length === 0) return;
    if (item.hasClass('notification-item-removing')) return;
    var container = $('.notifications');

    var itemHeight = item.outerHeight();
    item.css('height', itemHeight + 'px').transition(0);
    var clientLeft = item[0].clientLeft;

    item.css('height', '0px').transition('').addClass('notification-item-removing');
    if (item.data('f7NotificationOnClose')) item.data('f7NotificationOnClose')();

    if (container.find('.notification-item:not(.notification-item-removing)').length === 0) {
        container.transform('');
    }

    item.addClass('notification-hidden').transitionEnd(function () {
        item.remove();
        if (container.find('.notification-item').length === 0) {
            container.hide();
        }
    });
};<|endoftext|>


<commit_before>var MAX_DEVICE_NAME_LENGTH = 16;

var deviceCount = localStorage.getItem("deviceCount");
if (!deviceCount) {
    deviceCount = 0;
}

var devices = JSON.parse(localStorage.getItem("devices"));
if (!devices) {
    devices = new Array();
}

var serverAddress = localStorage.getItem("serverAddress");
if (!serverAddress) {
    serverAddress = "";
}

var serverPort = localStorage.getItem("serverPort");
if (!serverPort) {
    serverPort = "8000";
}

var prefixForGet = "http://" + serverAddress + ":" + serverPort;
console.log("prefixForGet is: " + prefixForGet);

// Set callback for the app ready event
Pebble.addEventListener("ready", function(e) {
    console.log("connect!" + e.ready);
    console.log(e.type);
});

Pebble.addEventListener("showConfiguration", function() {
    console.log("showing configuration");
    Pebble.openURL('https://s3.amazonaws.com/IndigoRemote/settings.html?serverAddress=' + serverAddress + '&serverPort=' + serverPort);
});

Pebble.addEventListener("webviewclosed", function(e) {
    console.log("configuration closed");
    // webview closed
    var options = JSON.parse(decodeURIComponent(e.response));
    console.log("Options = " + JSON.stringify(options));
    localStorage.setItem("serverAddress", options.serverAddress);
    serverAddress = options.serverAddress;
    localStorage.setItem("serverPort", options.serverPort);
    serverPort = options.serverPort;
});

//var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
//
//function btoa (input) {
//    for (
//         // initialize result and counter
//         var block, charCode, idx = 0, map = chars, output = '';
//         // if the next input index does not exist:
//         //   change the mapping table to "="
//         //   check if d has no fractional digits
//         input.charAt(idx | 0) || (map = '=', idx % 1);
//         // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
//         output += map.charAt(63 & block >> 8 - idx % 1 * 8)
//         ) {
//        charCode = input.charCodeAt(idx += 3/4);
//        if (charCode > 0xFF) {
//            console.log("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
//        }
//        block = block << 8 | charCode;
//    }
//    return output;
//}

// Basic sleep function based on ms.
// BUSY WAITS!!!
// We need this because otherwise we overwhelm Pebble with AppMessages and
// it drops them all.  Using setTimeout just makes everything async and out
// of order, without really solving the problem.
function busyWaitSleep(ms) {
    var unixtime_ms = new Date().getTime();
    while(new Date().getTime() < unixtime_ms + ms) {}
}

function sendDeviceCount(deviceCount) {
    Pebble.sendAppMessage({"device_count": deviceCount},
        function(e){
            console.log("Sent device_count message. transactionId=" + e.data.transactionId);
        },
        function(e){
            console.log("Unable to send device_count message. transactionId=" + e.data.transactionId);
            setTimeout(sendDeviceCount(deviceCount), 400);
//            busyWaitSleep(400);
//            sendDeviceCount(deviceCount)
        }
    );
}

function sendDeviceInfo(deviceNumber, deviceInfo) {
    Pebble.sendAppMessage({"device": 1,
                          "device_number": deviceNumber,
                          "device_name": deviceInfo.device_name,
                          "device_on": deviceInfo.device_on
                          },
        function(e){
            console.log("Sent device message. device=" + deviceInfo.name + " transactionId=" + e.data.transactionId);
        },
        function(e){
            console.log("Unable to send device message. device=" + deviceInfo.name + " transactionId=" + e.data.transactionId);
            setTimeout(sendDeviceInfo(deviceNumber, deviceInfo), 400);
//            busyWaitSleep(400);
//            sendDeviceInfo(deviceNumber, deviceInfo);
        }
    );
}

function getDevices() {
    var req = new XMLHttpRequest();
    // Get the list of all devices known to the Indigo Server
    req.open('GET', prefixForGet + "/devices.json", true);  // `true` makes the request asynchronous
    // Indigo uses Digest authentication, so this won't work:
    //    req.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password))
    // Instead, see http://stackoverflow.com/questions/10937890/javascript-digest-manually-authentication?rq=1
    // TODO: Support Digest Authentication
    req.onload = function(e) {
        if(req.status == 200) {
            var response = JSON.parse(req.responseText);
            var price;
            if (response.length > 0) {
                // Pare down to just devices that have typeSupportsOnOff: true
                deviceCount = 0
                devices = new Array();

                for (var i = 0, j = response.length; i < j; i += 1) {
                    var deviceRequest = new XMLHttpRequest();
                    deviceRequest.open('GET', prefixForGet + "/devices/" + response[i].nameURLEncoded + ".json", false);  // `false` makes the request synchronous
                    deviceRequest.send(null);
                    if( deviceRequest.status == 200) {
                        // Track device information
                        var deviceInfo = JSON.parse(deviceRequest.responseText);
                        if (deviceInfo.typeSupportsOnOff) {
                            devices[deviceCount] =
                            {
                                "device_name": deviceInfo.name.substring(0, MAX_DEVICE_NAME_LENGTH),
                                "device_url_name": response[i].nameURLEncoded,
                                "device_on": deviceInfo.isOn
                            };
                            deviceCount++;
                        }
                    }
                    else {
                        console.log("Request for device " + response[i].nameURLEncoded + " returned error code " + deviceRequest.status.toString());
                    }
                }
                localStorage.setItem("deviceCount", deviceCount);
                localStorage.setItem("devices", JSON.stringify(devices));

                // Need to pace ourselves so we don't overwhelm Pebble
                var timeout = 400;

                // We've got the total count of controllable devices, so send it out
                sendDeviceCount(deviceCount);
//                busyWaitSleep(timeout);

                // Now send out the information for each device
                for (var i = 0, j = devices.length; i < j; i += 1) {
                    setTimeout(sendDeviceInfo(i, devices[i], timeout));
//                    sendDeviceInfo(i, devices[i]);
//                    busyWaitSleep(timeout);
                }
            }
            else {
                sendDeviceCount(0);
            }
        } else {
            console.log("Request returned error code " + req.status.toString());
            sendDeviceCount(0);
        }
    }
    req.send(null);
}

function toggleDeviceOnOff(deviceNumber) {
    var req = new XMLHttpRequest();
    // TODO: Support Digest Authentication
    req.open('GET', prefixForGet + "/devices/" + devices[deviceNumber].device_url_name + ".json?toggle=1&_method=put", true);  // `true` makes the request asynchronous
    req.onload = function(e) {
        if (req.readyState == 4) {
            // 200 - HTTP OK
            if(req.status == 200) {
                var deviceInfo = JSON.parse(req.responseText);
                devices[deviceNumber].device_on = deviceInfo.isOn;
                sendDeviceInfo(deviceNumber, devices[deviceNumber]);
                localStorage.setItem("devices", JSON.stringify(devices));
            } else {
                console.log("Request returned error code " + req.status.toString());
            }
        }
    }
    req.send(null);
}

// Set callback for appmessage events
Pebble.addEventListener("appmessage", function(e) {
    if (e.payload.get_devices) {
        console.log("get_devices flag in payload");
        getDevices();
    }
    if (e.payload.device_toggle_on_off) {
        console.log("device_toggle_on_off flag in payload");
        toggleDeviceOnOff(e.payload.device_toggle_on_off);
    }
});<commit_msg>Removed busy waits<commit_after>var MAX_DEVICE_NAME_LENGTH = 16;

var deviceCount = localStorage.getItem("deviceCount");
if (!deviceCount) {
    deviceCount = 0;
}

var devices = JSON.parse(localStorage.getItem("devices"));
if (!devices) {
    devices = new Array();
}

var serverAddress = localStorage.getItem("serverAddress");
if (!serverAddress) {
    serverAddress = "";
}

var serverPort = localStorage.getItem("serverPort");
if (!serverPort) {
    serverPort = "8000";
}

var prefixForGet = "http://" + serverAddress + ":" + serverPort;
console.log("prefixForGet is: " + prefixForGet);

// Set callback for the app ready event
Pebble.addEventListener("ready", function(e) {
    console.log("connect!" + e.ready);
    console.log(e.type);
});

Pebble.addEventListener("showConfiguration", function() {
    console.log("showing configuration");
    Pebble.openURL('https://s3.amazonaws.com/IndigoRemote/settings.html?serverAddress=' + serverAddress + '&serverPort=' + serverPort);
});

Pebble.addEventListener("webviewclosed", function(e) {
    console.log("configuration closed");
    // webview closed
    var options = JSON.parse(decodeURIComponent(e.response));
    console.log("Options = " + JSON.stringify(options));
    localStorage.setItem("serverAddress", options.serverAddress);
    serverAddress = options.serverAddress;
    localStorage.setItem("serverPort", options.serverPort);
    serverPort = options.serverPort;
});

//var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
//
//function btoa (input) {
//    for (
//         // initialize result and counter
//         var block, charCode, idx = 0, map = chars, output = '';
//         // if the next input index does not exist:
//         //   change the mapping table to "="
//         //   check if d has no fractional digits
//         input.charAt(idx | 0) || (map = '=', idx % 1);
//         // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
//         output += map.charAt(63 & block >> 8 - idx % 1 * 8)
//         ) {
//        charCode = input.charCodeAt(idx += 3/4);
//        if (charCode > 0xFF) {
//            console.log("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
//        }
//        block = block << 8 | charCode;
//    }
//    return output;
//}

function sendDeviceCount(deviceCount) {
    Pebble.sendAppMessage({"device_count": deviceCount},
        function(e){
            console.log("Sent device_count message. transactionId=" + e.data.transactionId);
        },
        function(e){
            console.log("Unable to send device_count message. transactionId=" + e.data.transactionId);
            setTimeout(sendDeviceCount(deviceCount), 400);
        }
    );
}

function sendDeviceInfo(deviceNumber, deviceInfo) {
    Pebble.sendAppMessage({"device": 1,
                          "device_number": deviceNumber,
                          "device_name": deviceInfo.device_name,
                          "device_on": deviceInfo.device_on
                          },
        function(e){
            console.log("Sent device message. device=" + deviceInfo.name + " transactionId=" + e.data.transactionId);
        },
        function(e){
            console.log("Unable to send device message. device=" + deviceInfo.name + " transactionId=" + e.data.transactionId);
            setTimeout(sendDeviceInfo(deviceNumber, deviceInfo), 400);
        }
    );
}

function getDevices() {
    var req = new XMLHttpRequest();
    // Get the list of all devices known to the Indigo Server
    req.open('GET', prefixForGet + "/devices.json", true);  // `true` makes the request asynchronous
    // Indigo uses Digest authentication, so this won't work:
    //    req.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password))
    // Instead, see http://stackoverflow.com/questions/10937890/javascript-digest-manually-authentication?rq=1
    // TODO: Support Digest Authentication
    req.onload = function(e) {
        if(req.status == 200) {
            var response = JSON.parse(req.responseText);
            var price;
            if (response.length > 0) {
                // Pare down to just devices that have typeSupportsOnOff: true
                deviceCount = 0
                devices = new Array();

                for (var i = 0, j = response.length; i < j; i += 1) {
                    var deviceRequest = new XMLHttpRequest();
                    deviceRequest.open('GET', prefixForGet + "/devices/" + response[i].nameURLEncoded + ".json", false);  // `false` makes the request synchronous
                    deviceRequest.send(null);
                    if( deviceRequest.status == 200) {
                        // Track device information
                        var deviceInfo = JSON.parse(deviceRequest.responseText);
                        if (deviceInfo.typeSupportsOnOff) {
                            devices[deviceCount] =
                            {
                                "device_name": deviceInfo.name.substring(0, MAX_DEVICE_NAME_LENGTH),
                                "device_url_name": response[i].nameURLEncoded,
                                "device_on": deviceInfo.isOn
                            };
                            deviceCount++;
                        }
                    }
                    else {
                        console.log("Request for device " + response[i].nameURLEncoded + " returned error code " + deviceRequest.status.toString());
                    }
                }
                localStorage.setItem("deviceCount", deviceCount);
                localStorage.setItem("devices", JSON.stringify(devices));

                // Need to pace ourselves so we don't overwhelm Pebble
                var timeout = 400;

                // We've got the total count of controllable devices, so send it out
                sendDeviceCount(deviceCount);

                // Now send out the information for each device
                for (var i = 0, j = devices.length; i < j; i += 1) {
                    setTimeout(sendDeviceInfo(i, devices[i], timeout));
                }
            }
            else {
                sendDeviceCount(0);
            }
        } else {
            console.log("Request returned error code " + req.status.toString());
            sendDeviceCount(0);
        }
    }
    req.send(null);
}

function toggleDeviceOnOff(deviceNumber) {
    var req = new XMLHttpRequest();
    // TODO: Support Digest Authentication
    req.open('GET', prefixForGet + "/devices/" + devices[deviceNumber].device_url_name + ".json?toggle=1&_method=put", true);  // `true` makes the request asynchronous
    req.onload = function(e) {
        if (req.readyState == 4) {
            // 200 - HTTP OK
            if(req.status == 200) {
                var deviceInfo = JSON.parse(req.responseText);
                devices[deviceNumber].device_on = deviceInfo.isOn;
                sendDeviceInfo(deviceNumber, devices[deviceNumber]);
                localStorage.setItem("devices", JSON.stringify(devices));
            } else {
                console.log("Request returned error code " + req.status.toString());
            }
        }
    }
    req.send(null);
}

// Set callback for appmessage events
Pebble.addEventListener("appmessage", function(e) {
    if (e.payload.get_devices) {
        console.log("get_devices flag in payload");
        getDevices();
    }
    if (e.payload.device_toggle_on_off) {
        console.log("device_toggle_on_off flag in payload");
        toggleDeviceOnOff(e.payload.device_toggle_on_off);
    }
});<|endoftext|>


<commit_before>function unpack_data (data, out) {
    var teams = {};
    var players = {};
    data.team.forEach(function (team) {
        teams[team.team_id] = team;
        var playerList = team.player || team.squad;
        playerList.forEach(function (player) {
            players[player.player_id] = player;
        });
    });

    var match_status = data.match.match_status || "complete";

    console.log("match status: "+match_status);

    switch (match_status) {
        case "dormant":
            out.score = data.match.team1_filename+" v "+data.match.team2_filename;
            out.lead = "Match starts in "+data.match.match_clock;

            if (data.match.toss_decision && data.match.toss_decision !== "") {
                out.striker_name = teams[data.match.toss_winner_team_id].team_short_name+" won toss,";
                out.nonstriker_name = "will "+data.match.toss_decision_name;
            }
            break;

        case "complete": {
            out.score = data.match.team1_filename+" v "+data.match.team2_filename;

            if (data.match.winner_team_id == "0") {
                out.striker_name = "Match drawn";
            }
            else {
                out.striker_name = teams[data.match.winner_team_id].team_short_name+" won by";
                if (data.match.amount_name === "innings") {
                    out.nonstriker_name = "innings and "+data.match.amount+" runs";
                }
                else {
                    out.nonstriker_name = data.match.amount+" "+data.match.amount_name;
                }
            }
            break;
        }

        case "current": {
            var innings = data.live.innings;

            out.score = [
                teams[innings.batting_team_id].team_filename + " " + innings.runs,
                (innings.wickets < 10) ? "/"+innings.wickets : "",
                ((innings.event && innings.event == "declared") ? "d" : "")
            ].join('');

            out.overs = innings.overs;

            if (+data.match.scheduled_overs > 0) {
                switch (+innings.innings_number) {
                    case 1:
                        out.lead = "Run rate: "+innings.run_rate;
                        break;
                    default:
                        out.lead =
                            "Need "+(1-innings.lead)+" in "+
                            (innings.remaining_overs <= 10.0 ? innings.remaining_balls+" b" : innings.remaining_overs+" ov");
                        break;
                }
            }
            else {
                switch (+innings.innings_number) {
                    case 1:
                        out.lead = "First innings";
                        break;
                    case 4:
                        out.lead = "Target "+(innings.target);
                        break;
                    default:
                        out.lead =
                            innings.lead < 0 ? "Trail by "+(-innings.lead) :
                            innings.lead > 0 ? "Lead by "+innings.lead :
                                            "Scores level";
                }
            }

            var striker = data.live.batting.filter(function (player) { return player.live_current_name == "striker"; })[0];
            var nonstriker = data.live.batting.filter(function (player) { return player.live_current_name == "non-striker"; })[0];

            if (!striker) {
                striker = nonstriker;
                nonstriker = null;
            }

            if (striker) {
                var striker_name = players[striker.player_id].card_short;
                if (striker_name.length > 10) striker_name = players[striker.player_id].popular_name;
                out.striker_name = striker_name + (nonstriker ? "*" : "");
                out.striker_stats = striker.runs+" ("+striker.balls_faced+")";
            }

            if (nonstriker) {
                var nonstriker_name = players[nonstriker.player_id].card_short;
                if (nonstriker_name.length > 10) nonstriker_name = players[nonstriker.player_id].popular_name;
                out.nonstriker_name = nonstriker_name;
                out.nonstriker_stats = nonstriker.runs+" ("+nonstriker.balls_faced+")";
            }

            var bowler = data.live.bowling.filter(function (player) { return player.live_current_name == "current bowler"; })[0];
            if (bowler) {
                var bowler_name = players[bowler.player_id].card_short;
                if (bowler_name.length > 10) bowler_name = players[bowler.player_id].popular_name;
                out.bowler_name = bowler_name;
                out.bowler_stats = bowler.overs+"-"+bowler.maidens+"-"+bowler.conceded+"-"+bowler.wickets;
            }

            break;
        }
    }
}

function new_out () {
    var out = {
        "score":"",
        "overs":"",
        "lead":"",
        "striker_name":"",
        "striker_stats":"",
        "nonstriker_name":"",
        "nonstriker_stats":"",
        "bowler_name":"",
        "bowler_stats":""
    };
    return out;
}

function update () {
    var out = new_out();
    var matchId = localStorage.getItem("matchId");
    if (!matchId) {
        out.striker_name = "No match selected";
        out.nonstriker_name = "in config.";
        Pebble.sendAppMessage(out);
        return;
    }
    var req = new XMLHttpRequest();
    req.open('GET', "http://www.espncricinfo.com/ci/engine/match/"+matchId+".json");
    req.onload = function(e) {
        if (req.readyState == 4) {
            if(req.status == 200) {
                console.log("got new data, updating");

                var data = JSON.parse(req.responseText);
                if (data) {
                    unpack_data(data, out);
                    console.log(JSON.stringify(out));
                    Pebble.sendAppMessage(out);
                }

            } else {
                console.log("Error");
            }
        }
    };
    req.send(null);
}

Pebble.addEventListener("ready", function (e) {
    console.log("connected, doing first update");
    update();
});

Pebble.addEventListener("appmessage", function (e) {
    console.log("tick, doing update");
    update();
});

Pebble.addEventListener("showConfiguration", function (e) {
    console.log("config requested");
    Pebble.openURL("http://eatenbyagrue.org/a/sixfour.psgi");
});

Pebble.addEventListener("webviewclosed", function (e) {
    console.log("config closed, response: "+e.response);
    if (e.response !== "CANCELLED") {
        localStorage.setItem("matchId", e.response);
        update();
    }
});
<commit_msg>only use the popular name if its available<commit_after>function unpack_data (data, out) {
    var teams = {};
    var players = {};
    data.team.forEach(function (team) {
        teams[team.team_id] = team;
        var playerList = team.player || team.squad;
        playerList.forEach(function (player) {
            players[player.player_id] = player;
        });
    });

    var match_status = data.match.match_status || "complete";

    console.log("match status: "+match_status);

    switch (match_status) {
        case "dormant":
            out.score = data.match.team1_filename+" v "+data.match.team2_filename;
            out.lead = "Match starts in "+data.match.match_clock;

            if (data.match.toss_decision && data.match.toss_decision !== "") {
                out.striker_name = teams[data.match.toss_winner_team_id].team_short_name+" won toss,";
                out.nonstriker_name = "will "+data.match.toss_decision_name;
            }
            break;

        case "complete": {
            out.score = data.match.team1_filename+" v "+data.match.team2_filename;

            if (data.match.winner_team_id == "0") {
                out.striker_name = "Match drawn";
            }
            else {
                out.striker_name = teams[data.match.winner_team_id].team_short_name+" won by";
                if (data.match.amount_name === "innings") {
                    out.nonstriker_name = "innings and "+data.match.amount+" runs";
                }
                else {
                    out.nonstriker_name = data.match.amount+" "+data.match.amount_name;
                }
            }
            break;
        }

        case "current": {
            var innings = data.live.innings;

            out.score = [
                teams[innings.batting_team_id].team_filename + " " + innings.runs,
                (innings.wickets < 10) ? "/"+innings.wickets : "",
                ((innings.event && innings.event == "declared") ? "d" : "")
            ].join('');

            out.overs = innings.overs;

            if (+data.match.scheduled_overs > 0) {
                switch (+innings.innings_number) {
                    case 1:
                        out.lead = "Run rate: "+innings.run_rate;
                        break;
                    default:
                        out.lead =
                            "Need "+(1-innings.lead)+" in "+
                            (innings.remaining_overs <= 10.0 ? innings.remaining_balls+" b" : innings.remaining_overs+" ov");
                        break;
                }
            }
            else {
                switch (+innings.innings_number) {
                    case 1:
                        out.lead = "First innings";
                        break;
                    case 4:
                        out.lead = "Target "+(innings.target);
                        break;
                    default:
                        out.lead =
                            innings.lead < 0 ? "Trail by "+(-innings.lead) :
                            innings.lead > 0 ? "Lead by "+innings.lead :
                                            "Scores level";
                }
            }

            var striker = data.live.batting.filter(function (player) { return player.live_current_name == "striker"; })[0];
            var nonstriker = data.live.batting.filter(function (player) { return player.live_current_name == "non-striker"; })[0];

            if (!striker) {
                striker = nonstriker;
                nonstriker = null;
            }

            if (striker) {
                var striker_name = players[striker.player_id].card_short;
                if (striker_name.length > 10 && players[striker.player_id].popular_name.length > 0)
                    striker_name = players[striker.player_id].popular_name;
                out.striker_name = striker_name + (nonstriker ? "*" : "");
                out.striker_stats = striker.runs+" ("+striker.balls_faced+")";
            }

            if (nonstriker) {
                var nonstriker_name = players[nonstriker.player_id].card_short;
                if (nonstriker_name.length > 10 && players[nonstriker.player_id].popular_name.length > 0)
                    nonstriker_name = players[nonstriker.player_id].popular_name;
                out.nonstriker_name = nonstriker_name;
                out.nonstriker_stats = nonstriker.runs+" ("+nonstriker.balls_faced+")";
            }

            var bowler = data.live.bowling.filter(function (player) { return player.live_current_name == "current bowler"; })[0];
            if (bowler) {
                var bowler_name = players[bowler.player_id].card_short;
                if (bowler_name.length > 10) bowler_name = players[bowler.player_id].popular_name;
                out.bowler_name = bowler_name;
                out.bowler_stats = bowler.overs+"-"+bowler.maidens+"-"+bowler.conceded+"-"+bowler.wickets;
            }

            break;
        }
    }
}

function new_out () {
    var out = {
        "score":"",
        "overs":"",
        "lead":"",
        "striker_name":"",
        "striker_stats":"",
        "nonstriker_name":"",
        "nonstriker_stats":"",
        "bowler_name":"",
        "bowler_stats":""
    };
    return out;
}

function update () {
    var out = new_out();
    var matchId = localStorage.getItem("matchId");
    if (!matchId) {
        out.striker_name = "No match selected";
        out.nonstriker_name = "in config.";
        Pebble.sendAppMessage(out);
        return;
    }
    var req = new XMLHttpRequest();
    req.open('GET', "http://www.espncricinfo.com/ci/engine/match/"+matchId+".json");
    req.onload = function(e) {
        if (req.readyState == 4) {
            if(req.status == 200) {
                console.log("got new data, updating");

                var data = JSON.parse(req.responseText);
                if (data) {
                    unpack_data(data, out);
                    console.log(JSON.stringify(out));
                    Pebble.sendAppMessage(out);
                }

            } else {
                console.log("Error");
            }
        }
    };
    req.send(null);
}

Pebble.addEventListener("ready", function (e) {
    console.log("connected, doing first update");
    update();
});

Pebble.addEventListener("appmessage", function (e) {
    console.log("tick, doing update");
    update();
});

Pebble.addEventListener("showConfiguration", function (e) {
    console.log("config requested");
    Pebble.openURL("http://eatenbyagrue.org/a/sixfour.psgi");
});

Pebble.addEventListener("webviewclosed", function (e) {
    console.log("config closed, response: "+e.response);
    if (e.response !== "CANCELLED") {
        localStorage.setItem("matchId", e.response);
        update();
    }
});
<|endoftext|>


<commit_before>console.log('Started', self);
self.addEventListener('install', function(event) {
    self.skipWaiting();
    console.log('Installed', event);
});
self.addEventListener('activate', function(event) {
    console.log('Activated', event);
});
self.addEventListener('push', function(event) {
    if (event.data) {
        var json = event.data.json();
        self.registration.showNotification(json.title, json);
    }
});
self.addEventListener('notificationclick', function(event) {
    console.log('Notification click: tag ', event.notification.tag);
    event.notification.close();
    if (event.action === 'record-pendant') {
        var url = 'https://glassycollections.com/';
        event.waitUntil(clients.matchAll({
                includeUncontrolled: true,
                type: 'window'
            }).then(
            function(activeClients) {
                if (activeClients.length > 0) {
                    activeClients[0].navigate(url);
                    activeClients[0].focus();
                } else {
                    clients.openWindow(url);
                }
            })
        );
    }
});
<commit_msg>Make record-pendant the default notification action. Prod testing is great :sadnerd:<commit_after>console.log('Started', self);
self.addEventListener('install', function(event) {
    self.skipWaiting();
    console.log('Installed', event);
});
self.addEventListener('activate', function(event) {
    console.log('Activated', event);
});
self.addEventListener('push', function(event) {
    if (event.data) {
        var json = event.data.json();
        self.registration.showNotification(json.title, json);
    }
});
self.addEventListener('notificationclick', function(event) {
    console.log('Notification click: tag ', event.notification.tag);
    event.notification.close();

    var action = event.action || 'record-pendant';

    if (action === 'record-pendant') {
        var url = 'https://glassycollections.com/';
        event.waitUntil(clients.matchAll({
                includeUncontrolled: true,
                type: 'window'
            }).then(
            function(activeClients) {
                if (activeClients.length > 0) {
                    activeClients[0].navigate(url);
                    activeClients[0].focus();
                } else {
                    clients.openWindow(url);
                }
            })
        );
    }
});
<|endoftext|>


<commit_before>import Morph from "./Morph.js"

import d3 from 'src/external/d3.v4.js';

import { Graph } from 'src/client/triples/triples.js';
import * as drawTools from 'src/client/triples/drawTools.js';
import * as math from 'src/client/triples/math.js';

const MIN_MAGNIFICATION = 0.01;
const MAX_MAGNIFICATION = 4;

const NODE_BY_KNOT = new Map();
function getNodeByKnot(knot) {
  if(!NODE_BY_KNOT.has(knot)) {
    NODE_BY_KNOT.set(knot, new Node(knot));
  }
  return NODE_BY_KNOT.get(knot);
}

class RectangleTools {
  static distanceToBorder(rect, dx, dy) {
  	var width = rect.width(),
  		height = rect.height();

  	var innerDistance,
  		m_link = Math.abs(dy / dx),
  		m_rect = height / width;

  	if (m_link <= m_rect) {
  		var timesX = dx / (width / 2),
  			rectY = dy / timesX;
  		innerDistance = Math.sqrt(Math.pow(width / 2, 2) + Math.pow(rectY, 2));
  	} else {
  		var timesY = dy / (height / 2),
  			rectX = dx / timesY;
  		innerDistance = Math.sqrt(Math.pow(height / 2, 2) + Math.pow(rectX, 2));
  	}

  	return innerDistance;
  };
}

const cssClassesByFileType = {
  'png': ['image'],
  'PNG': ['image'],
  'jpg': ['image'],
  'svg': ['image'],
  'mp3': ['audio'],
  'mov': ['movie'],
  'mp4': ['movie'],
  'avi': ['movie'],
  'pptx': ['presentation'],
  'md': ['markdown'],
  'htm': ['html'],
  'html': ['html'],
  'json': ['data'],
  'csv': ['data']
}
const cssClassesByTagURL = {
  'https://lively4/dropbox/tag.md': ['tag'],
  'https://lively4/dropbox/is_a.md': ['is-a'],
  'https://lively4/dropbox/same_as.md': ['same-as'],
  'https://lively4/dropbox/contains.md': ['contains'],
}
class Node {
  static getCSSClassesByType(node) {

  }
  constructor(knot, label) {
    this.knot = knot;
    //this.r = ~~d3.randomUniform(8, 28)();
    this._radius = this.knot.content && this.knot.content.split ?
	    Math.min(this.knot.content.split(/\r?\n/).length, 100) :
	    40;
	 this._width = 60;
	 this._height = 20;
  }
  label() {
    return this.knot.label();
  }
  isTriple() {
    return this.knot.isTriple();
  }
  isExternal() {  return Graph.isExternalURL(new URL(this.knot.url)); }
  getKnot() { return this.knot; }

  draw(parentElement, additionalCssClasses) {
    let cssClasses;

    if(this.knot.isTriple()) {
      cssClasses = cssClassesByTagURL[this.knot.predicate.url] || ['unspecified'];
      cssClasses.push('nostroke')
    } else {
      const fileEnding = this.knot.url.split('#').shift().split('?').shift().split('.').pop();
      //lively.notify(fileEnding)
  		cssClasses = cssClassesByFileType[fileEnding] ?
  		  cssClassesByFileType[fileEnding] :
  		  (lively.notify(fileEnding), ['white']);
    }

	  // that.collectCssClasses();

		//that.nodeElement(parentElement);

		//if (additionalCssClasses instanceof Array) {
		//	cssClasses = cssClasses.concat(additionalCssClasses);
		//}

    if(this.knot.isTriple()) {
      drawTools.appendRectangularClass(parentElement, 60, 20, cssClasses, this.label());
    } else {
		  drawTools.appendCircularClass(parentElement, this.actualRadius(), cssClasses, this.label());
    }

		//that.postDrawActions(parentElement);
	}

	actualRadius() {
	  return this._radius;
	}
	width() { return this._width; }
	height() { return this._height; }
	distanceToBorder(dx, dy) { return this.isTriple() ?
	  RectangleTools.distanceToBorder(this, dx, dy) :
	  this.actualRadius();
	}
}

class Link extends Node {
  constructor(node) {
    super(node.getKnot());

    this._subject = getNodeByKnot(this.getKnot().subject);
    this._predicate = getNodeByKnot(this.getKnot().predicate);
    this._object = getNodeByKnot(this.getKnot().object);
    this._triple = getNodeByKnot(this.getKnot());

    this.frontPart = new LinkPart({
      source: this._subject,
      target: this._triple
    });
    this.backPart = new LinkPart({
      source: this._triple,
      target: this._object
    });
  }
  get subject() { return this._subject; }
  get predicate() { return this._predicate; }
  get object() { return this._object; }
  get triple() { return this._triple; }

  //TODO: support loops specially
  isLoop() {
    return this.subject === this.object;
  }
  linkParts() {
    return [this.frontPart, this.backPart];
  }

  draw(linkGroup, markerContainer) {
  	linkGroup.append("path")
  		//.classed("link-path", true)
  		//.classed(this.domain().cssClassOfNode(), true)
  		//.classed(this.range().cssClassOfNode(), true)
      //.classed(property.linkType(), true);
  }

  // TODO: if we are self-referencial: compute the number of self references from the graph
  loops() {
    return 3;
  }
}

class LinkPart {
  constructor({ source, target }) {
    this.source = source;
    this.target = target;
  }
}

export default class TripleNotes extends Morph {

  async initialize() {
    this.windowTitle = "Knot Explorer";

    let parentElement = this.get('#graph');
    var width,height;
    var chartWidth, chartHeight;
    var margin;
    var svg = d3.select(parentElement)
      .append("svg");
    var graphContainer = svg.append("g").classed("graphContainer", true);

    setSize();

    let graph = await Graph.getInstance();

    let knots = graph.knots;
    this.updateStatistics(knots);

    let nodes = knots.map(getNodeByKnot);
    let links = nodes
      .filter(node => node.isTriple())
      .map(node => new Link(node));

    let hiddenLinks = [];
		links.forEach(link => hiddenLinks = hiddenLinks.concat(link.linkParts()));

    drawChart({
      nodes,
      links,
      hiddenLinks
    });

    lively.addEventListener("triple-notes", this, "extent-changed", e => { setSize(); });

    function setSize() {
      width = parentElement.clientWidth;
      height = parentElement.clientHeight;
      //console.log(`%cwidth: ${width} height: ${height}`, 'font-size: 20pt')

      margin = {top:0, left:0, bottom:0, right:0 };

      chartWidth = width - (margin.left+margin.right)
      chartHeight = height - (margin.top+margin.bottom)

      //graphContainer.attr("width", width).attr("height", height)

      svg
        .attr("width", chartWidth)
        .attr("height", chartHeight)
        .attr("transform", "translate("+[margin.left, margin.top]+")");
    }

    function zoomed() {
      graphContainer.attr("transform", d3.event.transform);
    }

    svg.call(d3.zoom()
			.duration(150)
    	.scaleExtent([MIN_MAGNIFICATION, MAX_MAGNIFICATION])
      .on("zoom", zoomed));

    function drawChart({ nodes, links, hiddenLinks }) {

      var simulation = d3.forceSimulation()
        .force("link", d3.forceLink().id(d => d.index).distance(200))
        //.force("collide",d3.forceCollide(d => d.r + 8).iterations(16) )
        .force("charge", d3.forceManyBody().strength(node => node.isTriple() ? -190*0.5 : -190))
        .force("center", d3.forceCenter(chartWidth / 2, chartWidth / 2))
        .force("y", d3.forceY(0).strength(0.001))
        .force("x", d3.forceX(0).strength(0.001));

      let linkPartContainer = graphContainer.append("g").classed("linkPartContainer", true);
      var hiddenLinkElements = linkPartContainer.selectAll("line")
        .data(hiddenLinks).enter()
        .append("line")
        .style("stroke", "black")
        .style("stroke-opacity", 0.3)
        .style("stroke-width", 10);

      let nodeContainer = graphContainer.append("g").classed("nodeContainer", true);
      let nodeElements = nodeContainer.selectAll(".node")
        .data(nodes).enter()
        .append("g")
        .attr("class", "node")
        .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended))
          .on("dblclick", async node => {
            d3.event.stopPropagation();

            let knotView = await lively.openComponentInWindow("knot-view");
            knotView.loadKnotForURL(node.getKnot().url);
          });

      nodeElements.each(function (node) {
  			node.draw(d3.select(this));
      });

      nodeElements.append("text")
        .attr("class", "text")
        .style("text-anchor", "middle")
        .style("alignment-baseline", "middle")
        .text(d => d.label());

      let linkContainer = graphContainer.append("g").classed("linkContainer", true);
      let markerContainer = linkContainer.append("defs");
      createPropertyMarker(markerContainer);
      function createPropertyMarker(markerContainer) {
      	var marker = appendBasicMarker(markerContainer);
      	//marker.attr("refX", 12);
          var m1X = -12 ;
          var m1Y = 8 ;
          var m2X = -12;
          var m2Y = -8 ;
      	marker.append("path")
      		//.attr("d", "M0,-8L12,0L0,8Z")
              .attr("d", "M0,0L " + m1X + "," + m1Y + "L" + m2X + "," + m2Y + "L" + 0 + "," + 0 )
      		.classed("basic-triple-link", true);
      }

      function appendBasicMarker(markerContainer) {
      	return markerContainer.append("marker")
      		.datum({})
      		.attr("id", "triple-notes-basic-triple-link")

      		.attr("viewBox", "-14 -10 28 20")
      		.attr("markerWidth",10)
      		.attr("markerHeight", 10)
      		//.attr("markerUnits", "userSpaceOnUse")
      		.attr("orient", "auto");
      }

  		// Draw links
  		let linkGroups = linkContainer.selectAll(".link")
  			.data(links).enter()
  			.append("g")
  			.classed("link", true);

  		linkGroups.each(function (link) {
  		  d3.select(this).attr("marker-end", "url(#triple-notes-basic-triple-link)");
  			link.draw(d3.select(this), markerContainer);
  		});

  		// Select the path for direct access to receive a better performance
      let linkPathElements = linkGroups.selectAll("path");

      let curveFunction = d3.line()
  			.x(function (d) {
  				return d.x;
  			})
  			.y(function (d) {
  				return d.y;
  			})
        .curve(d3.curveNatural);
      function recalculatePositions() {
        nodeElements.attr("transform", d => "translate(" + d.x + "," + d.y + ")");

        hiddenLinkElements
          .attr("x1", d => d.source.x)
          .attr("y1", d => d.source.y)
          .attr("x2", d => d.target.x)
          .attr("y2", d => d.target.y);

    		// Set link paths and calculate additional information
    		linkPathElements.attr("d", function (link) {
    			if (link.isLoop()) {
    				return math.calculateLoopPath(link);
    			}
    			var curvePoint = link.triple;
    			var pathStart = math.calculateIntersection(curvePoint, link.subject, 1);
    			var pathEnd = math.calculateIntersection(curvePoint, link.object, 1);

    			return curveFunction([pathStart, curvePoint, pathEnd]);
        });
      }

      simulation
        .nodes(nodes)
        .on("tick", recalculatePositions);

      simulation.force("link")
        .links(hiddenLinks);

      function dragstarted(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
      }

      function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
      }

      function dragended(d) {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      }
    }
  }

  updateStatistics(knots) {
    this.get('#number-of-knots').innerHTML = knots.length;
    this.get('#number-of-triples').innerHTML = knots.filter(k => k.isTriple()).length;
  }
}<commit_msg>AUTO-COMMIT templates/triple-notes.js<commit_after>import Morph from "./Morph.js"

import d3 from 'src/external/d3.v4.js';

import { Graph } from 'src/client/triples/triples.js';
import * as drawTools from 'src/client/triples/drawTools.js';
import * as math from 'src/client/triples/math.js';

const MIN_MAGNIFICATION = 0.01;
const MAX_MAGNIFICATION = 4;

const NODE_BY_KNOT = new Map();
function getNodeByKnot(knot) {
  if(!NODE_BY_KNOT.has(knot)) {
    NODE_BY_KNOT.set(knot, new Node(knot));
  }
  return NODE_BY_KNOT.get(knot);
}

class RectangleTools {
  static distanceToBorder(rect, dx, dy) {
  	var width = rect.width(),
  		height = rect.height();

  	var innerDistance,
  		m_link = Math.abs(dy / dx),
  		m_rect = height / width;

  	if (m_link <= m_rect) {
  		var timesX = dx / (width / 2),
  			rectY = dy / timesX;
  		innerDistance = Math.sqrt(Math.pow(width / 2, 2) + Math.pow(rectY, 2));
  	} else {
  		var timesY = dy / (height / 2),
  			rectX = dx / timesY;
  		innerDistance = Math.sqrt(Math.pow(height / 2, 2) + Math.pow(rectX, 2));
  	}

  	return innerDistance;
  };
}

const cssClassesByFileType = {
  'png': ['image'],
  'PNG': ['image'],
  'jpg': ['image'],
  'svg': ['image'],
  'mp3': ['audio'],
  'mov': ['movie'],
  'mp4': ['movie'],
  'avi': ['movie'],
  'pptx': ['presentation'],
  'md': ['markdown'],
  'htm': ['html'],
  'html': ['html'],
  'json': ['data'],
  'csv': ['data']
}
const cssClassesByTagURL = {
  'https://lively4/dropbox/tag.md': ['tag'],
  'https://lively4/dropbox/is_a.md': ['is-a'],
  'https://lively4/dropbox/same_as.md': ['same-as'],
  'https://lively4/dropbox/contains.md': ['contains'],
}
class Node {
  static getCSSClassesByType(node) {

  }
  constructor(knot, label) {
    this.knot = knot;
    //this.r = ~~d3.randomUniform(8, 28)();
    this._radius = this.knot.content && this.knot.content.split ?
	    Math.min(this.knot.content.split(/\r?\n/).length, 100) :
	    40;
	 this._width = 60;
	 this._height = 20;
  }
  label() {
    return this.knot.label();
  }
  isTriple() {
    return this.knot.isTriple();
  }
  isExternal() {  return Graph.isExternalURL(new URL(this.knot.url)); }
  getKnot() { return this.knot; }

  draw(parentElement, additionalCssClasses) {
    let cssClasses;

    if(this.knot.isTriple()) {
      cssClasses = cssClassesByTagURL[this.knot.predicate.url] || ['unspecified'];
      cssClasses.push('nostroke')
    } else {
      const fileEnding = this.knot.url.split('#').shift().split('?').shift().split('.').pop();
      //lively.notify(fileEnding)
  		cssClasses = cssClassesByFileType[fileEnding] ?
  		  cssClassesByFileType[fileEnding] :
  		  (lively.notify(fileEnding), ['white']);
    }

	  // that.collectCssClasses();

		//that.nodeElement(parentElement);

		//if (additionalCssClasses instanceof Array) {
		//	cssClasses = cssClasses.concat(additionalCssClasses);
		//}

    if(this.knot.isTriple()) {
      drawTools.appendRectangularClass(parentElement, 60, 20, cssClasses, this.label());
    } else {
		  drawTools.appendCircularClass(parentElement, this.actualRadius(), cssClasses, this.label());
    }

		//that.postDrawActions(parentElement);
	}

	actualRadius() {
	  return this._radius;
	}
	width() { return this._width; }
	height() { return this._height; }
	distanceToBorder(dx, dy) { return this.isTriple() ?
	  RectangleTools.distanceToBorder(this, dx, dy) :
	  this.actualRadius();
	}
}

class Link extends Node {
  constructor(node) {
    super(node.getKnot());

    this._subject = getNodeByKnot(this.getKnot().subject);
    this._predicate = getNodeByKnot(this.getKnot().predicate);
    this._object = getNodeByKnot(this.getKnot().object);
    this._triple = getNodeByKnot(this.getKnot());

    this.frontPart = new LinkPart({
      source: this._subject,
      target: this._triple
    });
    this.backPart = new LinkPart({
      source: this._triple,
      target: this._object
    });
  }
  get subject() { return this._subject; }
  get predicate() { return this._predicate; }
  get object() { return this._object; }
  get triple() { return this._triple; }

  //TODO: support loops specially
  isLoop() {
    return this.subject === this.object;
  }
  linkParts() {
    return [this.frontPart, this.backPart];
  }

  draw(linkGroup, markerContainer) {
  	linkGroup.append("path")
  		//.classed("link-path", true)
  		//.classed(this.domain().cssClassOfNode(), true)
  		//.classed(this.range().cssClassOfNode(), true)
      //.classed(property.linkType(), true);
  }

  // TODO: if we are self-referencial: compute the number of self references from the graph
  loops() {
    return 3;
  }
}

class LinkPart {
  constructor({ source, target }) {
    this.source = source;
    this.target = target;
  }
}

export default class TripleNotes extends Morph {

  async initialize() {
    this.windowTitle = "Knot Explorer";

    let parentElement = this.get('#graph');
    var width,height;
    var chartWidth, chartHeight;
    var margin;
    var svg = d3.select(parentElement)
      .append("svg");
    var graphContainer = svg.append("g").classed("graphContainer", true);

    setSize();

    let graph = await Graph.getInstance();

    let knots = graph.knots;
    this.updateStatistics(knots);

    let nodes = knots.map(getNodeByKnot);
    let links = nodes
      .filter(node => node.isTriple())
      .map(node => new Link(node));

    let hiddenLinks = [];
		links.forEach(link => hiddenLinks = hiddenLinks.concat(link.linkParts()));

    drawChart({
      nodes,
      links,
      hiddenLinks
    });

    lively.addEventListener("triple-notes", this, "extent-changed", e => { setSize(); });

    function setSize() {
      width = parentElement.clientWidth;
      height = parentElement.clientHeight;
      //console.log(`%cwidth: ${width} height: ${height}`, 'font-size: 20pt')

      margin = {top:0, left:0, bottom:0, right:0 };

      chartWidth = width - (margin.left+margin.right)
      chartHeight = height - (margin.top+margin.bottom)

      //graphContainer.attr("width", width).attr("height", height)

      svg
        .attr("width", chartWidth)
        .attr("height", chartHeight)
        .attr("transform", "translate("+[margin.left, margin.top]+")");
    }

    function zoomed() {
      graphContainer.attr("transform", d3.event.transform);
    }

    svg.call(d3.zoom()
			.duration(150)
    	.scaleExtent([MIN_MAGNIFICATION, MAX_MAGNIFICATION])
      .on("zoom", zoomed));

    function drawChart({ nodes, links, hiddenLinks }) {

      var simulation = d3.forceSimulation()
        .force("link", d3.forceLink().id(d => d.index).distance(200))
        //.force("collide",d3.forceCollide(d => d.r + 8).iterations(16) )
        .force("charge", d3.forceManyBody().strength(node => node.isTriple() ? -190*0.5 : -190))
        .force("center", d3.forceCenter(chartWidth / 2, chartWidth / 2))
        .force("y", d3.forceY(0).strength(0.001))
        .force("x", d3.forceX(0).strength(0.001));

      let linkPartContainer = graphContainer.append("g").classed("linkPartContainer", true);
      var hiddenLinkElements = linkPartContainer.selectAll("line")
        .data(hiddenLinks).enter()
        .append("line")
        .style("stroke", "black")
        .style("stroke-opacity", 0.1)
        .style("stroke-width", 10);

      let nodeContainer = graphContainer.append("g").classed("nodeContainer", true);
      let nodeElements = nodeContainer.selectAll(".node")
        .data(nodes).enter()
        .append("g")
        .attr("class", "node")
        .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended))
          .on("dblclick", async node => {
            d3.event.stopPropagation();

            let knotView = await lively.openComponentInWindow("knot-view");
            knotView.loadKnotForURL(node.getKnot().url);
          });

      nodeElements.each(function (node) {
  			node.draw(d3.select(this));
      });

      nodeElements.append("text")
        .attr("class", "text")
        .style("text-anchor", "middle")
        .style("alignment-baseline", "middle")
        .text(d => d.label());

      let linkContainer = graphContainer.append("g").classed("linkContainer", true);
      let markerContainer = linkContainer.append("defs");
      createPropertyMarker(markerContainer);
      function createPropertyMarker(markerContainer) {
      	var marker = appendBasicMarker(markerContainer);
      	//marker.attr("refX", 12);
          var m1X = -12 ;
          var m1Y = 8 ;
          var m2X = -12;
          var m2Y = -8 ;
      	marker.append("path")
      		//.attr("d", "M0,-8L12,0L0,8Z")
              .attr("d", "M0,0L " + m1X + "," + m1Y + "L" + m2X + "," + m2Y + "L" + 0 + "," + 0 )
      		.classed("basic-triple-link", true);
      }

      function appendBasicMarker(markerContainer) {
      	return markerContainer.append("marker")
      		.datum({})
      		.attr("id", "triple-notes-basic-triple-link")

      		.attr("viewBox", "-14 -10 28 20")
      		.attr("markerWidth",10)
      		.attr("markerHeight", 10)
      		//.attr("markerUnits", "userSpaceOnUse")
      		.attr("orient", "auto");
      }

  		// Draw links
  		let linkGroups = linkContainer.selectAll(".link")
  			.data(links).enter()
  			.append("g")
  			.classed("link", true);

  		linkGroups.each(function (link) {
  		  d3.select(this).attr("marker-end", "url(#triple-notes-basic-triple-link)");
  			link.draw(d3.select(this), markerContainer);
  		});

  		// Select the path for direct access to receive a better performance
      let linkPathElements = linkGroups.selectAll("path");

      let curveFunction = d3.line()
  			.x(function (d) {
  				return d.x;
  			})
  			.y(function (d) {
  				return d.y;
  			})
        .curve(d3.curveNatural);
      function recalculatePositions() {
        nodeElements.attr("transform", d => "translate(" + d.x + "," + d.y + ")");

        hiddenLinkElements
          .attr("x1", d => d.source.x)
          .attr("y1", d => d.source.y)
          .attr("x2", d => d.target.x)
          .attr("y2", d => d.target.y);

    		// Set link paths and calculate additional information
    		linkPathElements.attr("d", function (link) {
    			if (link.isLoop()) {
    				return math.calculateLoopPath(link);
    			}
    			var curvePoint = link.triple;
    			var pathStart = math.calculateIntersection(curvePoint, link.subject, 1);
    			var pathEnd = math.calculateIntersection(curvePoint, link.object, 1);

    			return curveFunction([pathStart, curvePoint, pathEnd]);
        });
      }

      simulation
        .nodes(nodes)
        .on("tick", recalculatePositions);

      simulation.force("link")
        .links(hiddenLinks);

      function dragstarted(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
      }

      function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
      }

      function dragended(d) {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      }
    }
  }

  updateStatistics(knots) {
    this.get('#number-of-knots').innerHTML = knots.length;
    this.get('#number-of-triples').innerHTML = knots.filter(k => k.isTriple()).length;
  }
}<|endoftext|>


<commit_before> 'use strict';

 var tls = require('tls'),
     util = require('util'),
     Emitter = require('events').EventEmitter;

 /**
  *
  * Zoquete constructor
  *
  * @param {Object} options - Tls options reference: https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener
  *
  */

 function Zoquete(options) {
     this.options = options;
     this.setMaxListeners(0);
     this.isServer = false;
     this.isClient = false;
 }

 /**
  *
  *  Inherits from `EventEmitter`.
  *
  */
 util.inherits(Zoquete, Emitter);

 /**
  *
  * Creates a socket server tls
  *
  * @param {Function} callback - When the server has been created
  *
  */
 Zoquete.prototype.server = function(callback) {
     var self = this;
     this.server = tls.createServer(this.options, function(socket) {
         self.removeAllListeners();
         self._resetSocket(socket);
         self._socket.pipe(self._socket);
         self.isServer = true;
         if (typeof callback === 'function') {
             callback();
         }
     });
     this.server.listen(this.options.port);
     return this;
 };

 /**
  *
  * Reset socket, remove all listeners, assign socket
  * set encoding and add default listeners
  *
  * @param {Object} socket - Socket
  *
  * @returns {Object}
  *
  */
 Zoquete.prototype._resetSocket = function(socket) {
     this._socket = socket;
     this._socket.setEncoding('utf8');
     this._wrapondata();
     this._socket.on('error', function(e) {
         console.log('Error: %s', e);
     });
     this._socket.on('close', function(e) {
         console.log('Close: %s', e);
     });
     this._socket.on('end', function(e) {
         console.log('End: %s', e);
     });
     return this._socket;
 };

 /**
  *
  * Creates a socket client tls
  *
  * @param {Function} callback - When the client has connected to server
  *
  */
 Zoquete.prototype.client = function(callback) {
     var self = this,
         socket = tls.connect(this.options, function() {
             self.isClient = true;
             if (typeof callback === 'function') {
                 callback();
             }
         });
     this._resetSocket(socket);
     process.stdin.pipe(this._socket);
     process.stdin.resume();
     return this;
 };

 /**
  *
  * Wraps socket.wirte method
  *
  * @param {String} ev - Event name
  * @param {Object} data - JSON data to send
  *
  * @returns {Promise}
  *
  */
 Zoquete.prototype.send = function(ev, data) {
     var self = this,
         req = this._parser(ev, data);
     if (req) {
         this._socket.write(req);
         return new Promise(function(resolve, reject) {
             self.once(ev + ':done', function(data) {
                 self.removeAllListeners(ev + ':fail');
                 resolve(data);
             });
             self.once(ev + ':fail', function(data) {
                 self.removeAllListeners(ev + ':done');
                 reject(data);
             });
         });
     }
 };

 /**
  *
  * Wraps socket.on('datat') event
  *
  */
 Zoquete.prototype._wrapondata = function() {
     var self = this;
     self._socket.on('data', function(data) {
         self._reverse(data);
     });
 };

 /*
  *
  * Convert and validate Object with format {ev: 'myevent': content: {}}
  * to string (stingify)
  *
  * @param {String} ev - Event name
  * @param {Object} data - JSON data to send
  *
  * @returns {String|Boolean}
  *
  */
 Zoquete.prototype._parser = function(ev, data) {
     return JSON.stringify({
         ev: ev,
         content: data
     });
 };

 /*
  *
  * Validate, convert string to object and trigger the event
  *
  * @param {Object} obj - JSON data to send
  *
  * @returns {Boolen}
  *
  */
 Zoquete.prototype._reverse = function(obj) {
     try {
        obj = JSON.parse(obj);
        this.emit(obj.ev, obj.content);
     } catch (e) {
        this._socket.emit('error', e);
     }
 };

 /*
  *
  * Close connection
  *
  * @returns {Boolen}
  *
  */
 Zoquete.prototype.close = function() {
     if (this.isServer) {
         this._socket.end();
     }
     return;
 };

 module.exports = Zoquete;
<commit_msg>Added support to get data from stream<commit_after> 'use strict';

 var tls = require('tls'),
     util = require('util'),
     Emitter = require('events').EventEmitter;

 /**
  *
  * Zoquete constructor
  *
  * @param {Object} options - Tls options reference: https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener
  *
  */

 function Zoquete(options) {
     this.options = options;
     this.setMaxListeners(0);
     this.isServer = false;
     this.isClient = false;
 }

 /**
  *
  *  Inherits from `EventEmitter`.
  *
  */
 util.inherits(Zoquete, Emitter);

 /**
  *
  * Creates a socket server tls
  *
  * @param {Function} callback - When the server has been created
  *
  */
 Zoquete.prototype.server = function(callback) {
     var self = this;
     this.server = tls.createServer(this.options, function(socket) {
         self.removeAllListeners();
         self._resetSocket(socket);
         self._socket.pipe(self._socket);
         self.isServer = true;
         if (typeof callback === 'function') {
             callback();
         }
     });
     this.server.listen(this.options.port);
     return this;
 };

 /**
  *
  * Reset socket, remove all listeners, assign socket
  * set encoding and add default listeners
  *
  * @param {Object} socket - Socket
  *
  * @returns {Object}
  *
  */
 Zoquete.prototype._resetSocket = function(socket) {
     this._socket = socket;
     this._socket.setEncoding('utf8');
     this._wrapondata();
     this._socket.on('error', function(e) {
         console.log('Error: %s', e);
     });
     this._socket.on('close', function(e) {
         console.log('Close: %s', e);
     });
     this._socket.on('end', function(e) {
         console.log('End: %s', e);
     });
     return this._socket;
 };

 /**
  *
  * Creates a socket client tls
  *
  * @param {Function} callback - When the client has connected to server
  *
  */
 Zoquete.prototype.client = function(callback) {
     var self = this,
         socket = tls.connect(this.options, function() {
             self.isClient = true;
             if (typeof callback === 'function') {
                 callback();
             }
         });
     this._resetSocket(socket);
     process.stdin.pipe(this._socket);
     process.stdin.resume();
     return this;
 };

 /**
  *
  * Wraps socket.wirte method
  *
  * @param {String} ev - Event name
  * @param {Object} data - JSON data to send
  *
  * @returns {Promise}
  *
  */
 Zoquete.prototype.send = function(ev, data) {
     var self = this,
         req = this._parser(ev, data);
     if (req) {
         this._socket.write(req);
         return new Promise(function(resolve, reject) {
             self.once(ev + ':done', function(data) {
                 self.removeAllListeners(ev + ':fail');
                 resolve(data);
             });
             self.once(ev + ':fail', function(data) {
                 self.removeAllListeners(ev + ':done');
                 reject(data);
             });
         });
     }
 };

 /**
  *
  * Wraps socket.on('datat') event
  *
  */
 Zoquete.prototype._wrapondata = function() {
    var self = this;
    var received = '';
    self._socket.on('data', function(data) {
      received += data;

      if (Buffer.byteLength(data, 'utf8') < 1024) {
        self._reverse(received);
        received = '';
      }
    });
 };

 /*
  *
  * Convert and validate Object with format {ev: 'myevent': content: {}}
  * to string (stingify)
  *
  * @param {String} ev - Event name
  * @param {Object} data - JSON data to send
  *
  * @returns {String|Boolean}
  *
  */
 Zoquete.prototype._parser = function(ev, data) {
     return JSON.stringify({
         ev: ev,
         content: data
     });
 };

 /*
  *
  * Validate, convert string to object and trigger the event
  *
  * @param {Object} obj - JSON data to send
  *
  * @returns {Boolen}
  *
  */
 Zoquete.prototype._reverse = function(obj) {
     try {
        obj = JSON.parse(obj);
        this.emit(obj.ev, obj.content);
     } catch (e) {
        this._socket.emit('error', e);
     }
 };

 /*
  *
  * Close connection
  *
  * @returns {Boolen}
  *
  */
 Zoquete.prototype.close = function() {
     if (this.isServer) {
         this._socket.end();
     }
     return;
 };

 module.exports = Zoquete;
<|endoftext|>