<commit_before>/**
* A timetable view of a TripPattern and Calendar.
*/

var GtfsEditor = GtfsEditor || {};

(function (G, $, ich) {
  G.stopTimeRenderer = function (instance, td, row, col, prop, value, cellProperties) {
    // TODO: 12h time
    // TODO: single-time view
    // value is stoptime

    var text;

    if (_.isUndefined(value)) {
      text = '-';
    }
    else {
      var arr = col % 2 == 1;
      var time = arr ? value.arrivalTime : value.departureTime;

      var secs = time % 60;
      var mins = (time - secs) % (60 * 60) / 60;
      var hours = (time - secs - mins * 60) / (60 * 60);

      text =
      '' + hours + '' +
      '' + (mins < 10 ? '0' + mins : mins) + '' +
      '' + (secs < 10 ? '0' + secs : secs) + '';

      $(td).addClass('time');

      $(td).addClass(arr ? 'time-arr' : 'time-dep');

      // dim departure times that are the same as their arrival times
      if (!arr && value.departureTime == value.arrivalTime)
        $(td).addClass('time-dep-dimmed');
      }

      Handsontable.renderers.HtmlRenderer(instance, td, row, col, prop, text, cellProperties);
  };

  G.TripPatternScheduleView = Backbone.View.extend({
    initialize: function (attr) {
      // consistency check
      var tripPatternId = null;
      var serviceCalendarId = null;
      var first = true;
      this.collection.each(function (trip) {
        if (first) {
          tripPatternId = trip.get('pattern').id;
          serviceCalendarId = trip.get('serviceCalendar').id;
          first = false;
        }
        else {
          if (trip.get('pattern').id != tripPatternId ||
                trip.get('serviceCalendar').id != serviceCalendarId) {
            throw new Error("Trip pattern or service calendars differ between trips");
          }
        }
      });
    },

    // combination of getAttr and setAttr for handsontable
    attr: function (name) {
      return {data: function (trip, val) {
        if (name.indexOf('stop:') === 0) {
          // we need to return a stop time, so first parse out the column header
          var sp = name.split(':');
          var stopId = sp[1];
          var stopSeq = sp[2];
          var arr = sp[3] == 'arr';

          // find the stopTime with this stop id and stop sequence
          // note that this makes an assumption about stop_sequence: when a stop is ommitted,
          // its sequence number is omitted as well
          var st = _.find(trip.get('stopTimes'), function (st) {
            return st.stop.id == stopId && st.stopSequence == stopSeq;
          });

          //return st;
          // TODO: this is absolutely the wrong place to do time formatting
          // TODO: don't just give departure time
          // TODO: create a special cell editor for this
          if (st === null) {
            return '-';
          }

          return st;
        }

        else if (name == 'trip_id') {
          return trip.get('gtfsTripId');
        }

        else if (name == 'block_id') {
          return trip.get('blockId');
        }

        else if (name == 'trip_name') {
          return trip.get('tripName');
        }
      },
      renderer: name.indexOf('stop:') === 0 ? G.stopTimeRenderer : Handsontable.renderers.TextRenderer
    };
  },

  render: function () {
    // render the template
    this.$el.html(ich['timetable-tpl']());

    // figure out what columns we're rendering
    var columns = [this.attr('trip_id'), this.attr('block_id'), this.attr('name')];
    // TODO: i18n
    var headers = ['Trip ID', 'Block ID', 'Trip name'];

    var instance = this;

    // we generate a mergecells array to tell the table to merge the stop headers for arr and dep
    var mergeCells = [];
    // note: the merged header cells aren't actually merged, but depend on a really awful hack (in timetable.css) where the width of
    // two columns is hardcoded as the header width. As a side effect, these numbers must be exactly twice the width of the time
    // display cells
    var colWidths = [150, 150, 150];

    _.each(this.collection.at(0).get('pattern').patternStops, function (patternStop, idx) {
      // we put stopSequence here for loop routes
      columns.push(instance.attr('stop:' + patternStop.stop.id + ':' + patternStop.stopSequence + ':arr'));
      columns.push(instance.attr('stop:' + patternStop.stop.id + ':' + patternStop.stopSequence + ':dep'));
      headers.push(patternStop.stop.stopName);
      // dummy header, will be overwritten when cells are merged
      headers.push('');

      // merge the two created header cells. idx + 4 is because there are three columns before the times,
      // and columns are 1-based
      mergeCells.push({row: -1, col: idx + 3, rowspan: 1, colspan: 2})
      colWidths.push(75);
      colWidths.push(75);
    });

    var $container = this.$('#timetable');
    $container.handsontable({
      data: this.collection.toArray(),
      dataSchema: function () { return new G.Trip(); },
      // we'll be defining interaction on our own
      contextMenu: false,
      columns: columns,
      colHeaders: headers,
      colWidths: colWidths
      //mergeCells: mergeCells
    });
    return this;
  }
});
})(GtfsEditor, jQuery, ich);
<commit_msg>first shot at editing; need to use a cell editor so that the double-click value isn't the dreaded [Object object].<commit_after>/**
* A timetable view of a TripPattern and Calendar.
*/

var GtfsEditor = GtfsEditor || {};

(function (G, $, ich) {
  G.stopTimeRenderer = function (instance, td, row, col, prop, value, cellProperties) {
    // TODO: 12h time
    // TODO: single-time view
    // value is stoptime

    var text;

    if (_.isUndefined(value)) {
      text = '-';
    }
    else {
      var arr = col % 2 == 1;
      var time = arr ? value.arrivalTime : value.departureTime;

      var secs = time % 60;
      var mins = (time - secs) % (60 * 60) / 60;
      var hours = (time - secs - mins * 60) / (60 * 60);

      text =
      '' + hours + '' +
      '' + (mins < 10 ? '0' + mins : mins) + '' +
      '' + (secs < 10 ? '0' + secs : secs) + '';

      $(td).addClass('time');

      $(td).addClass(arr ? 'time-arr' : 'time-dep');

      // dim departure times that are the same as their arrival times
      if (!arr && value.departureTime == value.arrivalTime)
        $(td).addClass('time-dep-dimmed');
      }

      Handsontable.renderers.HtmlRenderer(instance, td, row, col, prop, text, cellProperties);
  };

  G.TripPatternScheduleView = Backbone.View.extend({
    initialize: function (attr) {
      // consistency check
      var tripPatternId = null;
      var serviceCalendarId = null;
      var first = true;
      this.collection.each(function (trip) {
        if (first) {
          tripPatternId = trip.get('pattern').id;
          serviceCalendarId = trip.get('serviceCalendar').id;
          first = false;
        }
        else {
          if (trip.get('pattern').id != tripPatternId ||
                trip.get('serviceCalendar').id != serviceCalendarId) {
            throw new Error("Trip pattern or service calendars differ between trips");
          }
        }
      });
    },

    // parse out a time entered by a human and return seconds since (noon - 12h)
    parseTime: function (time) {
      // TODO: many time formats
      // 332p
      // 1532
      // 153200
      // 15:33
      // 3:33 PM
      // etc.
      var spTime = time.split(':');
      return spTime[0] * 3600 + spTime[1] * 60 + spTime[2] * 1;
    },

    // combination of getAttr and setAttr for handsontable
    attr: function (name) {
      var instance = this;
      return {data: function (trip, val) {
        if (name.indexOf('stop:') === 0) {
          // we need to return a stop time, so first parse out the column header
          var sp = name.split(':');
          var stopId = sp[1];
          var stopSeq = sp[2];
          var arr = sp[3] == 'arr';

          // find the stopTime with this stop id and stop sequence
          // note that this makes an assumption about stop_sequence: when a stop is ommitted,
          // its sequence number is omitted as well
          var st = _.find(trip.get('stopTimes'), function (st) {
            return st.stop.id == stopId && st.stopSequence == stopSeq;
          });

          if (_.isUndefined(val)) {
            return st;
          }
          else {
            if (arr) {
              st.arrivalTime = instance.parseTime(val) || st.arrivalTime;
            }
            else {
              st.departureTime = instance.parseTime(val) || st.departureTime;
            }
            // TODO: save here
          }
        }

        else if (name == 'trip_id') {
          return trip.get('gtfsTripId');
        }

        else if (name == 'block_id') {
          return trip.get('blockId');
        }

        else if (name == 'trip_name') {
          return trip.get('tripName');
        }
      },
      renderer: name.indexOf('stop:') === 0 ? G.stopTimeRenderer : Handsontable.renderers.TextRenderer
    };
  },

  render: function () {
    // render the template
    this.$el.html(ich['timetable-tpl']());

    // figure out what columns we're rendering
    var columns = [this.attr('trip_id'), this.attr('block_id'), this.attr('name')];
    // TODO: i18n
    var headers = ['Trip ID', 'Block ID', 'Trip name'];

    var instance = this;

    // we generate a mergecells array to tell the table to merge the stop headers for arr and dep
    var mergeCells = [];
    // note: the merged header cells aren't actually merged, but depend on a really awful hack (in timetable.css) where the width of
    // two columns is hardcoded as the header width. As a side effect, these numbers must be exactly twice the width of the time
    // display cells
    var colWidths = [150, 150, 150];

    _.each(this.collection.at(0).get('pattern').patternStops, function (patternStop, idx) {
      // we put stopSequence here for loop routes
      columns.push(instance.attr('stop:' + patternStop.stop.id + ':' + patternStop.stopSequence + ':arr'));
      columns.push(instance.attr('stop:' + patternStop.stop.id + ':' + patternStop.stopSequence + ':dep'));
      headers.push(patternStop.stop.stopName);
      // dummy header, will be overwritten when cells are merged
      headers.push('');

      // merge the two created header cells. idx + 4 is because there are three columns before the times,
      // and columns are 1-based
      mergeCells.push({row: -1, col: idx + 3, rowspan: 1, colspan: 2})
      colWidths.push(75);
      colWidths.push(75);
    });

    var $container = this.$('#timetable');
    $container.handsontable({
      data: this.collection.toArray(),
      dataSchema: function () { return new G.Trip(); },
      // we'll be defining interaction on our own
      contextMenu: false,
      columns: columns,
      colHeaders: headers,
      colWidths: colWidths
      //mergeCells: mergeCells
    });
    return this;
  }
});
})(GtfsEditor, jQuery, ich);
<|endoftext|>


<commit_before>/*
    Copyright 2012 Rustici Software

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

/**
TinCan client library

@module TinCan
@submodule TinCan.Agent
**/
(function () {
    "use strict";

    /**
    @class TinCan.Agent
    @constructor
    */
    var Agent = TinCan.Agent = function (cfg) {
        this.log("constructor");

        /**
        @property objectType
        @type String
        @default Agent
        */
        this.objectType = "Agent";

        /**
        @property name
        @type String
        */
        this.name = null;

        /**
        @property mbox
        @type String
        */
        this.mbox = null;

        /**
        @property mbox_sha1sum
        @type String
        */
        this.mbox_sha1sum = null;

        /**
        @property openid
        @type Array
        */
        this.openid = null;

        /**
        @property account
        @type Array
        */
        this.account = null;

        this.init(cfg);
    };
    Agent.prototype = {
        /**
        @property LOG_SRC
        */
        LOG_SRC: 'Agent',

        /**
        @method log
        */
        log: TinCan.prototype.log,

        /**
        @method init
        @param {Object} [options] Configuration used to initialize
        */
        init: function (cfg) {
            this.log("init");
            var i,
                directProps = [
                    "mbox",
                    "name",
                    "account"
                ]
            ;

            cfg = cfg || {};

            for (i = 0; i < directProps.length; i += 1) {
                if (cfg.hasOwnProperty(directProps[i]) && cfg[directProps[i]] !== null) {
                    this[directProps[i]] = cfg[directProps[i]];
                }
            }
        },

        /**
        @method asVersion
        @param {Object} [options]
        @param {String} [options.version] Version to return (defaults to newest supported)
        */
        asVersion: function (version) {
            this.log("asVersion: " + version);
            var result = {
                objectType: this.objectType
            };

            version = version || TinCan.versions()[0];

            if (version === "0.95") {
                if (this.mbox !== null) {
                    result.mbox = this.mbox;
                }
                if (this.name !== null) {
                    result.name = this.name;
                }
            }
            else if (version === "0.90") {
                if (this.mbox !== null) {
                    result.mbox = [
                        this.mbox
                    ];
                }
                if (this.name !== null) {
                    result.name = [
                        this.name
                    ];
                }
            }

            return result;
        }
    };

    /**
    @method fromJSON
    @return {Object} Agent
    @static
    */
    Agent.fromJSON = function (agentJSON) {
        Agent.prototype.log("fromJSON");
        var _agent = JSON.parse(agentJSON);

        return new Agent(_agent);
    };
}());
<commit_msg>Auto add "mailto" to mbox when doesn't already have it<commit_after>/*
    Copyright 2012 Rustici Software

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

/**
TinCan client library

@module TinCan
@submodule TinCan.Agent
**/
(function () {
    "use strict";

    /**
    @class TinCan.Agent
    @constructor
    */
    var Agent = TinCan.Agent = function (cfg) {
        this.log("constructor");

        /**
        @property objectType
        @type String
        @default Agent
        */
        this.objectType = "Agent";

        /**
        @property name
        @type String
        */
        this.name = null;

        /**
        @property mbox
        @type String
        */
        this.mbox = null;

        /**
        @property mbox_sha1sum
        @type String
        */
        this.mbox_sha1sum = null;

        /**
        @property openid
        @type Array
        */
        this.openid = null;

        /**
        @property account
        @type Array
        */
        this.account = null;

        this.init(cfg);
    };
    Agent.prototype = {
        /**
        @property LOG_SRC
        */
        LOG_SRC: 'Agent',

        /**
        @method log
        */
        log: TinCan.prototype.log,

        /**
        @method init
        @param {Object} [options] Configuration used to initialize
        */
        init: function (cfg) {
            this.log("init");
            var i,
                directProps = [
                    "mbox",
                    "name",
                    "account"
                ],
                val
            ;

            cfg = cfg || {};

            for (i = 0; i < directProps.length; i += 1) {
                if (cfg.hasOwnProperty(directProps[i]) && cfg[directProps[i]] !== null) {
                    val = cfg[directProps[i]];
                    if (directProps[i] === "mbox" && val.indexOf("mailto:") === -1) {
                        val = "mailto:" + val;
                    }
                    this[directProps[i]] = val;
                }
            }
        },

        /**
        @method asVersion
        @param {Object} [options]
        @param {String} [options.version] Version to return (defaults to newest supported)
        */
        asVersion: function (version) {
            this.log("asVersion: " + version);
            var result = {
                objectType: this.objectType
            };

            version = version || TinCan.versions()[0];

            if (version === "0.95") {
                if (this.mbox !== null) {
                    result.mbox = this.mbox;
                }
                if (this.name !== null) {
                    result.name = this.name;
                }
            }
            else if (version === "0.90") {
                if (this.mbox !== null) {
                    result.mbox = [
                        this.mbox
                    ];
                }
                if (this.name !== null) {
                    result.name = [
                        this.name
                    ];
                }
            }

            return result;
        }
    };

    /**
    @method fromJSON
    @return {Object} Agent
    @static
    */
    Agent.fromJSON = function (agentJSON) {
        Agent.prototype.log("fromJSON");
        var _agent = JSON.parse(agentJSON);

        return new Agent(_agent);
    };
}());
<|endoftext|>


<commit_before>'use strict';

angular.module('arachne.controllers')

    .controller('EditCatalogController', ['$scope', '$uibModalInstance', 'catalog', 'edit',
        function ($scope, $uibModalInstance, catalog, edit) {
            $scope.catalog = catalog;
            $scope.edit = edit;
        }
    ]);<commit_msg>Rename controller dependencies.<commit_after>'use strict';

angular.module('arachne.controllers')

    .controller('EditCatalogController', ['$scope', '$uibModalInstance', 'Catalog', 'CatalogEntry',
        function ($scope, $uibModalInstance, Catalog, CatalogEntry) {
            $scope.catalog = Catalog;
            $scope.edit = CatalogEntry;
        }
    ]);<|endoftext|>


<commit_before>/*@pjs preload="data/images/logo1.png";*/

var sketchProc=function(processingInstance){ with (processingInstance){

//Setup
var wi = window.innerWidth ||
        document.documentElement.clientWidth ||
        document.body.clientWidth;
var he = window.innerHeight ||
         document.documentElement.clientHeight ||
         document.body.clientHeight;
size(wi*0.9,he*0.9);
frameRate(60);

setup = function() {
	mainfont = createFont("Times New Roman");
	logo = loadImage("data/images/logo1.png");

	keys = [];
	page = 0;
	chapter1 = [];

	m = false;
	md = false;
	flevel = 255;
	bw = width/8;
	bh = width/16;
	prim = color(15,15,15);
	sec = color(100,30,30);
	tert = color(150,150,150);
	backg = color(55,55,55);

	fade = function() {
		flevel -= 10;
		fill(55,55,55,flevel);
	};

	loadpanels = function(name,number,target) {
		for (i = 0; i < number;) {
			target[i] = loadImage("data/images/panels/"+name+i+".png");
			i ++;
		}
	};

	buttons = {
		start:{x:width*(3/4),y:height/2,w:bw,h:bh,text:"Enter"},
		next:{x:width*(6/7),y:height*(1/2),w:bw,h:bh,text:"Next"},
		prev:{x:width*(1/7),y:height*(1/2),w:bw,h:bh,text:"Previous"},
	};

	displaypanel = function(img,x,y) {
		imageMode(CENTER);
		pushMatrix();
		translate(x,y);
		scale(0.001*height,0.001*height);
			image(img,0,0);
		popMatrix();
	};

	button = function(con) {
		bux = con.x
		buy = con.y
		buw = con.w
		buh = con.h
		butext = con.text
		con.pressed = false;

		rectMode(CENTER);

		if (mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2) {
			fill(prim);
		} else {
			fill(sec);
		}
		stroke(prim);
		strokeWeight(buh/10);
		rect(bux,buy,buw,buh,buh/3);

		if (mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2) {
			fill(sec);
		} else {
			fill(prim);
		}
		textFont(mainfont,buh/2);
		textAlign(CENTER,CENTER);
		text(butext,bux,buy);

		if ((mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2 && m) || (mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2 && md)) {
			con.pressed = true;
		}
		return con.pressed;
	};

	loadpanels("chap1/",1,chapter1);
	standardbuttons = function() {
		button(buttons.next);
		if (buttons.next.pressed) {
			page += 1;
			flevel = 255;
		};

		button(buttons.prev);
		if (buttons.prev.pressed) {
			page -= 1;
			flevel = 255;
		};
	};

	pages = [
		function() {
			background(backg)

			displaypanel(logo,width/4,height/2)

			button(buttons.start)
			if (buttons.start.pressed==true) {
				page += 1
			}
		},
		function() {
			background(backg)

			displaypanel(chapter1[0],width/2,height/2);

			standardbuttons();

			fade();
		},

	];

};

draw = function() {
	pages[page]();
};

keyPressed = function() {
	keys[keyCode] = true;
};
keyReleased = function() {
	keys[keyCode] = false;
};
mousePressed = function() {
	m = true;
};
mouseDragged = function() {
	md = true;
};
mouseReleased = function() {
	m = false;
	md = false;
};

}};
<commit_msg>Update main.js<commit_after>/*@pjs preload="data/images/logo1.png";*/

var sketchProc=function(processingInstance){ with (processingInstance){

//Setup
var wi = window.innerWidth ||
        document.documentElement.clientWidth ||
        document.body.clientWidth;
var he = window.innerHeight ||
         document.documentElement.clientHeight ||
         document.body.clientHeight;
size(wi*0.9,he*0.9);
frameRate(60);

setup = function() {
	mainfont = createFont("Times New Roman");
	logo = loadImage("data/images/logo1.png");

	keys = [];
	page = 0;
	chapter1 = [];

	m = false;
	md = false;
	flevel = 255;
	bw = width/8;
	bh = width/16;
	prim = color(15,15,15);
	sec = color(100,30,30);
	tert = color(150,150,150);
	backg = color(55,55,55);

	fade = function() {
		flevel -= 10;
		fill(55,55,55,flevel);
		noStroke();
		rectMode(CORNER);
		rect(-1,-1,width+1,height+1);
	};

	loadpanels = function(name,number,target) {
		for (i = 0; i < number;) {
			target[i] = loadImage("data/images/panels/"+name+i+".png");
			i ++;
		}
	};

	buttons = {
		start:{x:width*(3/4),y:height/2,w:bw,h:bh,text:"Enter"},
		next:{x:width*(6/7),y:height*(1/2),w:bw,h:bh,text:"Next"},
		prev:{x:width*(1/7),y:height*(1/2),w:bw,h:bh,text:"Previous"},
	};

	displaypanel = function(img,x,y) {
		imageMode(CENTER);
		pushMatrix();
		translate(x,y);
		scale(0.001*height,0.001*height);
			image(img,0,0);
		popMatrix();
	};

	button = function(con) {
		bux = con.x
		buy = con.y
		buw = con.w
		buh = con.h
		butext = con.text
		con.pressed = false;

		rectMode(CENTER);

		if (mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2) {
			fill(prim);
		} else {
			fill(sec);
		}
		stroke(prim);
		strokeWeight(buh/10);
		rect(bux,buy,buw,buh,buh/3);

		if (mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2) {
			fill(sec);
		} else {
			fill(prim);
		}
		textFont(mainfont,buh/2);
		textAlign(CENTER,CENTER);
		text(butext,bux,buy);

		if ((mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2 && m) || (mouseX>bux-buw/2&&mouseX<bux+buw/2 && mouseY>buy-buh/2&&mouseY<buy+buh/2 && md)) {
			con.pressed = true;
		}
		return con.pressed;
	};

	loadpanels("chap1/",1,chapter1);
	standardbuttons = function() {
		button(buttons.next);
		if (buttons.next.pressed) {
			page += 1;
			flevel = 255;
		};

		button(buttons.prev);
		if (buttons.prev.pressed) {
			page -= 1;
			flevel = 255;
		};
	};

	pages = [
		function() {
			background(backg)

			displaypanel(logo,width/4,height/2)

			button(buttons.start)
			if (buttons.start.pressed==true) {
				page += 1
			}
		},
		function() {
			background(backg)

			displaypanel(chapter1[0],width/2,height/2);

			standardbuttons();

			fade();
		},

	];

};

draw = function() {
	pages[page]();
};

keyPressed = function() {
	keys[keyCode] = true;
};
keyReleased = function() {
	keys[keyCode] = false;
};
mousePressed = function() {
	m = true;
};
mouseDragged = function() {
	md = true;
};
mouseReleased = function() {
	m = false;
	md = false;
};

}};
<|endoftext|>


<commit_before>"use strict";

/*global nodeca, _*/

var NLib = require('nlib');
var Async = NLib.Vendor.Async;

var Section = nodeca.models.forum.Section;
var Thread = nodeca.models.forum.Thread;

var forum_breadcrumbs = require('../../lib/forum_breadcrumbs.js');
var to_tree = require('../../lib/to_tree.js');

var threads_in_fields = [
  '_id',
  'id',
  'title',
  'prefix',
  'forum_id',
  '_views_count',
  'cache'
];

var subforums_in_fields = [
  '_id',
  'id',
  'title',
  'description',
  'parent',
  'parent_list',
  'moderator_list',
  'display_order',
  'level',
  'cache'
];

var subforums_out_fields = [
  '_id',
  'id',
  'title',
  'description',
  'moderator_list',
  'child_list',
  'cache'
];

var forum_info_out_fields = [
  'id',
  'title',
  'description',
  'is_category'
];

// Prefetch forum to simplify permisson check.
// Check that forum exists.
//
nodeca.filters.before('@', function (params, next) {
  var env = this;

  env.extras.puncher.start('Forum info prefetch');

  Section.findOne({ id: params.id }).setOptions({ lean: true })
      .exec(function(err, forum) {

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

    // No forum -> "Not Found" status
    if (!forum) {
      next({ statusCode: 404 });
      return;
    }

    env.data.section = forum;

    env.extras.puncher.stop();

    next(err);
  });
});

// fetch and prepare threads
//
// ##### params
//
// - `id`   forum id
//
module.exports = function (params, next) {
  var env = this;

  var sort = {};
  var start;
  var query;

  var threads_per_page = nodeca.settings.global.get('threads_per_page');

  env.response.data.show_page_number = false;

  env.extras.puncher.start('Get threads');
  env.extras.puncher.start('Thread ids prefetch');

  if (env.session.hb) {
    sort['cache.hb.last_ts'] = -1;
  }
  else {
    sort['cache.real.last_ts'] = -1;
  }

  // FIXME add state condition to select only visible threads
  start = (params.page - 1) * threads_per_page;

  // Fetch IDs of "visible" threads interval (use coverage index)
  Thread.find({ forum_id: params.id }).select('_id').sort(sort).skip(start)
      .limit(threads_per_page + 1).setOptions({ lean: true }).exec(function(err, docs) {

    if (!docs.length) {
      if (params.page > 1) {

        // FIXME Redirect to last page if possible

        // No page -> "Not Found" status
        next({ statusCode: 404 });
      }
      else {
        // category or forum without threads
        env.extras.puncher.stop();
        env.extras.puncher.stop();

        env.data.threads = [];

        next();
      }
      return;
    }

    env.extras.puncher.stop({ count: docs.length });
    env.extras.puncher.start('Get threads by _id list');

    // FIXME modify state condition (deleted and etc) if user has permission
    // If no hidden threads - no conditions needed, just select by IDs

    query = Thread.find({ forum_id: params.id }).where('_id').lte(_.first(docs)._id);
    if (docs.length <= threads_per_page) {
      query.gte(_.last(docs)._id);
    }
    else {
      query.gt(_.last(docs)._id);
    }

    // Select all allowed threads in calculated
    // interval: visible + deleted and others (if allowed by permissions)
    query.select(threads_in_fields.join(' ')).sort(sort)
        .setOptions({ lean: true }).exec(function(err, threads){
      if (err) {
        next(err);
        return;
      }

      env.data.threads = threads;

      env.extras.puncher.stop({ count: threads.length });
      env.extras.puncher.stop();

      next();
    });
  });
};

// fetch sub-forums (only on first page)
//
nodeca.filters.after('@', function (params, next) {
  var env = this;

  var max_level;
  var query;

  env.data.sections = [];
  // subforums fetched only on first page
  if (params.page > 1) {
    next();
    return;
  }
  env.extras.puncher.start('Get subforums');

  max_level = env.data.section.level + 2; // need two next levels
  query = {
    level: { $lte: max_level },
    parent_list: env.data.section._id
  };

  // FIXME add permissions check
  Section.find(query).sort('display_order').setOptions({ lean: true })
      .select(subforums_in_fields.join(' '))
      .exec(function(err, sections) {
    if (err) {
      next(err);
      return;
    }
    env.data.sections = sections;

    env.extras.puncher.stop({ count: sections.length });
    next();
  });
});

// Build response:
//  - forums list -> filtered tree
//  - collect users ids (last posters / moderators / threads authors + last)
//  - threads
//
nodeca.filters.after('@', function (params, next) {
  var env = this;

  var root, max_subforum_level;

  env.extras.puncher.start('Post-process forums/threads/users');

  //
  // Process sections
  //

  if (env.session.hb) {
    this.data.sections = this.data.sections.map(function(doc) {
      doc.cache.real = doc.cache.hb;
      return doc;
    });
  }

  env.data.users = env.data.users || [];
  max_subforum_level = env.data.section.level + 2;

  // collect users from subforums
  this.data.sections.forEach(function(doc) {
    // queue users only for first 2 levels (those are not displayed on level 3)
    if (doc.level < max_subforum_level) {
      if (!!doc.moderator_list) {
        doc.moderator_list.forEach(function(user) {
          env.data.users.push(user);
        });
      }
      if (doc.cache.real.last_user) {
        env.data.users.push(doc.cache.real.last_user);
      }
    }
  });

  root = this.data.section._id;
  this.response.data.sections = to_tree(this.data.sections, root);

  // Cleanup output tree - delete attributes, that are not white list.
  // Since tree points to the same objects, that are in flat list,
  // we use flat array for iteration.
  this.data.sections.forEach(function(doc) {
    for (var attr in doc) {
      if (doc.hasOwnProperty(attr) &&
          subforums_out_fields.indexOf(attr) === -1) {
        delete(doc[attr]);
      }
    }
    delete (doc.cache.hb);
  });

  //
  // Process threads
  //

  if (env.session.hb) {
    this.data.threads = this.data.threads.map(function(doc) {
      doc.cache.real = doc.cache.hb;
      return doc;
    });
  }

  // calculate pages number
  var posts_per_page = nodeca.settings.global.get('posts_per_page');
  this.data.threads.forEach(function(doc) {
    doc.cache._page_number = Math.floor(doc.cache.real.post_count / posts_per_page);
  });

  this.response.data.threads = this.data.threads;

  // collect users from threads
  this.data.threads.forEach(function(doc) {
    if (doc.cache.real.first_user) {
      env.data.users.push(doc.cache.real.first_user);
    }
    if (doc.cache.real.last_user) {
      env.data.users.push(doc.cache.real.last_user);
    }
  });

  env.extras.puncher.stop();

  next();
});

// Fill head meta & fetch/fill breadcrumbs
//
nodeca.filters.after('@', function (params, next) {
  var env = this;

  var threads_per_page;
  var query;
  var fields;
  var t_params;

  var data = this.response.data;
  var forum = this.data.section;

  if (this.session.hb) {
    forum.cache.real = forum.cache.hb;
  }

  // prepare page title
  data.head.title = forum.title;
  if (params.page > 1) {
    t_params = { title: forum.title, page: params.page };
    data.head.title = env.helpers.t('forum.title_with_page', t_params);
  }

  // prepare forum info
  data.forum = _.pick(forum, forum_info_out_fields);

  // prepare pagination data
  threads_per_page = nodeca.settings.global.get('threads_per_page');
  data.page = {
    max: Math.ceil(forum.cache.real.thread_count / threads_per_page),
    current: parseInt(params.page, 10),
  };

  // fetch breadcrumbs data
  query = { _id: { $in: forum.parent_list } };
  fields = { '_id': 1, 'id': 1, 'title': 1 };

  env.extras.puncher.start('Build breadcrumbs');

  Section.find(query).select(fields).sort({ 'level': 1 })
      .setOptions({ lean: true }).exec(function(err, parents){
    if (err) {
      next(err);
      return;
    }

    parents.push(forum);
    data.widgets.breadcrumbs = forum_breadcrumbs(env, parents);

    env.extras.puncher.stop();

    next();
  });
});
<commit_msg>Fixed calculation of number of pages for the micro-pagination<commit_after>"use strict";

/*global nodeca, _*/

var NLib = require('nlib');
var Async = NLib.Vendor.Async;

var Section = nodeca.models.forum.Section;
var Thread = nodeca.models.forum.Thread;

var forum_breadcrumbs = require('../../lib/forum_breadcrumbs.js');
var to_tree = require('../../lib/to_tree.js');

var threads_in_fields = [
  '_id',
  'id',
  'title',
  'prefix',
  'forum_id',
  '_views_count',
  'cache'
];

var subforums_in_fields = [
  '_id',
  'id',
  'title',
  'description',
  'parent',
  'parent_list',
  'moderator_list',
  'display_order',
  'level',
  'cache'
];

var subforums_out_fields = [
  '_id',
  'id',
  'title',
  'description',
  'moderator_list',
  'child_list',
  'cache'
];

var forum_info_out_fields = [
  'id',
  'title',
  'description',
  'is_category'
];

// Prefetch forum to simplify permisson check.
// Check that forum exists.
//
nodeca.filters.before('@', function (params, next) {
  var env = this;

  env.extras.puncher.start('Forum info prefetch');

  Section.findOne({ id: params.id }).setOptions({ lean: true })
      .exec(function(err, forum) {

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

    // No forum -> "Not Found" status
    if (!forum) {
      next({ statusCode: 404 });
      return;
    }

    env.data.section = forum;

    env.extras.puncher.stop();

    next(err);
  });
});

// fetch and prepare threads
//
// ##### params
//
// - `id`   forum id
//
module.exports = function (params, next) {
  var env = this;

  var sort = {};
  var start;
  var query;

  var threads_per_page = nodeca.settings.global.get('threads_per_page');

  env.response.data.show_page_number = false;

  env.extras.puncher.start('Get threads');
  env.extras.puncher.start('Thread ids prefetch');

  if (env.session.hb) {
    sort['cache.hb.last_ts'] = -1;
  }
  else {
    sort['cache.real.last_ts'] = -1;
  }

  // FIXME add state condition to select only visible threads
  start = (params.page - 1) * threads_per_page;

  // Fetch IDs of "visible" threads interval (use coverage index)
  Thread.find({ forum_id: params.id }).select('_id').sort(sort).skip(start)
      .limit(threads_per_page + 1).setOptions({ lean: true }).exec(function(err, docs) {

    if (!docs.length) {
      if (params.page > 1) {

        // FIXME Redirect to last page if possible

        // No page -> "Not Found" status
        next({ statusCode: 404 });
      }
      else {
        // category or forum without threads
        env.extras.puncher.stop();
        env.extras.puncher.stop();

        env.data.threads = [];

        next();
      }
      return;
    }

    env.extras.puncher.stop({ count: docs.length });
    env.extras.puncher.start('Get threads by _id list');

    // FIXME modify state condition (deleted and etc) if user has permission
    // If no hidden threads - no conditions needed, just select by IDs

    query = Thread.find({ forum_id: params.id }).where('_id').lte(_.first(docs)._id);
    if (docs.length <= threads_per_page) {
      query.gte(_.last(docs)._id);
    }
    else {
      query.gt(_.last(docs)._id);
    }

    // Select all allowed threads in calculated
    // interval: visible + deleted and others (if allowed by permissions)
    query.select(threads_in_fields.join(' ')).sort(sort)
        .setOptions({ lean: true }).exec(function(err, threads){
      if (err) {
        next(err);
        return;
      }

      env.data.threads = threads;

      env.extras.puncher.stop({ count: threads.length });
      env.extras.puncher.stop();

      next();
    });
  });
};

// fetch sub-forums (only on first page)
//
nodeca.filters.after('@', function (params, next) {
  var env = this;

  var max_level;
  var query;

  env.data.sections = [];
  // subforums fetched only on first page
  if (params.page > 1) {
    next();
    return;
  }
  env.extras.puncher.start('Get subforums');

  max_level = env.data.section.level + 2; // need two next levels
  query = {
    level: { $lte: max_level },
    parent_list: env.data.section._id
  };

  // FIXME add permissions check
  Section.find(query).sort('display_order').setOptions({ lean: true })
      .select(subforums_in_fields.join(' '))
      .exec(function(err, sections) {
    if (err) {
      next(err);
      return;
    }
    env.data.sections = sections;

    env.extras.puncher.stop({ count: sections.length });
    next();
  });
});

// Build response:
//  - forums list -> filtered tree
//  - collect users ids (last posters / moderators / threads authors + last)
//  - threads
//
nodeca.filters.after('@', function (params, next) {
  var env = this;

  var root, max_subforum_level;

  env.extras.puncher.start('Post-process forums/threads/users');

  //
  // Process sections
  //

  if (env.session.hb) {
    this.data.sections = this.data.sections.map(function(doc) {
      doc.cache.real = doc.cache.hb;
      return doc;
    });
  }

  env.data.users = env.data.users || [];
  max_subforum_level = env.data.section.level + 2;

  // collect users from subforums
  this.data.sections.forEach(function(doc) {
    // queue users only for first 2 levels (those are not displayed on level 3)
    if (doc.level < max_subforum_level) {
      if (!!doc.moderator_list) {
        doc.moderator_list.forEach(function(user) {
          env.data.users.push(user);
        });
      }
      if (doc.cache.real.last_user) {
        env.data.users.push(doc.cache.real.last_user);
      }
    }
  });

  root = this.data.section._id;
  this.response.data.sections = to_tree(this.data.sections, root);

  // Cleanup output tree - delete attributes, that are not white list.
  // Since tree points to the same objects, that are in flat list,
  // we use flat array for iteration.
  this.data.sections.forEach(function(doc) {
    for (var attr in doc) {
      if (doc.hasOwnProperty(attr) &&
          subforums_out_fields.indexOf(attr) === -1) {
        delete(doc[attr]);
      }
    }
    delete (doc.cache.hb);
  });

  //
  // Process threads
  //

  if (env.session.hb) {
    this.data.threads = this.data.threads.map(function(doc) {
      doc.cache.real = doc.cache.hb;
      return doc;
    });
  }

  // calculate pages number
  var posts_per_page = nodeca.settings.global.get('posts_per_page');
  this.data.threads.forEach(function(doc) {
    doc.cache._page_number = Math.ceil(doc.cache.real.post_count / posts_per_page);
  });

  this.response.data.threads = this.data.threads;

  // collect users from threads
  this.data.threads.forEach(function(doc) {
    if (doc.cache.real.first_user) {
      env.data.users.push(doc.cache.real.first_user);
    }
    if (doc.cache.real.last_user) {
      env.data.users.push(doc.cache.real.last_user);
    }
  });

  env.extras.puncher.stop();

  next();
});

// Fill head meta & fetch/fill breadcrumbs
//
nodeca.filters.after('@', function (params, next) {
  var env = this;

  var threads_per_page;
  var query;
  var fields;
  var t_params;

  var data = this.response.data;
  var forum = this.data.section;

  if (this.session.hb) {
    forum.cache.real = forum.cache.hb;
  }

  // prepare page title
  data.head.title = forum.title;
  if (params.page > 1) {
    t_params = { title: forum.title, page: params.page };
    data.head.title = env.helpers.t('forum.title_with_page', t_params);
  }

  // prepare forum info
  data.forum = _.pick(forum, forum_info_out_fields);

  // prepare pagination data
  threads_per_page = nodeca.settings.global.get('threads_per_page');
  data.page = {
    max: Math.ceil(forum.cache.real.thread_count / threads_per_page),
    current: parseInt(params.page, 10),
  };

  // fetch breadcrumbs data
  query = { _id: { $in: forum.parent_list } };
  fields = { '_id': 1, 'id': 1, 'title': 1 };

  env.extras.puncher.start('Build breadcrumbs');

  Section.find(query).select(fields).sort({ 'level': 1 })
      .setOptions({ lean: true }).exec(function(err, parents){
    if (err) {
      next(err);
      return;
    }

    parents.push(forum);
    data.widgets.breadcrumbs = forum_breadcrumbs(env, parents);

    env.extras.puncher.stop();

    next();
  });
});
<|endoftext|>


<commit_before>const express = require('express');
const config = require('../../config');
const models = require('../models');
const router = express.Router();
const net = require('net');
const cache = require('apicache').middleware;
const checkJwt = require('./../checkJwt');
const _ = require('lodash');
const rdToWgs = require('rdtowgs');
const request = require('request');
const md5 = require('md5');

function stringToInt(solution) {
  return solution.map((x) => [parseInt(x.split(' ')[0], 10), parseInt(x.split(' ')[1], 10)]);
}

function rdSolutionToWgs(solution) {
  return solution.map((x) => rdToWgs(x[0], x[1]));
}

function calcCrow(lat1, lon1, lat2, lon2) {
  const R = 6371; // km
  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);
  const latconst1 = toRad(lat1);
  const latconst2 = toRad(lat2);

  const a = (Math.sin(dLat / 2) * Math.sin(dLat / 2)) + (Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(latconst1) * Math.cos(latconst2));
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  const distance = R * c;
  return distance;
}

function toRad(value) {
  return (value * Math.PI) / 180;
}

function getClairvoyanceResult(rd, latestSolution) {
  // Convert new solution to wgs coordinates
  const wgs = rdSolutionToWgs(rd);
  const wgsLatest = rdSolutionToWgs(latestSolution);

  // Calculate euclidean distances
  const cost = wgs.map((x, i) => calcCrow(x[0], x[1], wgsLatest[i][0], wgsLatest[i][1]));
  const totalCost = _.sum(cost);

  return {
    wgs,
    rd,
    cost,
    totalCost,
  };
}

router.post('/', checkJwt, (req, res) => {
  // Get last hint data
  models.Hint.findAll({
    include: [{
      model: models.HintType,
    }, models.User, models.Subarea],
  }).then((hints) => {
    const groupedHints = _.groupBy(hints, 'Subarea.name');

    const groupedHintsList = [];

    const sort = _.keys(groupedHints).sort();

    for (const i in sort) {
      groupedHintsList.push(groupedHints[sort[i]]);
    }

    const sortedHints = _.map(groupedHintsList, (groupedHint) => _.sortBy(groupedHint, ['createdAt']));

    const lastHints = _.map(sortedHints, (sortedHint) => `${_.last(sortedHint).rdy} ${_.last(sortedHint).rdx}`);

    const client = new net.Socket();
    client.connect(config.clairvoyance.port, config.clairvoyance.ip, () => {
      if (lastHints.length === 6) {
        console.log([req.body.data[0], lastHints]);
        client.write(JSON.stringify([req.body.data[0], lastHints]));
      } else {
        console.log([req.body.data[0]]);
        client.write(JSON.stringify([req.body.data[0]]));
      }
    });

    client.on('data', (data) => {
      const result = {
      };
      try {
        if (JSON.parse(data)) {
          const parsedData = JSON.parse(data);

          result.best = getClairvoyanceResult(stringToInt(parsedData[0]), stringToInt(lastHints));

          result.other = parsedData[1].map((x) => getClairvoyanceResult(stringToInt(x), stringToInt(lastHints)));

          res.send(JSON.stringify(result).toString('utf8'));
        }
      } catch (err) {
        //
      }
    });
  });
});

/**
  Returns the MD5 sum of an url
  Cached for 10 minutes.
  @param query.url The url to get the MD5 sum from.
*/
router.get('/md5', cache('10 minutes'), (req, res) => {
  req.apicacheGroup = req.query.url;

  request(req.query.url, (error, response, body) => {
    res.send(md5(body));
  });
});

/**
 * Initializes Clairvoyance with latest known hint
 */
router.get('/init', cache('20 seconds'), (req, res) => {
  // Make a request to the cached api.
  request('http://localhost:3000/api/hint/api', async (error, response, body) => {
    // Parse response to JSON
    const data = JSON.parse(body).data;

    // Get latest hint
    const hint = data[0];

    // Loop subareas check the hint. A subarea may not be present in the object, so we check for existence.
    // The loop eventually turns back the MD5 sum of every image retrieved
    const result = await Promise.all(_.map(config.dbMappings.nArea, async (subarea) => {
      // Check if hint has key `subarea`
      if (subarea in hint) {
        const pictures = hint[subarea];

        // Loop every image in the picture list.
        const md5s = await Promise.all(_.map(pictures, async (picture) => {
          return new Promise(resolve =>
            // Make a request to retrieve MD5 sum
              request('http://localhost:3000/api/clairvoyance/md5?url=http:'+picture, async (error, response, body) => {
                if (!error)
                  resolve(body);
              }));
        }));
        return md5s;
      } else {
        // Return null if subarea isn't set.
        return null;
      }

    }));
    // List that determines whether the letter already has been used.
    const contains = []

    // List of letters that may be used.
    const letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'];

    // Loop over subareas
    const initState = _.map(result, (subarea) => {

      // Loop over md5 sums of each subarea
      let subareaState = _.map(subarea, (md5) => {
        // Define new letter for this md5sum if it doesn't exist.
        if (!contains.includes(md5)) {
          contains.push(md5);
        }
        // Get the letter that correcponds to this md5sum
        return letters[contains.indexOf(md5)];
      }).join("");

      // If no letters are set, then set X as letters
      if (subareaState == "") {
        subareaState = "XXXXXXXXXX";
      }

      // Add a space in the middle of the joined letterkey
      return subareaState.substr(0, 5) + " " + subareaState.substr(5);
    });

    // Send result to the client
    res.send(initState);
  });
});

module.exports = router;
<commit_msg>Changed function to function<commit_after>const express = require('express');
const config = require('../../config');
const models = require('../models');
const router = express.Router();
const net = require('net');
const cache = require('apicache').middleware;
const checkJwt = require('./../checkJwt');
const _ = require('lodash');
const rdToWgs = require('rdtowgs');
const request = require('request');
const md5 = require('md5');

function stringToInt(solution) {
  return solution.map((x) => [parseInt(x.split(' ')[0], 10), parseInt(x.split(' ')[1], 10)]);
}

function rdSolutionToWgs(solution) {
  return solution.map((x) => rdToWgs(x[0], x[1]));
}

function calcCrow(lat1, lon1, lat2, lon2) {
  const R = 6371; // km
  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);
  const latconst1 = toRad(lat1);
  const latconst2 = toRad(lat2);

  const a = (Math.sin(dLat / 2) * Math.sin(dLat / 2)) + (Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(latconst1) * Math.cos(latconst2));
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  const distance = R * c;
  return distance;
}

function toRad(value) {
  return (value * Math.PI) / 180;
}

function getClairvoyanceResult(rd, latestSolution) {
  // Convert new solution to wgs coordinates
  const wgs = rdSolutionToWgs(rd);
  const wgsLatest = rdSolutionToWgs(latestSolution);

  // Calculate euclidean distances
  const cost = wgs.map((x, i) => calcCrow(x[0], x[1], wgsLatest[i][0], wgsLatest[i][1]));
  const totalCost = _.sum(cost);

  return {
    wgs,
    rd,
    cost,
    totalCost,
  };
}

router.post('/', checkJwt, (req, res) => {
  // Get last hint data
  models.Hint.findAll({
    include: [{
      model: models.HintType,
    }, models.User, models.Subarea],
  }).then((hints) => {
    const groupedHints = _.groupBy(hints, 'Subarea.name');

    const groupedHintsList = [];

    const sort = _.keys(groupedHints).sort();

    for (const i in sort) {
      groupedHintsList.push(groupedHints[sort[i]]);
    }

    const sortedHints = _.map(groupedHintsList, (groupedHint) => _.sortBy(groupedHint, ['createdAt']));

    const lastHints = _.map(sortedHints, (sortedHint) => `${_.last(sortedHint).rdy} ${_.last(sortedHint).rdx}`);

    const client = new net.Socket();
    client.connect(config.clairvoyance.port, config.clairvoyance.ip, () => {
      if (lastHints.length === 6) {
        console.log([req.body.data[0], lastHints]);
        client.write(JSON.stringify([req.body.data[0], lastHints]));
      } else {
        console.log([req.body.data[0]]);
        client.write(JSON.stringify([req.body.data[0]]));
      }
    });

    client.on('data', (data) => {
      const result = {
      };
      try {
        if (JSON.parse(data)) {
          const parsedData = JSON.parse(data);

          result.best = getClairvoyanceResult(stringToInt(parsedData[0]), stringToInt(lastHints));

          result.other = parsedData[1].map((x) => getClairvoyanceResult(stringToInt(x), stringToInt(lastHints)));

          res.send(JSON.stringify(result).toString('utf8'));
        }
      } catch (err) {
        //
      }
    });
  });
});

/**
  Returns the MD5 sum of an url
  Cached for 10 minutes.
  @param query.url The url to get the MD5 sum from.
*/
router.get('/md5', cache('10 minutes'), (req, res) => {
  req.apicacheGroup = req.query.url;

  request(req.query.url, (error, response, body) => {
    res.send(md5(body));
  });
});

/**
 * Initializes Clairvoyance with latest known hint
 */
router.get('/init', cache('20 seconds'), (req, res) => {
  // Make a request to the cached api.
  request('http://localhost:3000/api/hint/api', async function (error, response, body) {
    // Parse response to JSON
    const data = JSON.parse(body).data;

    // Get latest hint
    const hint = data[0];

    // Loop subareas check the hint. A subarea may not be present in the object, so we check for existence.
    // The loop eventually turns back the MD5 sum of every image retrieved
    const result = await Promise.all(_.map(config.dbMappings.nArea, async function (subarea) {
      // Check if hint has key `subarea`
      if (subarea in hint) {
        const pictures = hint[subarea];

        // Loop every image in the picture list.
        const md5s = await Promise.all(_.map(pictures, async function (picture) {
          return new Promise(resolve =>
            // Make a request to retrieve MD5 sum
              request('http://localhost:3000/api/clairvoyance/md5?url=http:'+picture, async function (error, response, body) {
                if (!error)
                  resolve(body);
              }));
        }));
        return md5s;
      } else {
        // Return null if subarea isn't set.
        return null;
      }

    }));
    // List that determines whether the letter already has been used.
    const contains = []

    // List of letters that may be used.
    const letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'];

    // Loop over subareas
    const initState = _.map(result, (subarea) => {

      // Loop over md5 sums of each subarea
      let subareaState = _.map(subarea, (md5) => {
        // Define new letter for this md5sum if it doesn't exist.
        if (!contains.includes(md5)) {
          contains.push(md5);
        }
        // Get the letter that correcponds to this md5sum
        return letters[contains.indexOf(md5)];
      }).join("");

      // If no letters are set, then set X as letters
      if (subareaState == "") {
        subareaState = "XXXXXXXXXX";
      }

      // Add a space in the middle of the joined letterkey
      return subareaState.substr(0, 5) + " " + subareaState.substr(5);
    });

    // Send result to the client
    res.send(initState);
  });
});

module.exports = router;
<|endoftext|>


<commit_before>exports.DocumentXmlReader = DocumentXmlReader;

var q = require("q");
var _ = require("underscore");
var path = require("path");

var documents = require("./documents");
var Result = require("./results").Result;
var warning = require("./results").warning;

function DocumentXmlReader(relationships, contentTypes, docxFile, numbering) {
    function convertXmlToDocument(documentXml) {
        var body = documentXml.root.first("w:body");

        var result = readXmlElements(body.children)
            .map(function(children) {
                return new documents.Document(children);
            });
        result.document = result.value;
        return result;
    }

    function readXmlElements(elements) {
        var results = elements.map(readXmlElement);
        return Result.combine(results);
    }

    function readXmlElement(element) {
        if (element.type === "element") {
            var handler = xmlElementReaders[element.name];
            if (handler) {
                return handler(element);
            } else if (!Object.prototype.hasOwnProperty.call(ignoreElements, element.name)) {
                return new Result(
                    [],
                    [warning("An unrecognised element was ignored: " + element.name)]
                );
            }
        }
        return new Result([]);
    }

    function readChildElements(element) {
        return readXmlElements(element.children);
    }

    var xmlElementReaders = {
        "w:p": function(element) {
            return readXmlElements(element.children)
                .map(function(children) {
                    var properties = _.find(children, isParagraphProperties);
                    return new documents.Paragraph(
                        children.filter(negate(isParagraphProperties)),
                        properties
                    );
                });
        },
        "w:pPr": function(element) {
            var properties = {
                type: "paragraphProperties"
            };

            var styleElement = element.first("w:pStyle");
            if (styleElement) {
                properties.styleName = styleElement.attributes["w:val"];
            }
            var alignElement = element.first("w:jc");
            if (alignElement) {
                properties.alignment = alignElement.attributes["w:val"];
                if (properties.alignment == 'center') {
                    properties.styleName = "CenteredHeading";
                }
            }
            var numberingPropertiesElement = element.first("w:numPr");
            if (numberingPropertiesElement) {
                var levelElement = numberingPropertiesElement.first("w:ilvl");
                var level = levelElement.attributes["w:val"];
                var numId = numberingPropertiesElement.first("w:numId").attributes["w:val"];
                properties.numbering = numbering.findLevel(numId, level);
            }

            return new Result(properties);
        },
        "w:r": function(element) {
            return readXmlElements(element.children)
                .map(function(children) {
                    var properties = _.find(children, isRunProperties);

                    return new documents.Run(
                        children.filter(negate(isRunProperties)),
                        properties
                    );
                });
        },
        "w:rPr": function(element) {
            var properties = {
                type: "runProperties"
            };

            var styleElement = element.first("w:rStyle");
            if (styleElement) {
                properties.styleName = styleElement.attributes["w:val"];
            }
            properties.isBold = !!element.first("w:b");
            properties.isItalic = !!element.first("w:i");

            return new Result(properties);
        },
        "w:t": function(element) {
            return new Result(new documents.Text(element.children[0].value));
        },
        "w:tab": function(element) {
            return new Result(new documents.Tab());
        },
        "w:hyperlink": function(element) {
            var relationshipId = element.attributes["r:id"];
            return readXmlElements(element.children).map(function(children) {
                if (relationshipId) {
                    var href = relationships[relationshipId].target;
                    return new documents.Hyperlink(children, {href: href});
                } else {
                    return children;
                }
            });
        },

        "w:ins": readChildElements,
        "w:smartTag": readChildElements,
        "w:drawing": readChildElements,
        "wp:inline": readDrawingElement,
        "wp:anchor": readDrawingElement
    };
    return {
        convertXmlToDocument: convertXmlToDocument,
        readXmlElement: readXmlElement
    };

    function readDrawingElement(element) {
        var blips = element
            .getElementsByTagName("a:graphic")
            .getElementsByTagName("a:graphicData")
            .getElementsByTagName("pic:pic")
            .getElementsByTagName("pic:blipFill")
            .getElementsByTagName("a:blip");

        var results = blips.map(function(blip) {
            var relationshipId = blip.attributes["r:embed"];
            var imagePath = path.join("word", relationships[relationshipId].target);
            var readImage = docxFile.read.bind(docxFile, imagePath);
            var altText = element.first("wp:docPr").attributes.descr;

            var image = documents.Image({
                readImage: readImage,
                altText: altText,
                contentType: contentTypes.findContentType(imagePath)
            });
            return new Result(image);
        });

        return Result.combine(results);
    }
}

var ignoreElements = {
    "w:bookmarkStart": true,
    "w:bookmarkEnd": true,
    "w:sectPr": true,
    "w:proofErr": true,
    "w:lastRenderedPageBreak": true,
    "w:commentRangeStart": true,
    "w:commentRangeEnd": true,
    "w:commentReference": true,
    "w:del": true
};

function notNull(value) {
    return value !== null;
}

function isParagraphProperties(element) {
    return element.type === "paragraphProperties";
}

function isRunProperties(element) {
    return element.type === "runProperties";
}

function negate(predicate) {
    return function(value) {
        return !predicate(value);
    };
}
<commit_msg>Don't set styleName from alignment if already set.<commit_after>exports.DocumentXmlReader = DocumentXmlReader;

var q = require("q");
var _ = require("underscore");
var path = require("path");

var documents = require("./documents");
var Result = require("./results").Result;
var warning = require("./results").warning;

function DocumentXmlReader(relationships, contentTypes, docxFile, numbering) {
    function convertXmlToDocument(documentXml) {
        var body = documentXml.root.first("w:body");

        var result = readXmlElements(body.children)
            .map(function(children) {
                return new documents.Document(children);
            });
        result.document = result.value;
        return result;
    }

    function readXmlElements(elements) {
        var results = elements.map(readXmlElement);
        return Result.combine(results);
    }

    function readXmlElement(element) {
        if (element.type === "element") {
            var handler = xmlElementReaders[element.name];
            if (handler) {
                return handler(element);
            } else if (!Object.prototype.hasOwnProperty.call(ignoreElements, element.name)) {
                return new Result(
                    [],
                    [warning("An unrecognised element was ignored: " + element.name)]
                );
            }
        }
        return new Result([]);
    }

    function readChildElements(element) {
        return readXmlElements(element.children);
    }

    var xmlElementReaders = {
        "w:p": function(element) {
            return readXmlElements(element.children)
                .map(function(children) {
                    var properties = _.find(children, isParagraphProperties);
                    return new documents.Paragraph(
                        children.filter(negate(isParagraphProperties)),
                        properties
                    );
                });
        },
        "w:pPr": function(element) {
            var properties = {
                type: "paragraphProperties"
            };

            var styleElement = element.first("w:pStyle");
            if (styleElement) {
                properties.styleName = styleElement.attributes["w:val"];
            }
            var alignElement = element.first("w:jc");
            if (alignElement) {
                properties.alignment = alignElement.attributes["w:val"];
                if (properties.alignment == 'center' && !properties.styleName) {
                    properties.styleName = "CenteredHeading";
                }
            }
            var numberingPropertiesElement = element.first("w:numPr");
            if (numberingPropertiesElement) {
                var levelElement = numberingPropertiesElement.first("w:ilvl");
                var level = levelElement.attributes["w:val"];
                var numId = numberingPropertiesElement.first("w:numId").attributes["w:val"];
                properties.numbering = numbering.findLevel(numId, level);
            }

            return new Result(properties);
        },
        "w:r": function(element) {
            return readXmlElements(element.children)
                .map(function(children) {
                    var properties = _.find(children, isRunProperties);

                    return new documents.Run(
                        children.filter(negate(isRunProperties)),
                        properties
                    );
                });
        },
        "w:rPr": function(element) {
            var properties = {
                type: "runProperties"
            };

            var styleElement = element.first("w:rStyle");
            if (styleElement) {
                properties.styleName = styleElement.attributes["w:val"];
            }
            properties.isBold = !!element.first("w:b");
            properties.isItalic = !!element.first("w:i");

            return new Result(properties);
        },
        "w:t": function(element) {
            return new Result(new documents.Text(element.children[0].value));
        },
        "w:tab": function(element) {
            return new Result(new documents.Tab());
        },
        "w:hyperlink": function(element) {
            var relationshipId = element.attributes["r:id"];
            return readXmlElements(element.children).map(function(children) {
                if (relationshipId) {
                    var href = relationships[relationshipId].target;
                    return new documents.Hyperlink(children, {href: href});
                } else {
                    return children;
                }
            });
        },

        "w:ins": readChildElements,
        "w:smartTag": readChildElements,
        "w:drawing": readChildElements,
        "wp:inline": readDrawingElement,
        "wp:anchor": readDrawingElement
    };
    return {
        convertXmlToDocument: convertXmlToDocument,
        readXmlElement: readXmlElement
    };

    function readDrawingElement(element) {
        var blips = element
            .getElementsByTagName("a:graphic")
            .getElementsByTagName("a:graphicData")
            .getElementsByTagName("pic:pic")
            .getElementsByTagName("pic:blipFill")
            .getElementsByTagName("a:blip");

        var results = blips.map(function(blip) {
            var relationshipId = blip.attributes["r:embed"];
            var imagePath = path.join("word", relationships[relationshipId].target);
            var readImage = docxFile.read.bind(docxFile, imagePath);
            var altText = element.first("wp:docPr").attributes.descr;

            var image = documents.Image({
                readImage: readImage,
                altText: altText,
                contentType: contentTypes.findContentType(imagePath)
            });
            return new Result(image);
        });

        return Result.combine(results);
    }
}

var ignoreElements = {
    "w:bookmarkStart": true,
    "w:bookmarkEnd": true,
    "w:sectPr": true,
    "w:proofErr": true,
    "w:lastRenderedPageBreak": true,
    "w:commentRangeStart": true,
    "w:commentRangeEnd": true,
    "w:commentReference": true,
    "w:del": true
};

function notNull(value) {
    return value !== null;
}

function isParagraphProperties(element) {
    return element.type === "paragraphProperties";
}

function isRunProperties(element) {
    return element.type === "runProperties";
}

function negate(predicate) {
    return function(value) {
        return !predicate(value);
    };
}
<|endoftext|>


<commit_before>var htmlparser  = require('htmlparser2');
var domutils    = require('domutils');

module.exports = function(html, allowable_tags) {
    var allowable_tags = (allowable_tags === undefined ? '' : allowable_tags);
    var tags = parseAllowableTags(allowable_tags);
    var strippedDom = [];
    var parser = new htmlparser.Parser(new htmlparser.DomHandler(function(error, dom) {
        strippedDom = stripDom(dom, tags);
    }));
    parser.write(html);
    parser.end();

    return strippedDom ? strippedDom.map(domutils.getOuterHTML).join('') : '';
};

function stripDom(element, allowed_tags) {
    if (Array.isArray(element)) {
        var results = [];
        element.forEach(function(elem) {
            var stripped = stripDom(elem, allowed_tags);
            if (Array.isArray(stripped)) {
                results = results.concat(stripped);
            } else if (stripped) {
                results.push(stripped);
            }
        });

        return (results.length ? results : null);
    }

    if (element.type == 'tag') {
        if (element.children) {
            element.children = stripDom(element.children, allowed_tags);
        }

        if (!(element.name in allowed_tags)) {
            return element.children;
        } else {
            return element;
        }
    }

    return element;
}

var tagRegex = /<(w+)>/g;
function parseAllowableTags(allowable_tags) {
    var tagRegex = /<(\w+)>/g;
    var match;
    var tags = {};
    while (match = tagRegex.exec(allowable_tags)) {
        tags[match[1]] = true;
    }
    return tags;
}
<commit_msg>Code cleanup<commit_after>var htmlparser  = require('htmlparser2');
var domutils    = require('domutils');

module.exports = function(html, allowable_tags) {
    var allowed_tags = parseAllowableTags(allowable_tags),
        strippedDom = [],
        domhandler = new htmlparser.DomHandler(function(error, dom) {
            if (!error) {
                strippedDom = stripDom(dom, allowed_tags);
            }
        }),
        parser = new htmlparser.Parser(domhandler);

    parser.write(html);
    parser.end();

    return strippedDom.map(domutils.getOuterHTML).join('');
};

function stripDom(element, allowed_tags) {
    if (Array.isArray(element)) {
        return element.reduce(function(previous, current) {
            return previous.concat(stripDom(current, allowed_tags));
        }, []).filter(Object);
    }

    if (element.type == 'tag') {
        if (element.children) {
            element.children = stripDom(element.children, allowed_tags);
        }

        return (element.name in allowed_tags ? element : element.children);
    }

    return element;
}

var tagRegex = /<(w+)>/g;
function parseAllowableTags(allowable_tags) {
    var tagRegex = /<(\w+)>/g,
        tags = {},
        match;

    while (match = tagRegex.exec(allowable_tags)) {
        tags[match[1]] = true;
    }
    return tags;
}
<|endoftext|>


<commit_before>'use strict';

var helpers = require('../helpers'),
    yaml = require('js-yaml'),
    fs = require('fs'),
    path = require('path');

var properties = yaml.safeLoad(fs.readFileSync(path.join(__dirname, '../../data', 'properties.yml'), 'utf8')).split(' ');

module.exports = {
  'name': 'no-misspelled-properties',
  'defaults': {
    'extra-properties': []
  },
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('property', function (node) {
      if (node.first().is('ident')) {
        var curProperty = node.first().content;

        if (curProperty.charAt(0) === '-') {
          curProperty = helpers.stripPrefix(curProperty);
        }

        if (curProperty.length > 0 && properties.indexOf(curProperty) === -1 && parser.options['extra-properties'].indexOf(curProperty) === -1) {
          result = helpers.addUnique(result, {
            'ruleId': parser.rule.name,
            'line': node.start.line,
            'column': node.start.column,
            'message': 'Property `' + curProperty + '` appears to be spelled incorrectly',
            'severity': parser.severity
          });
        }
      }
    });
    return result;
  }
};
<commit_msg>:bug: Fix issue with partially matching property names<commit_after>'use strict';

var helpers = require('../helpers'),
    yaml = require('js-yaml'),
    fs = require('fs'),
    path = require('path');

var properties = yaml.safeLoad(fs.readFileSync(path.join(__dirname, '../../data', 'properties.yml'), 'utf8')).split(' ');

/**
 * Get all valid properties
 *
 * @param {Array} props - The list of default valid properties
 * @param {Array} extras - The user specified list of valid properties
 * @returns {Array} Combined list
 */
var getCombinedList = function (props, extras) {
  return Object.assign([], props, extras);
};

/**
 * Check for partial match
 *
 * @param {string} prop - The prop to validate
 * @param {Array} props - Array of valid properties
 * @returns {Boolean} Whether prop partially matches list or not
 */
var isPartialStringMatch = function (prop, props) {
  for (var i = 0; i < props.length; i++) {
    if (props[i].indexOf(prop) >= 0) {
      return true;
    }
  }

  return false;
};

module.exports = {
  'name': 'no-misspelled-properties',
  'defaults': {
    'extra-properties': []
  },
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('property', function (node) {
      if (node.first().is('ident')) {
        var curProperty = node.first().content,
            propertyList = getCombinedList(properties, parser.options['extra-properties']);

        if (curProperty.charAt(0) === '-') {
          curProperty = helpers.stripPrefix(curProperty);
        }

        if (isPartialStringMatch(curProperty, propertyList)) {
          return false;
        }

        if (curProperty.length > 0) {
          result = helpers.addUnique(result, {
            'ruleId': parser.rule.name,
            'line': node.start.line,
            'column': node.start.column,
            'message': 'Property `' + curProperty + '` appears to be spelled incorrectly',
            'severity': parser.severity
          });
        }
      }

      return false;
    });

    return result;
  }
};
<|endoftext|>


<commit_before>var DeviceHandle = require('linux-device');
var MPR121 = require('node-picap');
var mpr121;

var p1Left = 4;
var p1Right = 5;
var p1Up = 6;
var p1Down = 7;

var p2Left = 8;
var p2Right = 9;
var p2Up = 10;
var p2Down = 11;

var p1Start = 12;
var p1Back = 13;

var device = new DeviceHandle('/dev/hidg0', true, 16, function(err, data) {
    if(err) return console.log("ERROR:", err);
    console.log("received interval:", data.readUInt32LE(0).toString(16));
});

parsePressedKeys = function(data) {
  var pressedKeys = [];
  data.forEach(function(electrode, i) {
    if (electrode.isNewTouch) {
      switch(i) {
        case 0:
          pressedKeys.push(p1Left);
          break;
        case 1:
          pressedKeys.push(p1Right);
          break;
        case 2:
          pressedKeys.push(p1Up);
          break;
        case 3:
          pressedKeys.push(p1Down);
          break;
        case 4:
          pressedKeys.push(p2Left);
          break;
        case 5:
          pressedKeys.push(p2Right);
          break;
        case 6:
          pressedKeys.push(p2Up);
          break;
        case 7:
          pressedKeys.push(p2Down);
          break;
        case 8:
          pressedKeys.push(p2Up);
          break;
        case 9:
          pressedKeys.push(p1Start);
          break;
        case 10:
          pressedKeys.push(p1Back);
          break;
      }
    }
  });
  return pressedKeys;
}

keystrokeFromPressedKeys = function(pressedKeys) {
  keystroke = "\\0\\0";
  pressedKeys.forEach(function(key) {
    keystroke += "\\" + key;
  });
  while(keystroke.length < 16) {
    keystroke += "\\0";
  }
  return keystroke.substring(0, 16);
}

// correct address for the Pi Cap - other boards may vary
mpr121 = new MPR121('0x5C');
mpr121.setTouchThreshold(40);
mpr121.setReleaseThreshold(20);

mpr121.on('data', function(data) {
  keys = parsePressedKeys(data);
  keystroke = keystrokeFromPressedKeys(keys);
  device.write(keystroke, function(err) {
  });
  console.log(spawn.execSync('echo -ne "' + keystroke + '" > /dev/hidg0').toString());
});

process.on('SIGINT', function () {
  device.close();
  process.exit(0);
});
<commit_msg>Add finished implementation (for now)<commit_after>var DeviceHandle = require('linux-device');
var MPR121 = require('node-picap');
var mpr121;

var p1Left = 0x04; // A
var p1Right = 0x05; // B
var p1Up = 0x06; // C
var p1Down = 0x07; // D

var p2Left = 0x08; // E
var p2Right = 0x09; // F
var p2Up = 0x0a; // G
var p2Down = 0x0b; // H

var p1Start = 0x0c; // I
var p1Back = 0x0d; // J

// Open up access to the USB interface
var device = new DeviceHandle('/dev/hidg0', true, 16, function(err, data) {
  if(err) return console.log("ERROR:", err);
  console.log("received interval:", data.readUInt32LE(0).toString(16));
});

parsePressedKeys = function(data) {
  var pressedKeys = [];
  data.forEach(function(electrode, i) {
    if (electrode.isTouched) {
      switch(i) {
        case 0:
          pressedKeys.push(p1Left);
          break;
        case 1:
          pressedKeys.push(p1Right);
          break;
        case 2:
          pressedKeys.push(p1Up);
          break;
        case 3:
          pressedKeys.push(p1Down);
          break;
        case 4:
          pressedKeys.push(p2Left);
          break;
        case 5:
          pressedKeys.push(p2Right);
          break;
        case 6:
          pressedKeys.push(p2Up);
          break;
        case 7:
          pressedKeys.push(p2Down);
          break;
        case 8:
          pressedKeys.push(p2Up);
          break;
        case 9:
          pressedKeys.push(p1Start);
          break;
        case 10:
          pressedKeys.push(p1Back);
          break;
      }
    }
  });
  return pressedKeys;
}

keystrokeFromPressedKeys = function(pressedKeys) {
  keystroke = [0x00, 0x00];
  pressedKeys.forEach(function(key) {
    keystroke.push(key);
  });
  while(keystroke.length < 8) {
    keystroke.push(0x00);
  }
  return keystroke.slice(0, 8);
}

// Set up the picap
mpr121 = new MPR121('0x5C');
mpr121.setTouchThreshold(40);
mpr121.setReleaseThreshold(20);

// Process touches
mpr121.on('data', function(data) {
  keys = parsePressedKeys(data);
  keystroke = keystrokeFromPressedKeys(keys);
  try {
    // Keystroke needs to be a byte array
    var buffer = Uint8Array.from(keystroke);
    device.write(buffer, function(err) {
    });
  } catch(e) {
    console.log("ERROR: ", e);
  }
});

process.on('SIGINT', function () {
  device.close();
  process.exit(0);
});
<|endoftext|>


<commit_before>'use strict';

angular.module('ITS.homeController', ['ngRoute', 'ITS.user.authentication'])

    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/home', {
            templateUrl: 'home/home.html',
            controller: 'homeController'
        });
    }])

    .controller('homeController',
    ['$scope', 'authentication', '$location',
        function ($scope, authentication, $location) {
            if(authentication.isAuthenticated()){
                $location.path('/dashboard')
            }

            $scope.authentication = authentication;

            $scope.login = function (user) {

                authentication.loginUser(user)
                    .then(function () {
                        $location.path("/dashboard")
                    })
            };

            $scope.register = function (user) {

                authentication.registerUser(user)
                    .then(function () {
                        authentication.loginUser(user)
                            .then(function () {
                                $location.path("/dashboard")
                            })

                    })
            };

            $scope.logout = function() {
                authentication.logout();
                $location.path("/")
            };

            $scope.getUsers = function () {
                authentication.getAllUsers()
                    .then(function (response) {

                    })
            };

        }]);

<commit_msg>homeContrller to Controller folder<commit_after><|endoftext|>


<commit_before>(function() {
    //Toggle the highlight option and set it in LocalStorage
    var objOptionAddHighlight = document.getElementById('ext-etheraddresslookup-show_style');
    if(objOptionAddHighlight) {
        objOptionAddHighlight.addEventListener('click', toggleMatchHighlight);
    }

    //Select the blockchain explorer set it in LocalStorage
    var objOptionBlockchainExplorer = document.getElementById('ext-etheraddresslookup-choose_blockchain');
    if(objOptionBlockchainExplorer) {
        objOptionBlockchainExplorer.addEventListener('change', toggleBlockchainExplorer);
    }

    //Toggle the blacklist domains option and set it in LocalStorage
    var objBlacklistDomains = document.getElementById('ext-etheraddresslookup-blacklist_domains');
    if(objBlacklistDomains) {
        objBlacklistDomains.addEventListener('click', toggleBlacklistDomains);
    }

    //Get the extension version
    var objManifest = chrome.runtime.getManifest();
    var objManifestVersion = document.getElementById('ext-manifest_version');
    if(objManifestVersion) {
        objManifestVersion.innerHTML = objManifest.version;
    }

    //init getting blacklisted domains
    getBlacklistedDomains();
    setInterval(function() {
        console.log("Re-caching domains");
        getBlacklistedDomains();
    }, 180000);

})();

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        var strOption = request.func;
        var strResponse = "";

        switch(strOption) {
            case 'highlight_option' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-show_style");
                break;
            case 'blockchain_explorer' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-blockchain_explorer");
                break;
            case 'blacklist_domains' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-blacklist_domains");
                }
                break;
            case 'blacklist_domain_list' :
                console.log("Getting domain list");
                strResponse = getBlacklistedDomains();
                break;
            default:
                strResponse = "unsupported";
                break;
        }

        sendResponse({resp:strResponse});
    }
);

function getBlacklistedDomains()
{
    var objBlacklistedDomains = {"timestamp":0,"domains":[]};
    //See if we need to get the blacklisted domains - ie: do we have them cached?
    if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list") === null) {
        objBlacklistedDomains = getBlacklistedDomainsFromSource();
    } else {
        var objBlacklistedDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        //Check to see if the cache is older than 5 minutes, if so re-cache it.
        objBlacklistedDomains = JSON.parse(objBlacklistedDomains);
        console.log("Domains last fetched: " + (Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) + " seconds ago");
        if ((Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) > 180) {
            console.log("Caching blacklisted domains again.");
            objBlacklistedDomains = getBlacklistedDomainsFromSource();
        }
    }

    return objBlacklistedDomains.domains;
}

function getBlacklistedDomainsFromSource()
{
    console.log("Getting blacklist from GitHub now");
    var objAjax = new XMLHttpRequest();
    objAjax.open("GET", "https://raw.githubusercontent.com/409H/EtherAddressLookup/master/blacklists/domains.json", true);
    objAjax.send();
    objAjax.onreadystatechange = function () {
        if (objAjax.readyState === 4) {
            var arrBlacklistedDomains = JSON.parse(objAjax.responseText);
            var objBlacklist = {};
            objBlacklist.timestamp = Math.floor(Date.now() / 1000);
            objBlacklist.domains = arrBlacklistedDomains;
            localStorage.setItem("ext-etheraddresslookup-blacklist_domains_list", JSON.stringify(objBlacklist));
            return objBlacklist;
        }
    }
    return {"timestamp":0,"domains":[]};
}<commit_msg>Added logic to fetch and cache the whitelisted domains<commit_after>(function() {
    //Toggle the highlight option and set it in LocalStorage
    var objOptionAddHighlight = document.getElementById('ext-etheraddresslookup-show_style');
    if(objOptionAddHighlight) {
        objOptionAddHighlight.addEventListener('click', toggleMatchHighlight);
    }

    //Select the blockchain explorer set it in LocalStorage
    var objOptionBlockchainExplorer = document.getElementById('ext-etheraddresslookup-choose_blockchain');
    if(objOptionBlockchainExplorer) {
        objOptionBlockchainExplorer.addEventListener('change', toggleBlockchainExplorer);
    }

    //Toggle the blacklist domains option and set it in LocalStorage
    var objBlacklistDomains = document.getElementById('ext-etheraddresslookup-blacklist_domains');
    if(objBlacklistDomains) {
        objBlacklistDomains.addEventListener('click', toggleBlacklistDomains);
    }

    //Get the extension version
    var objManifest = chrome.runtime.getManifest();
    var objManifestVersion = document.getElementById('ext-manifest_version');
    if(objManifestVersion) {
        objManifestVersion.innerHTML = objManifest.version;
    }

    //init getting blacklisted domains
    getBlacklistedDomains();
    setInterval(function() {
        console.log("Re-caching blacklisted domains");
        getBlacklistedDomains();
    }, 180000);

    getWhitelistedDomains();
    setInterval(function() {
        console.log("Re-caching whitelisted domains");
        getWhitelistedDomains();
    }, 180000);
})();

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        var strOption = request.func;
        var strResponse = "";

        switch(strOption) {
            case 'highlight_option' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-show_style");
                break;
            case 'blockchain_explorer' :
                strResponse = localStorage.getItem("ext-etheraddresslookup-blockchain_explorer");
                break;
            case 'blacklist_domains' :
                //This option is enabled by default
                if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains") === null) {
                    strResponse = 1;
                } else {
                    strResponse = localStorage.getItem("ext-etheraddresslookup-blacklist_domains");
                }
                break;
            case 'blacklist_domain_list' :
                console.log("Getting blacklisted domain list");
                strResponse = getBlacklistedDomains();
                break;
            case 'whitelist_domain_list' :
                console.log("Getting whitelisted domain list");
                strResponse = getWhitelistedDomains();
                break;
            default:
                strResponse = "unsupported";
                break;
        }

        sendResponse({resp:strResponse});
    }
);

//@todo - make these nicer and so they're not duplicated
function getBlacklistedDomains()
{
    var objBlacklistedDomains = {"timestamp":0,"domains":[]};
    //See if we need to get the blacklisted domains - ie: do we have them cached?
    if(localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list") === null) {
        objBlacklistedDomains = getBlacklistedDomainsFromSource();
    } else {
        var objBlacklistedDomains = localStorage.getItem("ext-etheraddresslookup-blacklist_domains_list");
        //Check to see if the cache is older than 5 minutes, if so re-cache it.
        objBlacklistedDomains = JSON.parse(objBlacklistedDomains);
        console.log("Domains last fetched: " + (Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) + " seconds ago");
        if ((Math.floor(Date.now() / 1000) - objBlacklistedDomains.timestamp) > 180) {
            console.log("Caching blacklisted domains again.");
            objBlacklistedDomains = getBlacklistedDomainsFromSource();
        }
    }

    return objBlacklistedDomains.domains;
}

function getWhitelistedDomains()
{
    var objWhitelistedDomains = {"timestamp":0,"domains":[]};
    //See if we need to get the blacklisted domains - ie: do we have them cached?
    if(localStorage.getItem("ext-etheraddresslookup-whitelist_domains_list") === null) {
        objWhitelistedDomains = getWhitelistedDomainsFromSource();
    } else {
        var objWhitelistedDomains = localStorage.getItem("ext-etheraddresslookup-whitelist_domains_list");
        //Check to see if the cache is older than 5 minutes, if so re-cache it.
        objWhitelistedDomains = JSON.parse(objWhitelistedDomains);
        console.log("Whitelisted domains last fetched: " + (Math.floor(Date.now() / 1000) - objWhitelistedDomains.timestamp) + " seconds ago");
        if ((Math.floor(Date.now() / 1000) - objWhitelistedDomains.timestamp) > 180) {
            console.log("Caching blacklisted domains again.");
            objWhitelistedDomains = getWhitelistedDomainsFromSource();
        }
    }

    return objWhitelistedDomains.domains;
}

function getBlacklistedDomainsFromSource()
{
    console.log("Getting blacklist from GitHub now");
    var objAjax = new XMLHttpRequest();
    objAjax.open("GET", "https://raw.githubusercontent.com/409H/EtherAddressLookup/master/blacklists/domains.json", true);
    objAjax.send();
    objAjax.onreadystatechange = function () {
        if (objAjax.readyState === 4) {
            var arrBlacklistedDomains = JSON.parse(objAjax.responseText);
            var objBlacklist = {};
            objBlacklist.timestamp = Math.floor(Date.now() / 1000);
            objBlacklist.domains = arrBlacklistedDomains;
            localStorage.setItem("ext-etheraddresslookup-blacklist_domains_list", JSON.stringify(objBlacklist));
            return objBlacklist;
        }
    }
    return {"timestamp":0,"domains":[]};
}

function getWhitelistedDomainsFromSource()
{
    console.log("Getting whitelist from GitHub now");
    var objAjax = new XMLHttpRequest();
    objAjax.open("GET", "https://raw.githubusercontent.com/409H/EtherAddressLookup/master/whitelists/domains.json", true);
    objAjax.send();
    objAjax.onreadystatechange = function () {
        if (objAjax.readyState === 4) {
            var arrWhitelistedDomains = JSON.parse(objAjax.responseText);
            var objWhitelist = {};
            objWhitelist.timestamp = Math.floor(Date.now() / 1000);
            objWhitelist.domains = arrWhitelistedDomains;
            localStorage.setItem("ext-etheraddresslookup-whitelist_domains_list", JSON.stringify(objWhitelist));
            return objWhitelist;
        }
    }
    return {"timestamp":0,"domains":[]};
}<|endoftext|>