<commit_before>/**
 * Application logic.
 *
 * @package themakermap
 */

(function($){
    /**
     * Configuration
     */
    var dataProvider = '1tteiG-HYAlsmh3ef5U-XVDEWu5QXqDxqWwDx-pc';

    /**
     * Storage objects
     */
    var makersLayer;
    var map, layer, infoWindow;

    /**
     * Window rendering handler.
     */
    function render () {
        var $map    = $('#map-wrapper');
        var calc    = $(window).height() - $map.position().top;

        $map.css('height', calc + 'px');
    }

    /**
     * Event handler for checkbox controls.
     *
     * @param {Object} Event
     *
     * @return {void}
     */
    function updateAnyCheckbox (e) {
        var $target = $(e.target);
        var $boxen  = $('#filter').find('input.classification-filter[type="checkbox"]').not('[value="any"]');
        var $any    = $('#filter').find('input.classification-filter[value="any"]');

        if ($target.val() == 'any') {
            // Update other checkboxes based on "any" state
            if ($any.is(':checked')) {
                $boxen.prop('checked', 'checked');
            } else {
                $boxen.removeAttr('checked');
            }
        } else {
            // Update "any" checkbox based on others' state
            if ($boxen.not(':checked').length) {
                $any.removeAttr('checked');
            } else {
                $any.prop('checked', 'checked');
            }
        }
    }

    /**
     * Google Maps
     */
    function initMaps () {
        map = new google.maps.Map(document.getElementById('map-canvas'), {
            center: new google.maps.LatLng(-37.8136, 144.9631),
            zoom: 9,
            disableDefaultUI: true,
            zoomControl: true,
    		zoomControlOptions: {
    			style: google.maps.ZoomControlStyle.LARGE,
    			position: google.maps.ControlPosition.TOP_RIGHT
    		},
            streetViewControl: true
        });

        var style = [
            {
                elementType: 'geometry',
                stylers: [
                    { saturation: -100 },
                    { weight: 0.4 }
                ]
            },
            {
                featureType: 'poi',
                stylers: [
                    { visibility: "off" }
                ]
            },
            {
                featureType: 'administrative.land_parcel',
                elementType: 'all',
                stylers: [
                    { visibility: 'off' }
                ]
            }
        ];

        var styledMapType = new google.maps.StyledMapType(style, {
            map: map,
            name: 'Styled Map'
        });

        map.mapTypes.set('map-style', styledMapType);
        map.setMapTypeId('map-style');

        infoWindow = new google.maps.InfoWindow({
            content: ""
        });
        loadData();

        if (navigator && navigator.geolocation) {
           locateMe();
        }
    }

		function locateMe () {
			navigator.geolocation.getCurrentPosition(function(position) {
	      var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
	      map.setCenter(latlng);
	      map.setZoom(12);

				$('.locateMe').fadeIn(1000,function(){
					$(this).tooltip('show');
				}).css("display",'table');

	    });

			$('.locateMe').click(function(){
				locateMe();
			});

		}

    /**
     * UI events
     */
    function initEventListeners () {
        // Selectors
        var $searchNav  = $('#search-nav');
        var $addContentNav = $('#add-content-nav');
        var $aboutNav = $('#about-nav');
        var $window = $(window);
        var $nav    = $('#topnav a');
        var $search = $('#search');
        var $filter = $('#filter');

        // Resize handler
        $window.resize(render);

        // Top nav
        $.hovertips($nav, {
            delay_hide:     0,
            delay_hover:    0,
            delay_leave:    0,
            render: function($el, data, loading) {
                var $tooltip;
                var self = this;
                $tooltip = $('
');
                $tooltip.addClass('nav-tooltip')
                $tooltip.html($el.find('img').attr('alt'));
                $el.on('click', function() {
                    self.hide(0);
                });
                return $tooltip;
            }
        });

        $addContentNav.click(function () {
            $('.searchMenu').hide();
            $('.aboutMenu').hide();
            $('.addContentMenu').show();
            makersLayer.setMap(null);
        });

        $aboutNav.click(function () {
            $('.searchMenu').hide();
            $('.addContentMenu').hide();
            $('.aboutMenu').show();
            console.log('content');
        });

        $searchNav.click(function () {
            $('.searchMenu').show();
            $('.aboutMenu').hide();
            $('.addContentMenu').hide();
            makersLayer.setMap(map);
        });

        // Load classifications
        var classQry = new Parse.Query(MakerMap.Model.PrimaryClassification);
        classQry.find({
            success: function(resp) {
                for (var i = 0; i < resp.length; i++) {
                    var cls = resp[i];
                    $("ul.filters").append("
" + cls.get("friendlyName") + " <input type='checkbox' class='classification-filter' value='" + cls.id + "' />
");
                }

                // Filter
                $filter.find('input.classification-filter').click(function (e) {
                    updateAnyCheckbox(e);
                    loadData();
                });
            },
            failure: function(err) {
                alert("An error occurred loading primary classifications: " + err);
            }
        });

        // Search
        $search.submit(function () {
            return false;
        });

        $search.find('input').keyup(function () {
            loadData();
        });
    }

		function filterMenu() {
			$('.filterIcon').click(function(){
				$('.filterWrap').slideToggle();
			});
		}

		function mobileMenu() {
			$('.menuToggle').click(function(){
				$('.aboutWrap').slideToggle();
			});
		}

    function initSocialite() {
        Socialite.load($('div.footer'));
    }

    function makerToFeature(mkr) {
        var coords = mkr.get("coordinates").toJSON();
        var obj = {
            id: mkr.id,
            geometry: {
                lng: coords.longitude,
                lat: coords.latitude
            },
            properties: {
                title: mkr.get("title"),
                description: mkr.get("description"),
                marker_color: mkr.get("marker_color"),
                marker_size: mkr.get("marker_size"),
                marker_symbol: mkr.get("marker_symbol")
            }
        };
        return new google.maps.Data.Feature(obj);
    }

    function getIcon(symbolName) {
        if (!symbolName || symbolName == "") {
            return null;
        }
        var relPart = "img/markers/" + symbolName + ".png";
        //HACK: Should be a better way to get the URL base of index.html
        if (window.location.pathname.indexOf("index.html") >= 0)
            return window.location.pathname.replace("index.html", relPart);
        else
            return relPart;
    }

    function loadData() {
        var query_array = [];
        var query = new Parse.Query(MakerMap.Model.Maker);

        // Detach the layer before replacing
        if (makersLayer) {
            makersLayer.setMap(null);
        }
        makersLayer = new google.maps.Data();
        makersLayer.setStyle(function(feature) {
            return {
                fillColor: feature.getProperty("marker_color"),
                clickable: true,
                title: feature.getProperty("title"),
                icon: getIcon(feature.getProperty("marker_symbol"))
            };
        });

        search_string = $('#search').find('input').val();
        if(search_string != "") {
            var title_query = new Parse.Query(MakerMap.Model.Maker);
            var description_query = new Parse.Query(MakerMap.Model.Maker);
            title_query.contains("title", search_string);
            description_query.contains("description", search_string);
            query = Parse.Query.or(title_query, description_query);
        }

        if($('#filter').find('input.classification-filter[value="any"]:checked').length == 0) {
            $('#filter').find('input.classification-filter[type="checkbox"]:checked').each(function () {
                query_array.push($(this).attr('value'));
            });
            var lookupQuery = new Parse.Query(MakerMap.Model.PrimaryClassification);
            lookupQuery.containedIn("objectId", query_array);
            query.matchesKeyInQuery("classification", "objectId", lookupQuery);
        }

        query.find({
            success: function(resp) {
                for (var i = 0; i < resp.length; i++) {
                    makersLayer.add(makerToFeature(resp[i]));
                }
                makersLayer.setMap(map);
                setupEventListeners();
            },
            failure: function(err) {
                alert("Error loading markers: " + err);
            }
        });
    }

    function setupEventListeners() {
        makersLayer.addListener('click', function(event) {
            infoWindow.setContent(
                '
'+event.feature.getProperty('title')+'
'+
                '
'+event.feature.getProperty('description')+'
'
            );
            var anchor = new google.maps.MVCObject();
            anchor.set("position",event.latLng);
            infoWindow.open(map,anchor);
        });
    };

    //Init the parse API
    Parse.initialize("wj2jWY2HA6L4C1qpWuZzsruUHkO8BZjIbtUI0hmr" /* App ID */, "3GNfJdTZKsLlRrqsH1n8vJtrgFCRwuCmfb33Y2JG" /* JS Key */);
    /**
     * On load, init maps & start listening for UI events
     */
    render();
    initMaps();
    initEventListeners();
		filterMenu();
		mobileMenu();
	$('.aboutMenu').hide();
    initSocialite();

    $(document).ready(function(){
        $('#location').geocomplete({
            map: map
        });
    });
})(jQuery);
<commit_msg>Show busy indicator for loading classification data<commit_after>/**
 * Application logic.
 *
 * @package themakermap
 */

(function($){
    /**
     * Parse Application ID
     */
    var PARSE_APP_ID = 'wj2jWY2HA6L4C1qpWuZzsruUHkO8BZjIbtUI0hmr';
    /**
     * Parse ID for JavaScript API
     */
    var PARSE_JS_ID = '3GNfJdTZKsLlRrqsH1n8vJtrgFCRwuCmfb33Y2JG';

    /**
     * Storage objects
     */
    var makersLayer;
    var map, layer, infoWindow;

    /**
     * Window rendering handler.
     */
    function render () {
        var $map    = $('#map-wrapper');
        var calc    = $(window).height() - $map.position().top;

        $map.css('height', calc + 'px');
    }

    /**
     * Strips all HTML tags from the given string
     *
     * @param {String} dirtyString
     *
     * @return {String}
     */
    function stripHTML(dirtyString) {
        var container = document.createElement('div');
        container.innerHTML = dirtyString;
        return container.textContent || container.innerText;
    }

    /**
     * Event handler for checkbox controls.
     *
     * @param {Object} Event
     *
     * @return {void}
     */
    function updateAnyCheckbox (e) {
        var $target = $(e.target);
        var $boxen  = $('#filter').find('input.classification-filter[type="checkbox"]').not('[value="any"]');
        var $any    = $('#filter').find('input.classification-filter[value="any"]');

        if ($target.val() == 'any') {
            // Update other checkboxes based on "any" state
            if ($any.is(':checked')) {
                $boxen.prop('checked', 'checked');
            } else {
                $boxen.removeAttr('checked');
            }
        } else {
            // Update "any" checkbox based on others' state
            if ($boxen.not(':checked').length) {
                $any.removeAttr('checked');
            } else {
                $any.prop('checked', 'checked');
            }
        }
    }

    /**
     * Google Maps
     */
    function initMaps () {
        map = new google.maps.Map(document.getElementById('map-canvas'), {
            center: new google.maps.LatLng(-37.8136, 144.9631),
            zoom: 9,
            disableDefaultUI: true,
            zoomControl: true,
            zoomControlOptions: {
                style: google.maps.ZoomControlStyle.LARGE,
                position: google.maps.ControlPosition.TOP_RIGHT
            },
            streetViewControl: true
        });

        var style = [
            {
                elementType: 'geometry',
                stylers: [
                    { saturation: -100 },
                    { weight: 0.4 }
                ]
            },
            {
                featureType: 'poi',
                stylers: [
                    { visibility: "off" }
                ]
            },
            {
                featureType: 'administrative.land_parcel',
                elementType: 'all',
                stylers: [
                    { visibility: 'off' }
                ]
            }
        ];

        var styledMapType = new google.maps.StyledMapType(style, {
            map: map,
            name: 'Styled Map'
        });

        map.mapTypes.set('map-style', styledMapType);
        map.setMapTypeId('map-style');

        infoWindow = new google.maps.InfoWindow({
            content: ""
        });
        loadData();

        if (navigator && navigator.geolocation) {
           locateMe();
        }
    }

    /**
     * Centers the map to the user's geolocated position
     */
    function locateMe () {
        navigator.geolocation.getCurrentPosition(function(position) {
            var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
            map.setCenter(latlng);
            map.setZoom(12);

            $('.locateMe').fadeIn(1000,function(){
                $(this).tooltip('show');
            }).css("display",'table');
        });
        $('.locateMe').click(function(){
            locateMe();
        });
    }

    /**
     * UI events
     */
    function initEventListeners () {
        // Selectors
        var $searchNav  = $('#search-nav');
        var $addContentNav = $('#add-content-nav');
        var $aboutNav = $('#about-nav');
        var $window = $(window);
        var $nav    = $('#topnav a');
        var $search = $('#search');
        var $filter = $('#filter');

        // Resize handler
        $window.resize(render);

        // Top nav
        $.hovertips($nav, {
            delay_hide:     0,
            delay_hover:    0,
            delay_leave:    0,
            render: function($el, data, loading) {
                var $tooltip;
                var self = this;
                $tooltip = $('
');
                $tooltip.addClass('nav-tooltip')
                $tooltip.html($el.find('img').attr('alt'));
                $el.on('click', function() {
                    self.hide(0);
                });
                return $tooltip;
            }
        });

        $addContentNav.click(function () {
            $('.searchMenu').hide();
            $('.aboutMenu').hide();
            $('.addContentMenu').show();
            makersLayer.setMap(null);
        });

        $aboutNav.click(function () {
            $('.searchMenu').hide();
            $('.addContentMenu').hide();
            $('.aboutMenu').show();
            console.log('content');
        });

        $searchNav.click(function () {
            $('.searchMenu').show();
            $('.aboutMenu').hide();
            $('.addContentMenu').hide();
            makersLayer.setMap(map);
        });

        var filterList = $("ul.filters");
        // Load classifications
        var listBusy = $("
Loading Classifications ...
");
        listBusy.appendTo(filterList);
        var classQry = new Parse.Query(MakerMap.Model.PrimaryClassification);
        classQry.find({
            success: function(resp) {
                for (var i = 0; i < resp.length; i++) {
                    var cls = resp[i];
                    filterList.append("
" + cls.get("friendlyName") + " <input type='checkbox' class='classification-filter' value='" + cls.id + "' />
");
                }

                // Filter
                $filter.find('input.classification-filter').click(function (e) {
                    updateAnyCheckbox(e);
                    loadData();
                });

                listBusy.remove();
            },
            failure: function(err) {
                alert("An error occurred loading primary classifications: " + err);
                listBusy.remove();
            }
        });

        // Search
        $search.submit(function () {
            return false;
        });

        $search.find('input').keyup(function () {
            loadData();
        });
    }

    function filterMenu() {
        $('.filterIcon').click(function(){
            $('.filterWrap').slideToggle();
        });
    }

    function mobileMenu() {
        $('.menuToggle').click(function(){
            $('.aboutWrap').slideToggle();
        });
    }

    function initSocialite() {
        Socialite.load($('div.footer'));
    }

    /**
     * Converts a Maker Parse instance to a google.maps.Data.Feature instance
     * for placement on a map
     */
    function makerToFeature(mkr) {
        var coords = mkr.get("coordinates").toJSON();
        var obj = {
            id: mkr.id,
            geometry: {
                lng: coords.longitude,
                lat: coords.latitude
            },
            properties: {
                title: mkr.get("title"),
                description: mkr.get("description"),
                marker_color: mkr.get("marker_color"),
                marker_size: mkr.get("marker_size"),
                marker_symbol: mkr.get("marker_symbol")
            }
        };
        return new google.maps.Data.Feature(obj);
    }

    function getIcon(symbolName) {
        if (!symbolName || symbolName == "") {
            return null;
        }
        var relPart = "img/markers/" + symbolName + ".png";
        //HACK: Should be a better way to get the URL base of index.html
        if (window.location.pathname.indexOf("index.html") >= 0)
            return window.location.pathname.replace("index.html", relPart);
        else
            return relPart;
    }

    /**
     * Reload the markers on the map based on the current search and filtering criteria
     */
    function loadData() {
        var query_array = [];
        var query = new Parse.Query(MakerMap.Model.Maker);

        // Detach the layer before replacing
        if (makersLayer) {
            makersLayer.setMap(null);
        }
        makersLayer = new google.maps.Data();
        makersLayer.setStyle(function(feature) {
            return {
                fillColor: feature.getProperty("marker_color"),
                clickable: true,
                title: stripHTML(feature.getProperty("title")),
                maker_title: feature.getProperty("title"),
                icon: getIcon(feature.getProperty("marker_symbol"))
            };
        });

        var search_string = $('#search').find('input').val();
        if(search_string != "") {
            var title_query = new Parse.Query(MakerMap.Model.Maker);
            var description_query = new Parse.Query(MakerMap.Model.Maker);
            title_query.contains("title", search_string);
            description_query.contains("description", search_string);
            query = Parse.Query.or(title_query, description_query);
        }

        if($('#filter').find('input.classification-filter[value="any"]:checked').length == 0) {
            $('#filter').find('input.classification-filter[type="checkbox"]:checked').each(function () {
                query_array.push($(this).attr('value'));
            });
            //This is basically: Maker.classification in [selected object ids from PrimaryClassification]
            var lookupQuery = new Parse.Query(MakerMap.Model.PrimaryClassification);
            lookupQuery.containedIn("objectId", query_array);
            query.matchesKeyInQuery("classification", "objectId", lookupQuery);
        }

        query.find({
            success: function(resp) {
                for (var i = 0; i < resp.length; i++) {
                    makersLayer.add(makerToFeature(resp[i]));
                }
                makersLayer.setMap(map);
                setupEventListeners();
            },
            failure: function(err) {
                alert("Error loading markers: " + err);
            }
        });
    }

    function setupEventListeners() {
        makersLayer.addListener('click', function(event) {
            infoWindow.setContent(
                '
'+event.feature.getProperty('maker_title')+'
'+
                '
'+event.feature.getProperty('description')+'
'
            );
            var anchor = new google.maps.MVCObject();
            anchor.set("position",event.latLng);
            infoWindow.open(map,anchor);
        });
    };

    //Init the parse API
    Parse.initialize(PARSE_APP_ID, PARSE_JS_ID);
    /**
     * On load, init maps & start listening for UI events
     */
    render();
    initMaps();
    initEventListeners();
    filterMenu();
    mobileMenu();
    $('.aboutMenu').hide();
    initSocialite();

    $(document).ready(function(){
        $('#location').geocomplete({
            map: map
        });
    });
})(jQuery);
<|endoftext|>


<commit_before>#!/usr/local/bin/node
"use strict";
const moddir      = "/usr/local/lib/node_modules/";
const express     = require(moddir+"express");
const request     = require(moddir+"request");
const FeedParser  = require(moddir+"feedparser");
const testurlFeed = "http://www.guardian.co.uk/world/usa/rss";
const fs          = require('fs');
var rssFile       = __dirname+'/public/rss.html';
var outMENU = '
\n';
var cacheSecounds 	= 12*300;	// secounds 300= 5 minut
var rssHours 		= 6; 	// hours

console.log('~~~ Wait for /rssy.json');
console.log(__dirname+'/rssy.json');
var rssy = fs.readFileSync(__dirname+'/rssy.json', 'utf8');
console.log(rssy);

function getFeed (urlfeed, callback) {
	let req = request (urlfeed);
	let feedparser = new FeedParser ();
	let feedItems = new Array ();
	req.on ("response", function (response) {
		let stream = this;
		if (response.statusCode == 200) {
			stream.pipe (feedparser);
			}
		});
	req.on ("error", function (err) {
		console.log ("getFeed: err.message == " + err.message);
		});
	feedparser.on ("readable", function () {
		try {
			let item = this.read (), flnew;
			if (item !== null) { //2/9/17 by DW
				feedItems.push (item);
				}
			}
		catch (err) {
			console.log ("getFeed: err.message == " + err.message);
			}
		});
	feedparser.on ("end", function () {
		callback (undefined, feedItems);
		});
	feedparser.on ("error", function (err) {
		console.log ("getFeed: err.message == " + err.message);
		callback (err);
		});
	}
		function pad (num) {
			let s = num.toString (), ctplaces = 4;
			while (s.length < ctplaces) {
				s = "0" + s;
				}
			return (s);
			}
//console.log ("\n" + myProductName + " v" + myVersion + ".\n");

/*=======================================*/
function readRSSY(res){
	let fromcache = false;
	// sprawdz czy jest plik
	if (fs.existsSync(rssFile)) {
		//sprawdz date
		fs.stat(rssFile, function(err, stats){
			let seconds = Math.round((new Date().getTime() - stats.mtime) / 1000);
			//console.log('#73==',seconds, new Date().getTime(),' - ',new Date(stats.mtime).getTime(),stats.mtime);
			console.log(`#73 File modified ${seconds} secunds ago`);
			if(seconds>cacheSecounds) {readRSSYfromWWW(res)}
			else {
				// zaladuj
				fs.readFile( rssFile, function (err, data) {
					if (err) {throw err; }
					//console.log(data.toString());
					sendRSS2Browser(res,data.toString());
					return;
				});
			}
		});
	}else {readRSSYfromWWW(res);}// is file
}

function readRSSYfromWWW(res){
	let artCount=1;
		rssy.forEach(function(item,y){
			console.log('#100=',y,item.title,item.url);
			outMENU += ''+item.title+'\n';
			//console.log('#102=',outMENU);
			let urlTestFeed = item.url;

			getFeed (urlTestFeed, function (err, feedItems) {
			if (!err) {
				let teraz = (new Date()).toLocaleString();
				let now   = (new Date()).getTime();
				let outHTML ='';
				//console.log ("
"+item.title+"
\n");
				outHTML+='
\n';
				outHTML+='
 ⇑ '+item.title+'
\n';
				//console.log ("There are " + feedItems.length + " items in the feed.\n");
				for (let i = 0; i < feedItems.length; i++) {
					//title,description,summary,date,pubdate,pubDate,link,guid,author,
					//console.log ("#" +pad(i)+"\n
"+feedItems[i].title+"
\n
"+feedItems[i].summary+".
\n\n");
					let pub   = (new Date(feedItems[i].date)).getTime();
					let delta = Math.round((now-pub)/3600000); // w godzinach
					if (delta>100) delta = 0;
					//console.log ("#121=", item.title, delta,rssHours,feedItems[i].date);
					if (item.title != 'PAP' && delta>rssHours) continue;
					//console.log(now,pub,delta);
					let czas  = (new Date(feedItems[i].date)).toLocaleString();// || (new Date(feedItems[i].pubdate)).toLocaleString() || (new Date(feedItems[i].pubDate)).toLocaleString();
					outHTML+='\n';
					outHTML+='
';
						outHTML+='
'+artCount+'. '+' ['+delta+'h] '+feedItems[i].title+'
\n';
						//outHTML+=''+czas+' ['+delta+']\n';
						outHTML+=feedItems[i].summary;
					outHTML+='
\n\n';
					artCount++;
					}
					outHTML +='
\n';
					finishRSS(res,outHTML,y,rssy.length);
				}

			}); // getFeed

		});
}

let startHTML ='\n';
	startHTML +='<meta charset="utf-8">\n';
	startHTML +='<meta name="viewport" content="width=device-width,initial-scale=1">\n';
	startHTML +='<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAcVMRQNGjO/zhqz/84as//OGrP/zhqz/84as//OGrP/zhqz/84as//OGrP/zhqz/84as//OGrP/zRozv8cVMRQM2fO/x5b0v8eW9L/HlvS/x5b0v8eW9L/HlvS/x5b0v8eW9L/HlvS/x5b0v8eW9L/HlvS/x5b0v8eW9L/M2fO/y9m0P8dW9T/GlzY/4Kq7/+Vs+v/HVvU/x1b1P8cXNb/m7jv/x1b1P8dW9T/HVvU/xlc2f8dW9T/HVvU/y9m0P8pY9H/G1zX/4Gx/v///////////5Cy6P8bXNf/E2bv//////90nuP/G1zX/xRe4v/g7P//n7zs/xpc1/8pY9H/I2DT/xdd3f+Bsf7///////////+Xt+r/GFzZ/zWA+P//////ToTb/xld2/8QX+f//////6bB7f8YXNn/I2DT/x5e1P8WXd7/FF7h/5W48f+Xt+r/E1rP/xRe4P/Y5////////xNb0f8WXd7/GGvz//////9rmOD/Fl3e/x5e1P8ZW9X/FF7i/xRe4v8UXuL/E17g/xRe4v9xqP3//////4mt5v8UXt//FF7i/1qZ/P//////MG/W/xRe4v8ZW9X/FlrV/xFf5v8RX+b/FmXp/zp/8f/Y5////////9Lg9v8ZYtr/EV/m/wxg7P/3+v//8PX8/xJd2P8RX+b/FlrV/xdb1/8OYOr/kLv+/////////////////4it5/8YYtz/D2Dp/w9g6f9xp/7//////06D2v8PYOj/D2Dp/xdb1/8bXtf/DGHt/whi8/94pOr/TIXe/xFc1f8NYOj/DGHt/wxh7f8ygPz//////+Hr+f8QXNn/DGHt/wxh7f8bXtf/IGLZ/wph8f8KYfH/CmHx/wph8f8KYfH/CmHx/wph8v9xp/3///////////8SWs7/CmHx/wph8f8KYfH/IGLZ/yVm2v8IYvT/CGL0/whi9P8IYvT/Fmz2/1uZ+//3+v///////+Hr+v8SW8//CGL0/whi9P8IYvT/CGL0/yVm2v8ratv/BmP4/wRj+v/g7P//////////////////8PX+/06D2v8OXt3/BmP4/wZj+P8GY/j/BmP4/wZj+P8ratv/MG7c/wRj+/8EY/v/nb7y/6bC7/9qmeP/LnDa/wxe4f8EY/n/BGP7/wRj+/8EY/v/BGP7/wRj+/8EY/v/MG7c/zJw3f8CZP3/AmT9/wJk/f8EY/f/AmT9/wJk/f8CZP3/AmT9/wJk/f8CZP3/AmT9/wJk/f8CZP3/AmT9/zJw3f8cVMRQM3He/zh03v84dN7/OHTe/zh03v84dN7/OHTe/zh03v84dN7/OHTe/zh03v84dN7/OHTe/zNx3v8cVMRQgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAAA==" />';
	startHTML +='<title>RSSy</title>\n';
	startHTML +='\n';
	startHTML +='\n\n\n';

let stopHTML ='\n\n\n';

var outALL ='';

var licznik =0;

function finishRSS(res,out,y,ile){
	outALL += out;
	licznik++
	console.log ('#164 licznik='+licznik,y,ile);
	if(licznik===ile) {
		let outM = '
'+outMENU+'
\n\n';
		console.log ('#167 outM='+outM);
		let alesHTML = startHTML+outM+outALL+stopHTML+'

';
		saveToFile(alesHTML);
		sendRSS2Browser(res,alesHTML);
		licznik=0;
	}
}
//readRSSY();

function sendRSS2Browser(res,alesHTML){
		res.send(alesHTML);
		res.end('
2 Koniec

');
		let czas = (new Date()).toLocaleString();

		//console.log ('#164 czas=',czas);
		console.log ('#### Poszło----------------------------------\n\n');

}

function saveToFile(alesHTML){
	let time = (new Date()).getTime();
	let czas = (new Date()).toLocaleString();
	let dat = '\n';

	fs.writeFile(rssFile, dat+alesHTML, function(err) {
		if(err) {
			return console.log(err);
		}
		console.log("#179 The file was saved!");
	});
}

let app = express();
let server  = require("http").createServer(app);
app.get("/*", function(req, res){
	outMENU = '
\n';
	outALL ='';

	//res.send('
hi
');
	readRSSY(res);
});
server.listen('8880',function(){console.log('------------------------------------\n  Listen on 8880\n------------------------------------\n\n');});

<commit_msg>Update rss.js<commit_after>#!/usr/local/bin/node
"use strict";
const moddir      = "/usr/local/lib/node_modules/";
const express     = require(moddir+"express");
const request     = require(moddir+"request");
const FeedParser  = require(moddir+"feedparser");
const testurlFeed = "http://www.guardian.co.uk/world/usa/rss";
const fs          = require('fs');
var rssFile       = __dirname+'/public/rss.html';
var outMENU = '
\n';
var cacheSecounds 	= 12*300;	// secounds 300= 5 minut
var rssHours 		= 6; 	// hours

console.log('~~~ Wait for /rssy.json',__dirname+'/rssy.json');
var strssy = fs.readFileSync(__dirname+'/rssy.json', 'utf8');
var rssy = JSON.parse(strssy);
//console.log(typeof(rssy),rssy);

function getFeed (urlfeed, callback) {
	let req = request (urlfeed);
	let feedparser = new FeedParser ();
	let feedItems = new Array ();
	req.on ("response", function (response) {
		let stream = this;
		if (response.statusCode == 200) {
			stream.pipe (feedparser);
			}
		});
	req.on ("error", function (err) {
		console.log ("getFeed: err.message == " + err.message);
		});
	feedparser.on ("readable", function () {
		try {
			let item = this.read (), flnew;
			if (item !== null) { //2/9/17 by DW
				feedItems.push (item);
				}
			}
		catch (err) {
			console.log ("getFeed: err.message == " + err.message);
			}
		});
	feedparser.on ("end", function () {
		callback (undefined, feedItems);
		});
	feedparser.on ("error", function (err) {
		console.log ("getFeed: err.message == " + err.message);
		callback (err);
		});
	}
		function pad (num) {
			let s = num.toString (), ctplaces = 4;
			while (s.length < ctplaces) {
				s = "0" + s;
				}
			return (s);
			}
//console.log ("\n" + myProductName + " v" + myVersion + ".\n");

/*=======================================*/
function readRSSY(res){
	let fromcache = false;
	// sprawdz czy jest plik
	if (fs.existsSync(rssFile)) {
		//sprawdz date
		fs.stat(rssFile, function(err, stats){
			let seconds = Math.round((new Date().getTime() - stats.mtime) / 1000);
			//console.log('#73==',seconds, new Date().getTime(),' - ',new Date(stats.mtime).getTime(),stats.mtime);
			console.log(`#73 File modified ${seconds} secunds ago`);
			if(seconds>cacheSecounds) {readRSSYfromWWW(res)}
			else {
				// zaladuj
				fs.readFile( rssFile, function (err, data) {
					if (err) {throw err; }
					//console.log(data.toString());
					sendRSS2Browser(res,data.toString());
					return;
				});
			}
		});
	}else {readRSSYfromWWW(res);}// is file
}

function readRSSYfromWWW(res){
	let artCount=1;
		rssy.forEach(function(item,y){
			outMENU += ''+item.title+'\n';
			let urlTestFeed = item.url;

			getFeed (urlTestFeed, function (err, feedItems) {
			if (!err) {
				let teraz = (new Date()).toLocaleString();
				let now   = (new Date()).getTime();
				let outHTML ='';
				outHTML+='
\n';
				outHTML+='
 ⇑ '+item.title+'
\n';
				for (let i = 0; i < feedItems.length; i++) {
					let pub   = (new Date(feedItems[i].date)).getTime();
					let delta = Math.round((now-pub)/3600000); // w godzinach
					if (delta>100) delta = 0;
					if (item.title != 'PAP' && delta>rssHours) continue;
					let czas  = (new Date(feedItems[i].date)).toLocaleString();// || (new Date(feedItems[i].pubdate)).toLocaleString() || (new Date(feedItems[i].pubDate)).toLocaleString();
					outHTML+='\n';
					outHTML+='
';
						outHTML+='
'+artCount+'. '+' ['+delta+'h] '+feedItems[i].title+'
\n';
						outHTML+=feedItems[i].summary;
					outHTML+='
\n\n';
					artCount++;
					}
					outHTML +='
\n';
					finishRSS(res,outHTML,y,rssy.length);
				}

			}); // getFeed

		});
}

let startHTML ='\n';
	startHTML +='<meta charset="utf-8">\n';
	startHTML +='<meta name="viewport" content="width=device-width,initial-scale=1">\n';
	startHTML +='<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAcVMRQNGjO/zhqz/84as//OGrP/zhqz/84as//OGrP/zhqz/84as//OGrP/zhqz/84as//OGrP/zRozv8cVMRQM2fO/x5b0v8eW9L/HlvS/x5b0v8eW9L/HlvS/x5b0v8eW9L/HlvS/x5b0v8eW9L/HlvS/x5b0v8eW9L/M2fO/y9m0P8dW9T/GlzY/4Kq7/+Vs+v/HVvU/x1b1P8cXNb/m7jv/x1b1P8dW9T/HVvU/xlc2f8dW9T/HVvU/y9m0P8pY9H/G1zX/4Gx/v///////////5Cy6P8bXNf/E2bv//////90nuP/G1zX/xRe4v/g7P//n7zs/xpc1/8pY9H/I2DT/xdd3f+Bsf7///////////+Xt+r/GFzZ/zWA+P//////ToTb/xld2/8QX+f//////6bB7f8YXNn/I2DT/x5e1P8WXd7/FF7h/5W48f+Xt+r/E1rP/xRe4P/Y5////////xNb0f8WXd7/GGvz//////9rmOD/Fl3e/x5e1P8ZW9X/FF7i/xRe4v8UXuL/E17g/xRe4v9xqP3//////4mt5v8UXt//FF7i/1qZ/P//////MG/W/xRe4v8ZW9X/FlrV/xFf5v8RX+b/FmXp/zp/8f/Y5////////9Lg9v8ZYtr/EV/m/wxg7P/3+v//8PX8/xJd2P8RX+b/FlrV/xdb1/8OYOr/kLv+/////////////////4it5/8YYtz/D2Dp/w9g6f9xp/7//////06D2v8PYOj/D2Dp/xdb1/8bXtf/DGHt/whi8/94pOr/TIXe/xFc1f8NYOj/DGHt/wxh7f8ygPz//////+Hr+f8QXNn/DGHt/wxh7f8bXtf/IGLZ/wph8f8KYfH/CmHx/wph8f8KYfH/CmHx/wph8v9xp/3///////////8SWs7/CmHx/wph8f8KYfH/IGLZ/yVm2v8IYvT/CGL0/whi9P8IYvT/Fmz2/1uZ+//3+v///////+Hr+v8SW8//CGL0/whi9P8IYvT/CGL0/yVm2v8ratv/BmP4/wRj+v/g7P//////////////////8PX+/06D2v8OXt3/BmP4/wZj+P8GY/j/BmP4/wZj+P8ratv/MG7c/wRj+/8EY/v/nb7y/6bC7/9qmeP/LnDa/wxe4f8EY/n/BGP7/wRj+/8EY/v/BGP7/wRj+/8EY/v/MG7c/zJw3f8CZP3/AmT9/wJk/f8EY/f/AmT9/wJk/f8CZP3/AmT9/wJk/f8CZP3/AmT9/wJk/f8CZP3/AmT9/zJw3f8cVMRQM3He/zh03v84dN7/OHTe/zh03v84dN7/OHTe/zh03v84dN7/OHTe/zh03v84dN7/OHTe/zNx3v8cVMRQgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAAA==" />';
	startHTML +='<title>RSSy</title>\n';
	startHTML +='\n';
	startHTML +='\n\n\n';

let stopHTML ='\n\n\n';

var outALL ='';

var licznik =0;

function finishRSS(res,out,y,ile){
	outALL += out;
	licznik++
	console.log ('#164 licznik='+licznik,y,ile);
	if(licznik===ile) {
		let outM = '
'+outMENU+'
\n\n';
		//console.log ('#167 outM='+outM);
		let alesHTML = startHTML+outM+outALL+stopHTML+'

';
		saveToFile(alesHTML);
		sendRSS2Browser(res,alesHTML);
		licznik=0;
	}
}
//readRSSY();

function sendRSS2Browser(res,alesHTML){
		res.send(alesHTML);
		res.end('
 Koniec

');
		let czas = (new Date()).toLocaleString();

		//console.log ('#164 czas=',czas);
		console.log ('#### Poszło----------------------------------\n\n');

}

function saveToFile(alesHTML){
	let time = (new Date()).getTime();
	let czas = (new Date()).toLocaleString();
	let dat = '\n';

	fs.writeFile(rssFile, dat+alesHTML, function(err) {
		if(err) {
			return console.log(err);
		}
		console.log("#179 The file was saved!");
	});
}

let app = express();
let server  = require("http").createServer(app);
app.get("/*", function(req, res){
	outMENU = '
\n';
	outALL ='';

	//res.send('
hi
');
	readRSSY(res);
});
server.listen('8880',function(){console.log('------------------------------------\n  Listen on 8880\n------------------------------------\n');});

<|endoftext|>


<commit_before>var posts = [];
var post_index = 0;
var post_count = 0;
var map;  // Google map object (global variable)

var lat;
var lng;

function setCookie() {
    var exdays = 1;
    var d = new Date();
    d.setTime(d.getTime() + (exdays*24*60*60*1000));
    var expires = "expires="+d.toUTCString();
    document.cookie = "cookie" + "=" + "!!!!" + "; " + expires;
}

function left_card() {
  post_index = (post_index + post_count - 1) % post_count;
  retrieve_comments();
  retrieve_map();
}

function right_card() {
  post_index = (post_index + post_count + 1) % post_count;
  if(post_index == post_count - 3) {
    retrieve_posts();
  }
  retrieve_comments();
  retrieve_map();
}

function retrieve_map() {
  $.get("http://bounce9833.azurewebsites.net/api/post_bounces", {post_id: posts[post_index]._id}, function(bounces) {
    console.log(bounces);
    console.log(bounces[0]);
    console.log(bounces[0].loc);
    // Create a Google coordinate object for where to center the map
    var latlngCenter = new google.maps.LatLng({lng: bounces[0].loc[0], lat: bounces[0].loc[1]} ); // Coordinates of Washington, DC (area centroid)

    // Map options for how to display the Google map
    var mapOptions = { zoom: 12, center: latlngCenter  };

    // Show the Google map in the div with the attribute id 'map-canvas'.
    map = new google.maps.Map(document.getElementById(posts[post_index]._id + 'right'), mapOptions);

    for(var i = 0; i < bounces.length; i++) {
      var latlng = {lat: bounces[i].loc[1], lng: bounces[i].loc[0]};
      var marker = new google.maps.Marker({
        position: latlng,
        map: map,
      });
    }
  });
}

function retrieve_comments() {
  $.get("http://bounce9833.azurewebsites.net/api/comment", {post_id: posts[post_index]._id}, function(comments) {
    var commentString = "";
    for (var i=0; i<comments.length; i++) {
      commentString += '
' + comments[i].text + '
';
    }
    commentString += "
<input type='text' id='" + posts[post_index]._id + "comment' placeholder='Comment'></input> Send";
    $('#' + posts[post_index]._id + 'left').html(commentString);
    return comments;
  });
}

function retrieve_posts() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    var lat = parseFloat(geoloc.coords.latitude);
    var lng = parseFloat(geoloc.coords.longitude);
    $.get("http://bounce9833.azurewebsites.net/api/post", {lat: lat, lng: lng, offset: post_count}, function(new_posts) {
      posts = posts.concat(new_posts);
      post_count = posts.length;
      if (posts.length == 0) {
        $("#card-view").append("

No Posts

");
      } else {
        for(var i = 0; i < new_posts.length; i++) {
          if (i == 0) {
            $("#card-view").append("
" +
                                 "
" +
                                  "
" +
                                    "
" + new_posts[i].text + "
" +
                                    "
Loading..
" +
                                  "
" +
                                  "
Loading..
" +
                                "
" +
                              "
");
          } else {
            $("#card-view").append("
" +
                                 "
" +
                                  "
" +
                                    "
" + new_posts[i].text + "
" +
                                    "
Loading..
" +
                                  "
" +
                                  "
Loading..
" +
                                "
" +
                              "
");
          }
        }
      }
    });
  });
  setTimeout(function() {
    retrieve_comments();
    retrieve_map();
  }, 2000);
}

function new_text_post() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    var lat = parseFloat(geoloc.coords.latitude);
    var lng = parseFloat(geoloc.coords.longitude);
    var text = document.getElementById('text').value;
    new_post(text, document.cookie, lat, lng);
  });
}

function new_post(text, uid, lat, lng) {
  $.post("http://bounce9833.azurewebsites.net/api/post", {text: text, user_id: uid, lat: lat, lng: lng}, function(message) {
    console.log(message);
  });
}

function add_comment() {
  var text = document.getElementById(posts[post_index]._id + 'comment').value;
  $.post("http://bounce9833.azurewebsites.net/api/comment", {post_id: posts[post_index]._id, user_id: document.cookie, text: text}, function(message) {
    console.log(message);
  })
  retrieve_comments();
}

function bounce() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    var lat = parseFloat(geoloc.coords.latitude);
    var lng = parseFloat(geoloc.coords.longitude);
    $.post("http://bounce9833.azurewebsites.net/api/bounce", {lat: lat, lng: lng, user_id: document.cookie, post_id: posts[post_index]._id}, function(message) {
      console.log(message);
    })
  });
}

function set_latlng() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    lat = geoloc.coords.latitude;
    lng = geoloc.coords.longitude;
  });

}

$(document).ready(function() {
  retrieve_posts();
})
<commit_msg>added call to cookie set on load<commit_after>var posts = [];
var post_index = 0;
var post_count = 0;
var map;  // Google map object (global variable)

var lat;
var lng;

function setCookie() {
    var exdays = 1;
    var d = new Date();
    d.setTime(d.getTime() + (exdays*24*60*60*1000));
    var expires = "expires="+d.toUTCString();
    document.cookie = "cookie" + "=" + "!!!!" + "; " + expires;
}

function left_card() {
  post_index = (post_index + post_count - 1) % post_count;
  retrieve_comments();
  retrieve_map();
}

function right_card() {
  post_index = (post_index + post_count + 1) % post_count;
  if(post_index == post_count - 3) {
    retrieve_posts();
  }
  retrieve_comments();
  retrieve_map();
}

function retrieve_map() {
  $.get("http://bounce9833.azurewebsites.net/api/post_bounces", {post_id: posts[post_index]._id}, function(bounces) {
    console.log(bounces);
    console.log(bounces[0]);
    console.log(bounces[0].loc);
    // Create a Google coordinate object for where to center the map
    var latlngCenter = new google.maps.LatLng({lng: bounces[0].loc[0], lat: bounces[0].loc[1]} ); // Coordinates of Washington, DC (area centroid)

    // Map options for how to display the Google map
    var mapOptions = { zoom: 12, center: latlngCenter  };

    // Show the Google map in the div with the attribute id 'map-canvas'.
    map = new google.maps.Map(document.getElementById(posts[post_index]._id + 'right'), mapOptions);

    for(var i = 0; i < bounces.length; i++) {
      var latlng = {lat: bounces[i].loc[1], lng: bounces[i].loc[0]};
      var marker = new google.maps.Marker({
        position: latlng,
        map: map,
      });
    }
  });
}

function retrieve_comments() {
  $.get("http://bounce9833.azurewebsites.net/api/comment", {post_id: posts[post_index]._id}, function(comments) {
    var commentString = "";
    for (var i=0; i<comments.length; i++) {
      commentString += '
' + comments[i].text + '
';
    }
    commentString += "
<input type='text' id='" + posts[post_index]._id + "comment' placeholder='Comment'></input> Send";
    $('#' + posts[post_index]._id + 'left').html(commentString);
    return comments;
  });
}

function retrieve_posts() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    var lat = parseFloat(geoloc.coords.latitude);
    var lng = parseFloat(geoloc.coords.longitude);
    $.get("http://bounce9833.azurewebsites.net/api/post", {lat: lat, lng: lng, offset: post_count}, function(new_posts) {
      posts = posts.concat(new_posts);
      post_count = posts.length;
      if (posts.length == 0) {
        $("#card-view").append("

No Posts

");
      } else {
        for(var i = 0; i < new_posts.length; i++) {
          if (i == 0) {
            $("#card-view").append("
" +
                                 "
" +
                                  "
" +
                                    "
" + new_posts[i].text + "
" +
                                    "
Loading..
" +
                                  "
" +
                                  "
Loading..
" +
                                "
" +
                              "
");
          } else {
            $("#card-view").append("
" +
                                 "
" +
                                  "
" +
                                    "
" + new_posts[i].text + "
" +
                                    "
Loading..
" +
                                  "
" +
                                  "
Loading..
" +
                                "
" +
                              "
");
          }
        }
      }
    });
  });
  setTimeout(function() {
    retrieve_comments();
    retrieve_map();
  }, 2000);
}

function new_text_post() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    var lat = parseFloat(geoloc.coords.latitude);
    var lng = parseFloat(geoloc.coords.longitude);
    var text = document.getElementById('text').value;
    new_post(text, document.cookie, lat, lng);
  });
}

function new_post(text, uid, lat, lng) {
  $.post("http://bounce9833.azurewebsites.net/api/post", {text: text, user_id: uid, lat: lat, lng: lng}, function(message) {
    console.log(message);
  });
}

function add_comment() {
  var text = document.getElementById(posts[post_index]._id + 'comment').value;
  $.post("http://bounce9833.azurewebsites.net/api/comment", {post_id: posts[post_index]._id, user_id: document.cookie, text: text}, function(message) {
    console.log(message);
  })
  retrieve_comments();
}

function bounce() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    var lat = parseFloat(geoloc.coords.latitude);
    var lng = parseFloat(geoloc.coords.longitude);
    $.post("http://bounce9833.azurewebsites.net/api/bounce", {lat: lat, lng: lng, user_id: document.cookie, post_id: posts[post_index]._id}, function(message) {
      console.log(message);
    })
  });
}

function set_latlng() {
  navigator.geolocation.getCurrentPosition(function(geoloc) {
    lat = geoloc.coords.latitude;
    lng = geoloc.coords.longitude;
  });

}

$(document).ready(function() {
  setCookie();
  retrieve_posts();
})
<|endoftext|>


<commit_before>#!/usr/bin/env node

var server = require('./src/server')

var config = {
  timeout: process.env.CRUDIVORE_TIMEOUT,
  pollInterval: process.env.CRUDIVORE_POLL_INTERVAL,
  phantomPortRange: {
    start: process.env.CRUDIVORE_PHANTOM_PORT_START || 10000,
    end:  process.env.CRUDIVORE_PHANTOM_PORT_END || 10100
  },
  initialThreadCount: process.env.CRUDIVORE_INITIAL_THREAD_COUNT
}

server(config)<commit_msg>Make index.js executable<commit_after>#!/usr/bin/env node

var server = require('./src/server')

var config = {
  timeout: process.env.CRUDIVORE_TIMEOUT,
  pollInterval: process.env.CRUDIVORE_POLL_INTERVAL,
  phantomPortRange: {
    start: process.env.CRUDIVORE_PHANTOM_PORT_START || 10000,
    end:  process.env.CRUDIVORE_PHANTOM_PORT_END || 10100
  },
  initialThreadCount: process.env.CRUDIVORE_INITIAL_THREAD_COUNT
}

server(config)<|endoftext|>


<commit_before>function HtmlReplaceWebpackPlugin(options)
{
  options = Array.isArray(options) ? options : [options]

  options.forEach(function(option)
  {
    if(typeof option.pattern == 'undefined' ||
      typeof option.replacement == 'undefined')
    {
      throw new Error('Both `pattern` and `replacement` options must be defined!')
    }
  })

  this.replace = function(htmlData)
  {
    options.forEach(function(option)
    {
      if(typeof option.replacement === 'function')
      {
        var matches = null;
        var isPatternValid = true;
          try {
              new RegExp(option.pattern);
          } catch(e) {
              isPatternValid = false;
          }

        if(!isPatternValid) throw new Error("Invalid `pattern` option provided, it must be a valid regex.");
        while((matches = option.pattern.exec(htmlData)) != null)
        {
          var replacement = option.replacement.apply(null, matches)

          // matches[0]: matching content string
          htmlData = htmlData.replace(matches[0], replacement)
        }
      }
      else
      {
        // htmlData = htmlData.replace(option.pattern, option.replacement)
        htmlData = htmlData.split(option.pattern).join(option.replacement)
      }
    })
    return htmlData
  }
}

HtmlReplaceWebpackPlugin.prototype.apply = function(compiler)
{
  var _this = this
  compiler.plugin('compilation', function(compilation)
  {
    // console.log('The compiler is starting a new compilation...')
    compilation.plugin('html-webpack-plugin-before-html-processing',
      function(htmlPluginData, callback)
      {
        htmlPluginData.html = _this.replace(htmlPluginData.html)
        callback(null, htmlPluginData)
      })
  })
}

module.exports = HtmlReplaceWebpackPlugin
<commit_msg>feature(webpack4): upgrade plugin for Webpack 4 compatibility<commit_after>function HtmlReplaceWebpackPlugin(options)
{
  options = Array.isArray(options) ? options : [options]

  options.forEach(function(option)
  {
    if(typeof option.pattern == 'undefined' ||
      typeof option.replacement == 'undefined')
    {
      throw new Error('Both `pattern` and `replacement` options must be defined!')
    }
  })

  this.replace = function(htmlData)
  {
    options.forEach(function(option)
    {
      if(typeof option.replacement === 'function')
      {
        var matches = null;
        var isPatternValid = true;
          try {
              new RegExp(option.pattern);
          } catch(e) {
              isPatternValid = false;
          }

        if(!isPatternValid) throw new Error("Invalid `pattern` option provided, it must be a valid regex.");
        while((matches = option.pattern.exec(htmlData)) != null)
        {
          var replacement = option.replacement.apply(null, matches)

          // matches[0]: matching content string
          htmlData = htmlData.replace(matches[0], replacement)
        }
      }
      else
      {
        // htmlData = htmlData.replace(option.pattern, option.replacement)
        htmlData = htmlData.split(option.pattern).join(option.replacement)
      }
    })
    return htmlData
  }
}

HtmlReplaceWebpackPlugin.prototype.apply = function(compiler)
{
  var _this = this
  compiler.hooks.compilation.tap('HtmlReplaceWebpackPlugin', function(compilation)
  {
    // console.log('The compiler is starting a new compilation...')
    compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync('html-webpack-plugin-before-html-processing',
      function(htmlPluginData, callback)
      {
        htmlPluginData.html = _this.replace(htmlPluginData.html)
        callback(null, htmlPluginData)
      })
  })
}

module.exports = HtmlReplaceWebpackPlugin
<|endoftext|>


<commit_before>import {
  moduleForModel,
  test
} from 'ember-qunit';
import modelList from '../../helpers/model-list';
import Ember from 'ember';

moduleForModel('cohort', 'Cohort', {
  setup: function(){
  },
  needs: modelList
});

test('it exists', function(assert) {
  var model = this.subject();
  // var store = this.store();
  assert.ok(!!model);
});

test('list top level groups', function(assert) {
  assert.expect(3);
  var model = this.subject();
  model.set('i18n.locale', 'en');

  var store = model.store;
  Ember.run(function(){

    var topGroup1 = store.createRecord('learner-group', {title:'Top Group 1', cohort: model});
    var topGroup2 = store.createRecord('learner-group', {title:'Top Group 2', cohort: model});

    var group1 = store.createRecord('learner-group', {title:'Group 1', cohort: model, parent: topGroup1});
    var group2 = store.createRecord('learner-group', {title:'Group 2', cohort: model, parent: topGroup1});
    var group3 = store.createRecord('learner-group', {title:'Group 3', cohort: model, parent: topGroup2});
    var group4 = store.createRecord('learner-group', {title:'Group 4', cohort: model, parent: topGroup2});

    model.get('learnerGroups').then(function(groups){
      groups.pushObject(group1);
      groups.pushObject(group2);
      groups.pushObject(group3);
      groups.pushObject(group4);
      groups.pushObject(topGroup1);
      groups.pushObject(topGroup2);
    });
  });

  Ember.run(function(){
    model.get('topLevelLearnerGroups').then(function(topLevelGroups){
      assert.equal(topLevelGroups.length, 2);
      assert.equal(topLevelGroups.objectAt(0).get('title'), 'Top Group 1');
      assert.equal(topLevelGroups.objectAt(1).get('title'), 'Top Group 2');
    });
  });

});
//
// test('get display title', function(assert) {
//   assert.expect(2);
//   var model = this.subject();
//
//   var store = model.store;
//
//   Ember.run(function(){
//     var program = store.createRecord('program', {duration: 4});
//     var programYear = store.createRecord('program-year', {startYear:'2000', program: program, cohort: model});
//     model.set('programYear', programYear);
//   });
//
//   Ember.run(function(){
//     var displayTitle = model.get('displayTitle');
//     assert.equal(displayTitle, 'Class of 2004');
//   });
//
//   Ember.run(function(){
//     model.set('title', 'testtitle');
//     var displayTitle = model.get('displayTitle');
//     assert.equal(displayTitle, 'testtitle');
//   });
//
// });
<commit_msg>Re-add services that are needed for the cohort model test<commit_after>import {
  moduleForModel,
  test
} from 'ember-qunit';
import modelList from '../../helpers/model-list';
import Ember from 'ember';

let needs = modelList;
needs.pushObject('service:i18n');
needs.pushObject('locale:en/translations');

moduleForModel('cohort', 'Cohort', {
  needs
});

test('it exists', function(assert) {
  var model = this.subject();
  // var store = this.store();
  assert.ok(!!model);
});

test('list top level groups', function(assert) {
  assert.expect(3);
  var model = this.subject();
  model.set('i18n.locale', 'en');

  var store = model.store;
  Ember.run(function(){

    var topGroup1 = store.createRecord('learner-group', {title:'Top Group 1', cohort: model});
    var topGroup2 = store.createRecord('learner-group', {title:'Top Group 2', cohort: model});

    var group1 = store.createRecord('learner-group', {title:'Group 1', cohort: model, parent: topGroup1});
    var group2 = store.createRecord('learner-group', {title:'Group 2', cohort: model, parent: topGroup1});
    var group3 = store.createRecord('learner-group', {title:'Group 3', cohort: model, parent: topGroup2});
    var group4 = store.createRecord('learner-group', {title:'Group 4', cohort: model, parent: topGroup2});

    model.get('learnerGroups').then(function(groups){
      groups.pushObject(group1);
      groups.pushObject(group2);
      groups.pushObject(group3);
      groups.pushObject(group4);
      groups.pushObject(topGroup1);
      groups.pushObject(topGroup2);
    });
  });

  Ember.run(function(){
    model.get('topLevelLearnerGroups').then(function(topLevelGroups){
      assert.equal(topLevelGroups.length, 2);
      assert.equal(topLevelGroups.objectAt(0).get('title'), 'Top Group 1');
      assert.equal(topLevelGroups.objectAt(1).get('title'), 'Top Group 2');
    });
  });

});
//
// test('get display title', function(assert) {
//   assert.expect(2);
//   var model = this.subject();
//
//   var store = model.store;
//
//   Ember.run(function(){
//     var program = store.createRecord('program', {duration: 4});
//     var programYear = store.createRecord('program-year', {startYear:'2000', program: program, cohort: model});
//     model.set('programYear', programYear);
//   });
//
//   Ember.run(function(){
//     var displayTitle = model.get('displayTitle');
//     assert.equal(displayTitle, 'Class of 2004');
//   });
//
//   Ember.run(function(){
//     model.set('title', 'testtitle');
//     var displayTitle = model.get('displayTitle');
//     assert.equal(displayTitle, 'testtitle');
//   });
//
// });
<|endoftext|>


<commit_before>/**
 * @overview Wraps NetSim REST API by extending our standard client API.
 * @see clientApi.js
 * @see net_sim_api.rb
 */
/* jshint
 funcscope: true,
 newcap: true,
 nonew: true,
 shadow: false,

 maxlen: 90,
 maxparams: 3,
 maxstatements: 200
 */
/* global $ */
'use strict';

var clientApi = require('@cdo/shared/clientApi');

/**
 * @name NetSimApi
 * @extends ClientApi
 */
var newApi = {
  /**
   * Base URL for target API.
   * @type {string}
   */
  api_base_url: "/v3/channels",

  /**
   * Request all rows including and following the given row ID.
   * @param {int} rowID - lower bound on row IDs to fetch
   * @param {NodeStyleCallback} callback - Expected result is an array of
   *        table rows.
   */
  allFromID: function(rowID, callback) {
    $.ajax({
      url: this.api_base_url + '@' + rowID,
      type: "get",
      dataType: "json"
    }).done(function(data, text) {
      callback(null, data);
    }).fail(function(request, status, error) {
      var err = new Error('status: ' + status + '; error: ' + error);
      callback(err, null);
    });
  }
};

module.exports = {
  /**
   * Create a NetSimApi instance with the given base URL, built by modifying
   * a ClientApi instance with the same base URL.
   * @param {!string} url - Custom API base url (e.g. '/v3/netsim')
   * @returns {NetSimApi}
   */
  create: function (url) {
    return $.extend(clientApi.create(url), newApi, {
      api_base_url: url
    });
  }
};
<commit_msg>NetSimApi fully reimplments clientApi in anticipation of future divergence<commit_after>/**
 * @overview Wraps NetSim REST API by extending our standard client API.
 * @see clientApi.js
 * @see net_sim_api.rb
 */
/* jshint
 funcscope: true,
 newcap: true,
 nonew: true,
 shadow: false,

 maxlen: 90,
 maxparams: 3,
 maxstatements: 200
 */
/* global $ */
'use strict';

/**
 * @name NetSimApi
 * @extends ClientApi
 */
var netsimApi = {
  /**
   * Base URL for target API.
   * Must be set through NetSimApi.create().
   * @type {string}
   */
  api_base_url: undefined,

  /**
   * Request all rows from the given table.
   * @param {NodeStyleCallback} callback - Expected result is an array of
   *        collection objects.
   */
  all: function(callback) {
    $.ajax({
      url: this.api_base_url,
      type: "get",
      dataType: "json"
    }).done(function(data, text) {
      callback(null, data);
    }).fail(function(request, status, error) {
      var err = new Error('status: ' + status + '; error: ' + error);
      callback(err, null);
    });
  },

  /**
   * Request all rows including and following the given row ID.
   * @param {int} rowID - lower bound on row IDs to fetch
   * @param {NodeStyleCallback} callback - Expected result is an array of
   *        table rows.
   */
  allFromID: function(rowID, callback) {
    $.ajax({
      url: this.api_base_url + '@' + rowID,
      type: "get",
      dataType: "json"
    }).done(function(data, text) {
      callback(null, data);
    }).fail(function(request, status, error) {
      var err = new Error('status: ' + status + '; error: ' + error);
      callback(err, null);
    });
  },

  /**
   * Insert a row.
   * @param {Object} value - collection contents, must be JSON.stringify-able.
   * @param {NodeStyleCallback} callback - Expected result is the created
   *        collection object (which will include an assigned 'id' key).
   */
  create: function(value, callback) {
    $.ajax({
      url: this.api_base_url,
      type: "post",
      contentType: "application/json; charset=utf-8",
      data: JSON.stringify(value)
    }).done(function(data, text) {
      callback(null, data);
    }).fail(function(request, status, error) {
      var err = new Error('status: ' + status + '; error: ' + error);
      callback(err, undefined);
    });
  },

  /**
   * Remove a row.
   * @param {number} id - The collection identifier.
   * @param {NodeStyleCallback} callback - Expected result is TRUE.
   */
  delete: function(id, callback) {
    $.ajax({
      url: this.api_base_url + "/" + id + "/delete",
      type: "post",
      dataType: "json"
    }).done(function(data, text) {
      callback(null, true);
    }).fail(function(request, status, error) {
      var err = new Error('status: ' + status + '; error: ' + error);
      callback(err, false);
    });
  },

  /**
   * Retrieve a row.
   * @param {number} id - The collection identifier.
   * @param {NodeStyleCallback} callback - Expected result is the requested
   *        collection object.
   */
  fetch: function(id, callback) {
    $.ajax({
      url: this.api_base_url + "/" + id,
      type: "get",
      dataType: "json",
    }).done(function(data, text) {
      callback(null, data);
    }).fail(function(request, status, error) {
      var err = new Error('status: ' + status + '; error: ' + error);
      callback(err, undefined);
    });
  },

  /**
   * Change the contents of a row.
   * @param {number} id - The collection identifier.
   * @param {Object} value - The new collection contents.
   * @param {NodeStyleCallback} callback - Expected result is the new collection
   *        object.
   */
  update: function(id, value, callback) {
    $.ajax({
      url: this.api_base_url + "/" + id,
      type: "post",
      contentType: "application/json; charset=utf-8",
      data: JSON.stringify(value)
    }).done(function(data, text) {
      callback(null, data);
    }).fail(function(request, status, error) {
      var err = new Error('status: ' + status + '; error: ' + error);
      callback(err, false);
    });
  }
};

module.exports = {
  /**
   * Create a NetSimApi instance with the given base URL.
   * @param {!string} url - Custom API base url (e.g. '/v3/netsim')
   * @returns {NetSimApi}
   */
  create: function (url) {
    return $.extend({}, netsimApi, {
      api_base_url: url
    });
  }
};
<|endoftext|>


<commit_before>// Game parameters
var DEBUG = false;
var cell_size = 50;
var block_size = 3 * cell_size;

// Color palette: http://paletton.com/#uid=33g0u0krPrxh6ySlZtltwlLzxgR
var cell_border = "#00534C";
var cell_number = "#086B63";
var cell_number_locked = "#00534C";
var cell_number_selected = "#865800";
var cell_number_colliding = "#840007";
var cell_fill = "#2D9088";
var cell_fill_selected = "#DB9A1D";
var cell_fill_colliding = "#D81C25";
var thick_lines = "#00534C";

var selection = 0;
var game = {board: 'undefined', locked: 'undefined'};
var ctx;
var boxes = [[  0,  1,  2,  9, 10, 11, 18, 19, 20],
             [  3,  4,  5, 12, 13, 14, 21, 22, 23],
             [  6,  7,  8, 15, 16, 17, 24, 25, 26],
             [ 27, 28, 29, 36, 37, 38, 45, 46, 47],
             [ 30, 31, 32, 39, 40, 41, 48, 49, 50],
             [ 33, 34, 35, 42, 43, 44, 51, 52, 53],
             [ 54, 55, 56, 63, 64, 65, 72, 73, 74],
             [ 57, 58, 59, 66, 67, 68, 75, 76, 77],
             [ 60, 61, 62, 69, 70, 71, 78, 79, 80]];

var main = function() {
    var canvas = document.getElementById("sudoku");
    ctx = canvas.getContext("2d");
    var solved = false;
    while(!solved) {
        createEmptyBoard(game);
        solved = generateSolution(game);
    }
    digHoles(game);
    drawBoard(ctx, 0, 0, game);
    canvas.setAttribute("tabindex", "0");
    canvas.addEventListener("keydown", function(e) {
        processKeys(e, game);
    });
    canvas.focus();
}

var drawCell = function(ctx, x, y, n, selected, colliding, locked) {
    ctx.lineWidth = 1;
    if(selected) {
        ctx.fillStyle = cell_fill_selected;
    } else if(colliding && locked) {
        ctx.fillStyle = cell_fill;
    } else if(colliding) {
        ctx.fillStyle = cell_fill_colliding;
    } else {
        ctx.fillStyle = cell_fill;
    }
    ctx.strokeStyle = cell_border;
    ctx.fillRect(x, y, cell_size, cell_size);
    ctx.strokeRect(x, y, cell_size, cell_size);
    ctx.font = "bold " + cell_size * 0.8 + "px sans-serif";
    ctx.textBaseline = "middle";
    ctx.textAlign = "center";
    if(colliding) {
        ctx.fillStyle = cell_number_colliding;
    } else if(selected) {
        ctx.fillStyle = cell_number_selected;
    } else if(locked) {
        ctx.fillStyle = cell_number_locked;
    } else {
        ctx.fillStyle = cell_number;
    }
    ctx.fillText(n, x + cell_size / 2, y + cell_size / 2);
}

var drawUpdated = function(ctx, oldSelection, newSelection, game) {
    // Draw previous selection as unselected
    var cellX = 0 + Math.floor(oldSelection / 9) * cell_size;
    var cellY = 0 + (oldSelection % 9) * cell_size;
    var number = (game.board[oldSelection] !== 0 ? game.board[oldSelection] : "");
    var colliding = (getCollisions(game, oldSelection).length > 0 ? true : false);
    var locked = (game.locked[newSelection] !== 0 ? true : false);
    drawCell(ctx, cellX, cellY, number, false, colliding, locked);

    // Draw new selection
    var cellX = 0 + Math.floor(newSelection / 9) * cell_size;
    var cellY = 0 + (newSelection % 9) * cell_size;
    var number = (game.board[newSelection] !== 0 ? game.board[newSelection] : "");
    var colliding = (getCollisions(game, newSelection).length > 0 ? true : false);
    var locked = (game.locked[newSelection] !== 0 ? true : false);
    drawCell(ctx, cellX, cellY, number, true, colliding, locked);
}

var drawBoard = function(ctx, x, y, game) {
    for(cell = 0; cell < 81; cell++) {
        var cellX = x + Math.floor(cell / 9) * cell_size;
        var cellY = y + (cell % 9) * cell_size;
        var number = (game.board[cell] !== 0 ? game.board[cell] : "");
        var selected = (cell == selection) ? true : false;
        var colliding = (getCollisions(game, cell).length > 0 ? true : false);
        var locked = (game.locked[cell] !== 0 ? true : false);
        drawCell(ctx, cellX, cellY, number, selected, colliding, locked);
    }
    drawThickLines(ctx);
}

var drawThickLines = function(ctx) {
    ctx.lineWidth = cell_size / 10;
    ctx.strokeStyle = thick_lines;
    for(i = 0; i < 4; i++) {
        ctx.moveTo(0, i * block_size);
        ctx.lineTo(3 * block_size, i * block_size);
    }
    for(i = 0; i < 4; i++) {
        ctx.moveTo(i * block_size, 0);
        ctx.lineTo(i * block_size, 3 * block_size);
    }
    ctx.stroke();
}

var createEmptyBoard = function(game) {
    game.board = new Array(81);
    for(i = 0; i < 81; i++) game.board[i] = 0;
    game.locked = new Array(81);
    for(i = 0; i < 81; i++) game.locked[i] = 0;
}

var generateSolution = function(game) {
    var untried = new Array(81);
    for(i = 0; i < 81; i++) {
        untried[i] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    }
    var i = 0;
    while(i < 81) {
        var nextToTry;
        if(untried[i].length > 0) {
            nextToTry = untried[i].splice([Math.floor(Math.random() * untried[i].length)], 1)[0];
        }
        game.board[i] = nextToTry;
        if(getCollisions(game, i).length > 0) {
            if(untried[i].length > 0) {
                continue;
            } else {
                untried[i] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
                i--;
                if(i < 0) {
                    return false;
                }
            }
        } else {
            i++;
        }
    }
    return true;
}

var digHoles = function(game) {
    for(i = 0; i < 35; i++) {
        var randomPick = Math.floor(Math.random() * game.board.length);
        game.locked[randomPick] = game.board[randomPick];
    }
    for(i = 0; i < 81; i++) {
        if(game.locked[i] === 0) game.board[i] = 0;
    }
}

var getCollisions = function(game, check_index) {
    var collisions = new Array();

    if(game.board[check_index] === 0) return collisions;

    //check row
    var row = Math.floor(check_index / 9);
    for(i = (row * 9); i < (row * 9 + 9); i++) {
        if(i != check_index &&
           game.board[i] === game.board[check_index] &&
           game.board[check_index] !== 0) {
            if(collisions.indexOf(i) === -1) {
                collisions.push(i);
            }
        }
    }

    //check column
    var col = check_index % 9;
    for(i = col; i < 73 + col; i += 9) {
        if(i != check_index &&
           game.board[i] === game.board[check_index] &&
           game.board[check_index] !== 0) {
            if(collisions.indexOf(i) == -1) {
                collisions.push(i);
            }
        }
    }

    //check box
    var box_index;
    for(i = 0; i < 9; i++) {
        if(boxes[i].indexOf(check_index) != -1) {
            box_index = i;
            break;
        }
    }
    for(j = 0; j < 9; j++) {
        var box_cell = boxes[box_index][j];
        if(box_cell != check_index &&
           game.board[box_cell] === game.board[check_index] &&
           game.board[check_index] !== 0) {
            if(collisions.indexOf(box_cell) == -1) {
                collisions.push(box_cell);
            }
        }
    }
    return collisions;
}

var checkAll = function(game) {
    var ok = true;
    for(p = 0; p < 81; p++) {
        var collisions = getCollisions(game, p);
        if(collisions.length > 0) {
            ok = false;
            break;
        }
    }
    return ok;
}

var processKeys = function(e, game) {
    var oldSelection = selection;
    switch(e.keyCode) {
        case 38:
            if((selection % 9) > 0) selection--;
            break;
        case 40:
            if((selection % 9) < 8) selection++;
            break;
        case 37:
            if(Math.floor(selection / 9) > 0) selection -= 9;
            break;
        case 39:
            if(Math.floor(selection / 9) < 8) selection += 9;
            break;
        case 27:
            selection.type = "none";
            break;
        case 46:
            if(game.locked[selection] === 0) game.board[selection] = 0;
            break;
        case 67:
            alert((checkAll(game) ? "Board is ok" : "Board is NOT ok"));
            break;
    }
    if(e.keyCode >= 49 && e.keyCode <= 57) {
            if(game.locked[selection] === 0) game.board[selection] = parseInt(String.fromCharCode(e.keyCode));
    }
    drawUpdated(ctx, oldSelection, selection, game);
    //drawBoard(ctx, 0, 0, game);
    drawThickLines(ctx);
}

main();
<commit_msg>Fix color bug<commit_after>// Game parameters
var DEBUG = false;
var cell_size = 50;
var block_size = 3 * cell_size;

// Color palette: http://paletton.com/#uid=33g0u0krPrxh6ySlZtltwlLzxgR
var cell_border = "#00534C";
var cell_number = "#086B63";
var cell_number_locked = "#00534C";
var cell_number_selected = "#865800";
var cell_number_colliding = "#840007";
var cell_fill = "#2D9088";
var cell_fill_selected = "#DB9A1D";
var cell_fill_colliding = "#D81C25";
var thick_lines = "#00534C";

var selection = 0;
var game = {
    board: 'undefined',
    locked: 'undefined',
    selection: 0,
    old_selection: 0
}
var ctx;
var boxes = [[  0,  1,  2,  9, 10, 11, 18, 19, 20],
             [  3,  4,  5, 12, 13, 14, 21, 22, 23],
             [  6,  7,  8, 15, 16, 17, 24, 25, 26],
             [ 27, 28, 29, 36, 37, 38, 45, 46, 47],
             [ 30, 31, 32, 39, 40, 41, 48, 49, 50],
             [ 33, 34, 35, 42, 43, 44, 51, 52, 53],
             [ 54, 55, 56, 63, 64, 65, 72, 73, 74],
             [ 57, 58, 59, 66, 67, 68, 75, 76, 77],
             [ 60, 61, 62, 69, 70, 71, 78, 79, 80]];

var main = function() {
    var canvas = document.getElementById("sudoku");
    ctx = canvas.getContext("2d");
    var solved = false;
    while(!solved) {
        createEmptyBoard(game);
        solved = generateSolution(game);
    }
    digHoles(game);
    drawBoard(ctx, 0, 0, game);
    canvas.setAttribute("tabindex", "0");
    canvas.addEventListener("keydown", function(e) {
        processKeys(e, game);
    });
    canvas.focus();
}

var drawCell = function(ctx, x, y, n, selected, colliding, locked) {
    ctx.lineWidth = 1;
    if(selected) {
        ctx.fillStyle = cell_fill_selected;
    } else if(colliding && locked) {
        ctx.fillStyle = cell_fill;
    } else if(colliding) {
        ctx.fillStyle = cell_fill_colliding;
    } else {
        ctx.fillStyle = cell_fill;
    }
    ctx.strokeStyle = cell_border;
    ctx.fillRect(x, y, cell_size, cell_size);
    ctx.strokeRect(x, y, cell_size, cell_size);
    ctx.font = "bold " + cell_size * 0.8 + "px sans-serif";
    ctx.textBaseline = "middle";
    ctx.textAlign = "center";
    if(colliding) {
        ctx.fillStyle = cell_number_colliding;
    } else if(selected) {
        ctx.fillStyle = cell_number_selected;
    } else if(locked) {
        ctx.fillStyle = cell_number_locked;
    } else {
        ctx.fillStyle = cell_number;
    }
    ctx.fillText(n, x + cell_size / 2, y + cell_size / 2);
}

var drawUpdated = function(ctx, oldSelection, newSelection, game) {
    // Draw previous selection as unselected
    var cellX = 0 + Math.floor(oldSelection / 9) * cell_size;
    var cellY = 0 + (oldSelection % 9) * cell_size;
    var number = (game.board[oldSelection] !== 0 ? game.board[oldSelection] : "");
    var colliding = (getCollisions(game, oldSelection).length > 0 ? true : false);
    var locked = (game.locked[oldSelection] !== 0 ? true : false);
    drawCell(ctx, cellX, cellY, number, false, colliding, locked);

    // Draw new selection
    cellX = 0 + Math.floor(newSelection / 9) * cell_size;
    cellY = 0 + (newSelection % 9) * cell_size;
    number = (game.board[newSelection] !== 0 ? game.board[newSelection] : "");
    colliding = (getCollisions(game, newSelection).length > 0 ? true : false);
    locked = (game.locked[newSelection] !== 0 ? true : false);
    drawCell(ctx, cellX, cellY, number, true, colliding, locked);
}

var drawBoard = function(ctx, x, y, game) {
    for(cell = 0; cell < 81; cell++) {
        var cellX = x + Math.floor(cell / 9) * cell_size;
        var cellY = y + (cell % 9) * cell_size;
        var number = (game.board[cell] !== 0 ? game.board[cell] : "");
        var selected = (cell == selection) ? true : false;
        var colliding = (getCollisions(game, cell).length > 0 ? true : false);
        var locked = (game.locked[cell] !== 0 ? true : false);
        drawCell(ctx, cellX, cellY, number, selected, colliding, locked);
    }
    drawThickLines(ctx);
}

var drawThickLines = function(ctx) {
    ctx.lineWidth = cell_size / 10;
    ctx.strokeStyle = thick_lines;
    for(i = 0; i < 4; i++) {
        ctx.moveTo(0, i * block_size);
        ctx.lineTo(3 * block_size, i * block_size);
    }
    for(i = 0; i < 4; i++) {
        ctx.moveTo(i * block_size, 0);
        ctx.lineTo(i * block_size, 3 * block_size);
    }
    ctx.stroke();
}

var createEmptyBoard = function(game) {
    game.board = new Array(81);
    for(i = 0; i < 81; i++) game.board[i] = 0;
    game.locked = new Array(81);
    for(i = 0; i < 81; i++) game.locked[i] = 0;
}

var generateSolution = function(game) {
    var untried = new Array(81);
    for(i = 0; i < 81; i++) {
        untried[i] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    }
    var i = 0;
    while(i < 81) {
        var nextToTry;
        if(untried[i].length > 0) {
            nextToTry = untried[i].splice([Math.floor(Math.random() * untried[i].length)], 1)[0];
        }
        game.board[i] = nextToTry;
        if(getCollisions(game, i).length > 0) {
            if(untried[i].length > 0) {
                continue;
            } else {
                untried[i] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
                i--;
                if(i < 0) {
                    return false;
                }
            }
        } else {
            i++;
        }
    }
    return true;
}

var digHoles = function(game) {
    for(i = 0; i < 35; i++) {
        var randomPick = Math.floor(Math.random() * game.board.length);
        game.locked[randomPick] = game.board[randomPick];
    }
    for(i = 0; i < 81; i++) {
        if(game.locked[i] === 0) game.board[i] = 0;
    }
}

var getCollisions = function(game, check_index) {
    var collisions = new Array();

    if(game.board[check_index] === 0) return collisions;

    //check row
    var row = Math.floor(check_index / 9);
    for(i = (row * 9); i < (row * 9 + 9); i++) {
        if(i != check_index &&
           game.board[i] === game.board[check_index] &&
           game.board[check_index] !== 0) {
            if(collisions.indexOf(i) === -1) {
                collisions.push(i);
            }
        }
    }

    //check column
    var col = check_index % 9;
    for(i = col; i < 73 + col; i += 9) {
        if(i != check_index &&
           game.board[i] === game.board[check_index] &&
           game.board[check_index] !== 0) {
            if(collisions.indexOf(i) == -1) {
                collisions.push(i);
            }
        }
    }

    //check box
    var box_index;
    for(i = 0; i < 9; i++) {
        if(boxes[i].indexOf(check_index) != -1) {
            box_index = i;
            break;
        }
    }
    for(j = 0; j < 9; j++) {
        var box_cell = boxes[box_index][j];
        if(box_cell != check_index &&
           game.board[box_cell] === game.board[check_index] &&
           game.board[check_index] !== 0) {
            if(collisions.indexOf(box_cell) == -1) {
                collisions.push(box_cell);
            }
        }
    }
    return collisions;
}

var checkAll = function(game) {
    var ok = true;
    for(p = 0; p < 81; p++) {
        var collisions = getCollisions(game, p);
        if(collisions.length > 0) {
            ok = false;
            break;
        }
    }
    return ok;
}

var processKeys = function(e, game) {
    var oldSelection = selection;
    switch(e.keyCode) {
        case 38:
            if((selection % 9) > 0) selection--;
            break;
        case 40:
            if((selection % 9) < 8) selection++;
            break;
        case 37:
            if(Math.floor(selection / 9) > 0) selection -= 9;
            break;
        case 39:
            if(Math.floor(selection / 9) < 8) selection += 9;
            break;
        case 27:
            selection.type = "none";
            break;
        case 46:
            if(game.locked[selection] === 0) game.board[selection] = 0;
            break;
        case 67:
            alert((checkAll(game) ? "Board is ok" : "Board is NOT ok"));
            break;
    }
    if(e.keyCode >= 49 && e.keyCode <= 57) {
            if(game.locked[selection] === 0) game.board[selection] = parseInt(String.fromCharCode(e.keyCode));
    }
    drawUpdated(ctx, oldSelection, selection, game);
    drawThickLines(ctx);
}

main();
<|endoftext|>


<commit_before>import { dbAdapter } from './models'
import { serializeUser } from './serializers/v2/user'

export class DummyPublisher {
  userUpdated() {}
  postCreated() {}
  postDestroyed() {}
  postUpdated() {}
  commentCreated() {}
  commentDestroyed() {}
  commentUpdated() {}
  likeAdded() {}
  likeRemoved() {}
  postHidden() {}
  postUnhidden() {}
  commentLikeAdded() {}
  commentLikeRemoved() {}
  globalUserUpdated() {}
}

export default class pubSub {
  constructor(publisher) {
    this.publisher = publisher
  }

  setPublisher(publisher) {
    this.publisher = publisher;
  }

  async updateUnreadDirects(userId) {
    const unreadDirectsNumber = await dbAdapter.getUnreadDirectsNumber(userId);
    const user = { id: userId, unreadDirectsNumber };
    const payload = JSON.stringify({ user });
    await this.publisher.userUpdated(payload);
  }

  async updateUnreadNotifications(userIntId) {
    const [{ uid: userId }] = await dbAdapter.getUsersIdsByIntIds([userIntId]);
    const unreadNotificationsNumber = await dbAdapter.getUnreadEventsNumber(userId);
    const user = { id: userId, unreadNotificationsNumber };
    const payload = JSON.stringify({ user });
    await this.publisher.userUpdated(payload);
  }

  async newPost(postId) {
    const payload = JSON.stringify({ postId })
    await this.publisher.postCreated(payload)
  }

  async destroyPost(postId, rooms) {
    const payload = JSON.stringify({ postId, rooms })
    await this.publisher.postDestroyed(payload)
  }

  async updatePost(postId) {
    const payload = JSON.stringify({ postId })
    await this.publisher.postUpdated(payload)
  }

  async newComment(comment, timelines) {
    const timelineIds = timelines.map((t) => t.id)
    const payload = JSON.stringify({ commentId: comment.id, timelineIds })
    await this.publisher.commentCreated(payload)
  }

  async destroyComment(commentId, postId) {
    const payload = JSON.stringify({ postId, commentId })
    await this.publisher.commentDestroyed(payload)
  }

  async updateComment(commentId) {
    const payload = JSON.stringify({ commentId })
    await this.publisher.commentUpdated(payload)
  }

  async newLike(post, userId) {
    const payload = JSON.stringify({ userId, postId: post.id })
    await this.publisher.likeAdded(payload)
  }

  async removeLike(postId, userId, rooms) {
    const payload = JSON.stringify({ userId, postId, rooms })
    await this.publisher.likeRemoved(payload)
  }

  async hidePost(userId, postId) {
    await this.publisher.postHidden(JSON.stringify({ userId, postId }))
  }

  async unhidePost(userId, postId) {
    await this.publisher.postUnhidden(JSON.stringify({ userId, postId }))
  }

  async newCommentLike(commentId, postId, likerUUID) {
    const payload = JSON.stringify({ commentId, postId, likerUUID });
    await this.publisher.commentLikeAdded(payload);
  }

  async removeCommentLike(commentId, postId, unlikerUUID) {
    const payload = JSON.stringify({ commentId, postId, unlikerUUID });
    await this.publisher.commentLikeRemoved(payload);
  }

  async globalUserUpdate(userId) {
    const user = await dbAdapter.getUserById(userId);
    const payload = JSON.stringify(serializeUser(user));
    await this.publisher.globalUserUpdated(payload);
  }
}
<commit_msg>Do not use 'timelines' argument in pubSub.newComment<commit_after>import { dbAdapter } from './models'
import { serializeUser } from './serializers/v2/user'

export class DummyPublisher {
  userUpdated() {}
  postCreated() {}
  postDestroyed() {}
  postUpdated() {}
  commentCreated() {}
  commentDestroyed() {}
  commentUpdated() {}
  likeAdded() {}
  likeRemoved() {}
  postHidden() {}
  postUnhidden() {}
  commentLikeAdded() {}
  commentLikeRemoved() {}
  globalUserUpdated() {}
}

export default class pubSub {
  constructor(publisher) {
    this.publisher = publisher
  }

  setPublisher(publisher) {
    this.publisher = publisher;
  }

  async updateUnreadDirects(userId) {
    const unreadDirectsNumber = await dbAdapter.getUnreadDirectsNumber(userId);
    const user = { id: userId, unreadDirectsNumber };
    const payload = JSON.stringify({ user });
    await this.publisher.userUpdated(payload);
  }

  async updateUnreadNotifications(userIntId) {
    const [{ uid: userId }] = await dbAdapter.getUsersIdsByIntIds([userIntId]);
    const unreadNotificationsNumber = await dbAdapter.getUnreadEventsNumber(userId);
    const user = { id: userId, unreadNotificationsNumber };
    const payload = JSON.stringify({ user });
    await this.publisher.userUpdated(payload);
  }

  async newPost(postId) {
    const payload = JSON.stringify({ postId })
    await this.publisher.postCreated(payload)
  }

  async destroyPost(postId, rooms) {
    const payload = JSON.stringify({ postId, rooms })
    await this.publisher.postDestroyed(payload)
  }

  async updatePost(postId) {
    const payload = JSON.stringify({ postId })
    await this.publisher.postUpdated(payload)
  }

  async newComment(comment) {
    const payload = JSON.stringify({ commentId: comment.id })
    await this.publisher.commentCreated(payload)
  }

  async destroyComment(commentId, postId) {
    const payload = JSON.stringify({ postId, commentId })
    await this.publisher.commentDestroyed(payload)
  }

  async updateComment(commentId) {
    const payload = JSON.stringify({ commentId })
    await this.publisher.commentUpdated(payload)
  }

  async newLike(post, userId) {
    const payload = JSON.stringify({ userId, postId: post.id })
    await this.publisher.likeAdded(payload)
  }

  async removeLike(postId, userId, rooms) {
    const payload = JSON.stringify({ userId, postId, rooms })
    await this.publisher.likeRemoved(payload)
  }

  async hidePost(userId, postId) {
    await this.publisher.postHidden(JSON.stringify({ userId, postId }))
  }

  async unhidePost(userId, postId) {
    await this.publisher.postUnhidden(JSON.stringify({ userId, postId }))
  }

  async newCommentLike(commentId, postId, likerUUID) {
    const payload = JSON.stringify({ commentId, postId, likerUUID });
    await this.publisher.commentLikeAdded(payload);
  }

  async removeCommentLike(commentId, postId, unlikerUUID) {
    const payload = JSON.stringify({ commentId, postId, unlikerUUID });
    await this.publisher.commentLikeRemoved(payload);
  }

  async globalUserUpdate(userId) {
    const user = await dbAdapter.getUserById(userId);
    const payload = JSON.stringify(serializeUser(user));
    await this.publisher.globalUserUpdated(payload);
  }
}
<|endoftext|>


<commit_before>/*
Name:         brothermfc
Description:  Access Brother MFC web UI details with node.js
Author:       Franklin van de Meent (https://frankl.in)
Feedback:     https://github.com/fvdm/nodejs-brothermfc/issues
Source:       https://github.com/fvdm/nodejs-brothermfc
License:      Unlicense / Public Domain (see LICENSE file)
*/

var ipp = require ('ipp');
var httpreq = require ('httpreq');

var config = {
  hostname: null,
  port: null,
  ippPort: 631
};

/**
 * Process response
 *
 * @callback callback
 * @param response {object} - httpreq response details
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function doResponse (response, callback) {
  var data = response && response.body || '';
  var error = null;

  var res = {
    code: response.statusCode,
    headers: response.headers,
    data: data.trim ()
  };

  if (response.statusCode >= 300) {
    error = new Error ('HTTP error');
    error.code = res.code;
    callback (error);
    return;
  }

  callback (null, res);
}

/**
 * Communication
 *
 * @callback callback
 * @param props {object} - Request properties
 * @param props.path - Request path
 * @param [props.method = GET] {string} - HTTP method
 * @param [props.protocol = http] {string} - `https` or `http`
 * @param [props.hostname = config.hostname] {string} - Printer hostname
 * @param [props.port = 80] {number} - Printer web UI port
 * @param [props.headers] {object} - Additional request headers
 * @returns {void}
 */

function talk (props, callback) {
  var options = {
    method: props.method || 'GET',
    parameters: props.query || null,
    headers: {}
  };

  options.url = props.protocol || config.protocol || 'http';
  options.url += '://';
  options.url += props.hostname || config.hostname;
  options.url += '/';
  options.url += props.port || config.port || 80;
  options.url += props.path;

  // custom request headers
  if (props.headers) {
    options.headers = props.headers;
  }

  // request
  httpreq.doRequest (options, function (err, res) {
    if (err) {
      callback (err);
      return;
    }

    doResponse (res, callback);
  });
}

/**
 * Method: general.status
 *
 * @callback callback
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodGeneralStatus (callback) {
  talk ({ path: '/general/status.html' }, function (err, res) {
    var result = {
      model: null,
      status: null,
      message: null,
      ink: {}
    };

    if (err) {
      callback (err);
      return;
    }

    res.data.replace (/

([^<]+)<\/h1>/, function (s, t) {
      result.model = t;
    });

    res.data.replace (/
([^<]+)<\/span><\/div>/, function (s, t, m) {
      result.status = t;
      result.message = m;
    });

    res.data.replace (/<img src="\.\.\/common\/images\/(\w+)\.gif" alt="([^\"]+)" class="tonerremain" height="(\d+)px"/g, function (s, c, s2, p) {
      result.ink [c] = Math.round (p * 1.7857142857);
    });

    res.data.replace (/
[^<]+:<\/span>([^<]+)<\/li>/g, function (s, t, v) {
      result [t] = v;
    });

    callback (null, result);
  });
}

/**
 * Method: general.information
 *
 * @callback callback
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodGeneralInformation (callback) {
  talk ({ path: '/etc/mnt_info.csv' }, function (err, res) {
    var data;
    var one;
    var two;
    var result = {};
    var i;
    var val;
    var key;

    if (err) {
      callback (err);
      return;
    }

    data = res.data.replace (/\""{0}/g, '');
    data = data.split ('\n');

    one = data [0] .split (',');
    two = data [1] .split (',');
    result = {};

    for (i = 0; i < one.length; i++) {
      val = two [i] .trim ();
      key = one [i] .trim () .replace (/(.+)/, function (s, t) {
        return t.toLowerCase () .replace (' ', '_') .replace ('.', '');
      });

      if (key !== '' && val !== '') {
        result [key] = val.match (/^\d+$/) ? val * 1 : val;
      }
    }

    callback (null, result);
  });
}

/**
 * Method: sleep
 *
 * `set` values:
 * 0 = 1 min
 * 1 = 2 min
 * 2 = 3 min
 * 3 = 5 min
 * 4 = 10 min
 * 5 = 30 min
 * 6 = 60 min
 *
 * @callback callback
 * @param set {number} - 1-6, see above
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodSleep (set, callback) {
  var result = {
    presets: []
  };

  var form = {
    pageid: 5,
    postif_registration_reject: 1,
    B15: set
  };

  if (!callback) {
    talk ({ path: '/general/sleep.html' }, function (err, res) {
      if (err) {
        callback (err);
        return;
      }

      res.data.replace (/<select id="B15" name="B15" >(.+)<\/select>/, function (s, sel) {
        sel.replace (/<option value="(\d+)"( selected="selected")?>(\d+) Mins<\/option>/g, function (s2, a, b, c) {
          result.presets.push ({
            key: a,
            minutes: c * 1
          });

          if (b) {
            result.value = {
              key: a,
              minutes: c * 1
            };
          }
        });
      });

      set (null, result);
    });

    return;
  }

  talk (
    {
      method: 'POST',
      path: '/general/sleep.html',
      query: form
    },
    function (err, res) {
      if (err) {
        callback (err);
        return;
      }

      if (!!~res.data.indexOf ('
')) {
        callback (null, true);
        return;
      }

      callback (new Error ('post failed'));
    }
  );
}

/**
 * Method: current
 *
 * @callback callback
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodCurrent (callback) {
  var printer = ipp.Printer ('http://' + config.hostname + ':' + config.ippPort + '/ipp/printer');
  var msg = {
    'operation-attributes-tag': {
      'requested-attributes': [
        'queued-job-count',
        'marker-names',
        'marker-levels',
        'printer-state',
        'printer-state-reasons',
        'printer-up-time'
      ]
    }
  };

  printer.execute ('Get-Printer-Attributes', msg, function (err, data) {
    var error = null;
    var result = {};
    var name;
    var i;

    if (err) {
      error = new Error ('ipp error');
      error.error = err;
      return callback (err);
    }

    data = data ['printer-attributes-tag'] || {};

    result.state = data ['printer-state'] || null;
    result.stateReasons = data ['printer-state-reasons'] || null;
    result.jobs = data ['queued-job-count'] || 0;
    result.uptime = data ['printer-up-time'] || 0;
    result.uptimeDate = new Date (Date.now () - (result.uptime * 1000));

    result.ink = {};

    if (data ['marker-names'] instanceof Array && data ['marker-levels'] instanceof Array) {
      for (i = 0; i < data ['marker-names'] .length; i++) {
        name = data ['marker-names'] [i] .toLowerCase () .replace (/.*\u001e(\w+) .*/, '$1');
        result.ink [name] = data ['marker-levels'] [i];
      }
    }

    callback (null, result);
  });
}

/**
 * Module interface
 *
 * @param setup {object} - Configuration parameters
 * @param setup.hostname {string} - Printer hostname or IP
 * @param [setup.port = 80] {number} - Printer UI port
 * @param [setup.ippPort = 631] {number} - Printer IPP port
 * @param [setup.protocol = http] {string} - Printer UI protocol, `http` or `https`
 * @returns {object} - Methods
 */

module.exports = function (setup) {
  var i;

  for (i in setup) {
    config [i] = setup [i];
  }

  return {
    current: methodCurrent,
    sleep: methodSleep,
    general: {
      status: methodGeneralStatus,
      information: methodGeneralInformation
    }
  };
};
<commit_msg>Set and use default config parameters<commit_after>/*
Name:         brothermfc
Description:  Access Brother MFC web UI details with node.js
Author:       Franklin van de Meent (https://frankl.in)
Feedback:     https://github.com/fvdm/nodejs-brothermfc/issues
Source:       https://github.com/fvdm/nodejs-brothermfc
License:      Unlicense / Public Domain (see LICENSE file)
*/

var ipp = require ('ipp');
var httpreq = require ('httpreq');

var config = {
  protocol: 'http',
  hostname: null,
  port: 80,
  ippPort: 631
};

/**
 * Process response
 *
 * @callback callback
 * @param response {object} - httpreq response details
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function doResponse (response, callback) {
  var data = response && response.body || '';
  var error = null;

  var res = {
    code: response.statusCode,
    headers: response.headers,
    data: data.trim ()
  };

  if (response.statusCode >= 300) {
    error = new Error ('HTTP error');
    error.code = res.code;
    callback (error);
    return;
  }

  callback (null, res);
}

/**
 * Communication
 *
 * @callback callback
 * @param props {object} - Request properties
 * @param props.path - Request path
 * @param [props.method = GET] {string} - HTTP method
 * @param [props.protocol = http] {string} - `https` or `http`
 * @param [props.hostname = config.hostname] {string} - Printer hostname
 * @param [props.port = 80] {number} - Printer web UI port
 * @param [props.headers] {object} - Additional request headers
 * @returns {void}
 */

function talk (props, callback) {
  var options = {
    method: props.method || 'GET',
    parameters: props.query || null,
    headers: {}
  };

  options.url = props.protocol || config.protocol;
  options.url += '://';
  options.url += props.hostname || config.hostname;
  options.url += '/';
  options.url += props.port || config.port;
  options.url += props.path;

  // custom request headers
  if (props.headers) {
    options.headers = props.headers;
  }

  // request
  httpreq.doRequest (options, function (err, res) {
    if (err) {
      callback (err);
      return;
    }

    doResponse (res, callback);
  });
}

/**
 * Method: general.status
 *
 * @callback callback
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodGeneralStatus (callback) {
  talk ({ path: '/general/status.html' }, function (err, res) {
    var result = {
      model: null,
      status: null,
      message: null,
      ink: {}
    };

    if (err) {
      callback (err);
      return;
    }

    res.data.replace (/

([^<]+)<\/h1>/, function (s, t) {
      result.model = t;
    });

    res.data.replace (/
([^<]+)<\/span><\/div>/, function (s, t, m) {
      result.status = t;
      result.message = m;
    });

    res.data.replace (/<img src="\.\.\/common\/images\/(\w+)\.gif" alt="([^\"]+)" class="tonerremain" height="(\d+)px"/g, function (s, c, s2, p) {
      result.ink [c] = Math.round (p * 1.7857142857);
    });

    res.data.replace (/
[^<]+:<\/span>([^<]+)<\/li>/g, function (s, t, v) {
      result [t] = v;
    });

    callback (null, result);
  });
}

/**
 * Method: general.information
 *
 * @callback callback
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodGeneralInformation (callback) {
  talk ({ path: '/etc/mnt_info.csv' }, function (err, res) {
    var data;
    var one;
    var two;
    var result = {};
    var i;
    var val;
    var key;

    if (err) {
      callback (err);
      return;
    }

    data = res.data.replace (/\""{0}/g, '');
    data = data.split ('\n');

    one = data [0] .split (',');
    two = data [1] .split (',');
    result = {};

    for (i = 0; i < one.length; i++) {
      val = two [i] .trim ();
      key = one [i] .trim () .replace (/(.+)/, function (s, t) {
        return t.toLowerCase () .replace (' ', '_') .replace ('.', '');
      });

      if (key !== '' && val !== '') {
        result [key] = val.match (/^\d+$/) ? val * 1 : val;
      }
    }

    callback (null, result);
  });
}

/**
 * Method: sleep
 *
 * `set` values:
 * 0 = 1 min
 * 1 = 2 min
 * 2 = 3 min
 * 3 = 5 min
 * 4 = 10 min
 * 5 = 30 min
 * 6 = 60 min
 *
 * @callback callback
 * @param set {number} - 1-6, see above
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodSleep (set, callback) {
  var result = {
    presets: []
  };

  var form = {
    pageid: 5,
    postif_registration_reject: 1,
    B15: set
  };

  if (!callback) {
    talk ({ path: '/general/sleep.html' }, function (err, res) {
      if (err) {
        callback (err);
        return;
      }

      res.data.replace (/<select id="B15" name="B15" >(.+)<\/select>/, function (s, sel) {
        sel.replace (/<option value="(\d+)"( selected="selected")?>(\d+) Mins<\/option>/g, function (s2, a, b, c) {
          result.presets.push ({
            key: a,
            minutes: c * 1
          });

          if (b) {
            result.value = {
              key: a,
              minutes: c * 1
            };
          }
        });
      });

      set (null, result);
    });

    return;
  }

  talk (
    {
      method: 'POST',
      path: '/general/sleep.html',
      query: form
    },
    function (err, res) {
      if (err) {
        callback (err);
        return;
      }

      if (!!~res.data.indexOf ('
')) {
        callback (null, true);
        return;
      }

      callback (new Error ('post failed'));
    }
  );
}

/**
 * Method: current
 *
 * @callback callback
 * @param callback {function} - `function (err, data) {}`
 * @returns {void}
 */

function methodCurrent (callback) {
  var printer = ipp.Printer ('http://' + config.hostname + ':' + config.ippPort + '/ipp/printer');
  var msg = {
    'operation-attributes-tag': {
      'requested-attributes': [
        'queued-job-count',
        'marker-names',
        'marker-levels',
        'printer-state',
        'printer-state-reasons',
        'printer-up-time'
      ]
    }
  };

  printer.execute ('Get-Printer-Attributes', msg, function (err, data) {
    var error = null;
    var result = {};
    var name;
    var i;

    if (err) {
      error = new Error ('ipp error');
      error.error = err;
      return callback (err);
    }

    data = data ['printer-attributes-tag'] || {};

    result.state = data ['printer-state'] || null;
    result.stateReasons = data ['printer-state-reasons'] || null;
    result.jobs = data ['queued-job-count'] || 0;
    result.uptime = data ['printer-up-time'] || 0;
    result.uptimeDate = new Date (Date.now () - (result.uptime * 1000));

    result.ink = {};

    if (data ['marker-names'] instanceof Array && data ['marker-levels'] instanceof Array) {
      for (i = 0; i < data ['marker-names'] .length; i++) {
        name = data ['marker-names'] [i] .toLowerCase () .replace (/.*\u001e(\w+) .*/, '$1');
        result.ink [name] = data ['marker-levels'] [i];
      }
    }

    callback (null, result);
  });
}

/**
 * Module interface
 *
 * @param setup {object} - Configuration parameters
 * @param setup.hostname {string} - Printer hostname or IP
 * @param [setup.port = 80] {number} - Printer UI port
 * @param [setup.ippPort = 631] {number} - Printer IPP port
 * @param [setup.protocol = http] {string} - Printer UI protocol, `http` or `https`
 * @returns {object} - Methods
 */

module.exports = function (setup) {
  var i;

  for (i in setup) {
    config [i] = setup [i];
  }

  return {
    current: methodCurrent,
    sleep: methodSleep,
    general: {
      status: methodGeneralStatus,
      information: methodGeneralInformation
    }
  };
};
<|endoftext|>