<commit_before>const DirEntry = require('./DirEntry.js');
const deasync = require('deasync');
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
const ffprobe = deasync(ffmpeg.ffprobe);

module.exports = class MediaFile extends DirEntry {

	constructor(name, path, playUrl) {
		super('file', name, path);
		var playUrl = playUrl;
		// parse tag metadata
		var format = '';
		var tracks = 1;
		var disc = '';
		var track = '';
		var title = name;
		var artist = '';
		var album = '';
		var duration = 1200;
		var gain = '0dB';
		try {
			var metadata = ffprobe(path);
			// console.log(metadata);
			format = metadata.format.format_name;
			var tags = metadata.format.tags;
			if (tags != null) {
				// console.log(tags);
				// tracks
				if (tags.tracks != null) {
					tracks = Number(tags.tracks);
				}
				// disc
				if (tags.disc != null) {
					disc = tags.disc;
				}
				if (tags.DISC != null) {
					disc = tags.DISC;
				}
				// track
				if (tags.track != null) {
					track = tags.track;
				}
				if (tags.TRACK != null) {
					track = tags.TRACK;
				}
				var slashIndex = track.indexOf('/');
				if (slashIndex > 0) {
					track = track.substring(0, slashIndex);
				}
				// title
				if (tags.title != null) {
					title = tags.title;
				}
				if (tags.TITLE != null) {
					title = tags.TITLE;
				}
				if (tags.song != null) {
					title = tags.song;
				}
				// artist
				if (tags.artist != null) {
					artist = tags.artist;
				}
				if (tags.ARTIST != null) {
					artist = tags.ARTIST;
				}
				if (tags.author != null) {
					artist = tags.author;
				}
				// album
				if (tags.album != null) {
					album = tags.album;
				}
				if (tags.ALBUM != null) {
					album = tags.ALBUM;
				}
				if (tags.game != null) {
					album = tags.game;
				}
				// duration
				if (metadata.format.duration != null && typeof metadata.format.duration == 'number') {
					duration = metadata.format.duration;
				}
				// gain
				if (tags.replaygain_track_gain != null) {
					gain = tags.replaygain_track_gain;
				}
				if (tags.REPLAYGAIN_TRACK_GAIN != null) {
					gain = tags.REPLAYGAIN_TRACK_GAIN;
				}
				if (tags.replaygain_album_gain != null) {
					gain = tags.replaygain_album_gain;
				}
				if (tags.REPLAYGAIN_ALBUM_GAIN != null) {
					gain = tags.REPLAYGAIN_ALBUM_GAIN;
				}
				gain = gain.replace(/\s/g, '');
			}
			if (disc.length > 0) {
				if (track.length < 2) {
					track = '0' + track;
				}
				track = disc + '.' + track;
			}
			playUrl += '&duration=' + duration + '&gain=' + gain;
		} catch (err) {
			console.log('Error while reading metadata for ' + path + '\n' + err);
		}

		this.tracks = [];
		for (var i = 0; i < tracks; i++) {
			var details = {};
			details.playUrl = playUrl + '&track_index=' + i;
			details.format = format;
			if (tracks > 1) {
				details.track = i + 1;
			} else {
				details.track = track;
			}
			details.title = title;
			details.artist = artist;
			details.album = album;
			details.duration = duration;
			details.gain = gain;
			this.tracks.push(details);
		}
	}

}
<commit_msg>use track gain<commit_after>const DirEntry = require('./DirEntry.js');
const deasync = require('deasync');
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
const ffprobe = deasync(ffmpeg.ffprobe);

module.exports = class MediaFile extends DirEntry {

	constructor(name, path, playUrl) {
		super('file', name, path);
		var playUrl = playUrl;
		// parse tag metadata
		var format = '';
		var tracks = 1;
		var disc = '';
		var track = '';
		var title = name;
		var artist = '';
		var album = '';
		var duration = 1200;
		var gain = '0dB';
		try {
			var metadata = ffprobe(path);
			// console.log(metadata);
			format = metadata.format.format_name;
			var tags = metadata.format.tags;
			if (tags != null) {
				// console.log(tags);
				// tracks
				if (tags.tracks != null) {
					tracks = Number(tags.tracks);
				}
				// disc
				if (tags.disc != null) {
					disc = tags.disc;
				}
				if (tags.DISC != null) {
					disc = tags.DISC;
				}
				// track
				if (tags.track != null) {
					track = tags.track;
				}
				if (tags.TRACK != null) {
					track = tags.TRACK;
				}
				var slashIndex = track.indexOf('/');
				if (slashIndex > 0) {
					track = track.substring(0, slashIndex);
				}
				// title
				if (tags.title != null) {
					title = tags.title;
				}
				if (tags.TITLE != null) {
					title = tags.TITLE;
				}
				if (tags.song != null) {
					title = tags.song;
				}
				// artist
				if (tags.artist != null) {
					artist = tags.artist;
				}
				if (tags.ARTIST != null) {
					artist = tags.ARTIST;
				}
				if (tags.author != null) {
					artist = tags.author;
				}
				// album
				if (tags.album != null) {
					album = tags.album;
				}
				if (tags.ALBUM != null) {
					album = tags.ALBUM;
				}
				if (tags.game != null) {
					album = tags.game;
				}
				// duration
				if (metadata.format.duration != null && typeof metadata.format.duration == 'number') {
					duration = metadata.format.duration;
				}
				// gain
				if (tags.replaygain_track_gain != null) {
					gain = tags.replaygain_track_gain;
				}
				if (tags.REPLAYGAIN_TRACK_GAIN != null) {
					gain = tags.REPLAYGAIN_TRACK_GAIN;
				}
				// if (tags.replaygain_album_gain != null) {
				// 	gain = tags.replaygain_album_gain;
				// }
				// if (tags.REPLAYGAIN_ALBUM_GAIN != null) {
				// 	gain = tags.REPLAYGAIN_ALBUM_GAIN;
				// }
				gain = gain.replace(/\s/g, '');
			}
			if (disc.length > 0) {
				if (track.length < 2) {
					track = '0' + track;
				}
				track = disc + '.' + track;
			}
			playUrl += '&duration=' + duration + '&gain=' + gain;
		} catch (err) {
			console.log('Error while reading metadata for ' + path + '\n' + err);
		}

		this.tracks = [];
		for (var i = 0; i < tracks; i++) {
			var details = {};
			details.playUrl = playUrl + '&track_index=' + i;
			details.format = format;
			if (tracks > 1) {
				details.track = i + 1;
			} else {
				details.track = track;
			}
			details.title = title;
			details.artist = artist;
			details.album = album;
			details.duration = duration;
			details.gain = gain;
			this.tracks.push(details);
		}
	}

}
<|endoftext|>


<commit_before>var websocket = {
    socket: null,
    retrySocketDelay: 1,
    buffer: new Map(),
    messageCounter: 0,
    open: function() {
        console.info("Trying to open websocket...");

        websocket.socket = new WebSocket("ws://" + location.host + "/florence/websocket");

        websocket.socket.onopen = function() {
            console.info("Websocket has been opened");
            websocket.retrySocketDelay = 1;
            websocket.buffer.forEach(function(message) {
                websocket.socket.send(message);
            });

            // FIXME we should be logging that the socket is open - but there's a horrible cyclical dependency on startup atm
        }

        websocket.socket.onerror = function() {
            console.error("Error opening websocket");
        }

        websocket.socket.onmessage = function(message) {
            message = JSON.parse(message.data);
            if (message.type === "version") {
                // TODO Not being used yet to check version but should replace existing implementation at some point
                Florence.version = message.payload.version;
                return;
            }
            if (message.type !== "ack") {
                return;
            }
            websocket.buffer.delete(parseInt(message.payload));
        }

        websocket.socket.onclose = function() {
            console.info("Websocket has been closed");
            websocket.retrySocketDelay *= 2;
            if (websocket.retrySocketDelay >= 10000) {
                websocket.retrySocketDelay = 10000;
            }

            setTimeout(() => {
                // setTimeout sets 'this' to window wrapping 'this.open()' in a lambda function
                // (rather than passing it inline), stops it.
                // Ref: https://stackoverflow.com/questions/2130241/pass-correct-this-context-to-settimeout-callback
                websocket.open();
            }, websocket.retrySocketDelay);
        }
    },
    send: function(message) {
        websocket.messageCounter++;
        message = websocket.messageCounter + ":" + message;

        if (websocket.buffer.size >= 50) {
            console.warn(`Websocket buffer has reached it's limit, so message will not be sent to server. Message: \n`, message);
            log.add(log.eventTypes.socketBufferFull); // This has to be excluded from being sent to the server or else we'll have an infinite loop
            return;
        }

        websocket.buffer.set(websocket.messageCounter, message);

        if (websocket.socket.readyState === 1) {
            websocket.socket.send(message);
        }
    }
};<commit_msg>Handle websocket opening on secure and insecure networks<commit_after>var websocket = {
    socket: null,
    retrySocketDelay: 1,
    buffer: new Map(),
    messageCounter: 0,
    open: function() {
        console.info("Trying to open websocket...");

        websocket.socket = new WebSocket(location.protocol.replace(/^http/, 'ws') + location.host + "/florence/websocket");

        websocket.socket.onopen = function() {
            console.info("Websocket has been opened");
            websocket.retrySocketDelay = 1;
            websocket.buffer.forEach(function(message) {
                websocket.socket.send(message);
            });

            // FIXME we should be logging that the socket is open - but there's a horrible cyclical dependency on startup atm
        }

        websocket.socket.onerror = function() {
            console.error("Error opening websocket");
        }

        websocket.socket.onmessage = function(message) {
            message = JSON.parse(message.data);
            if (message.type === "version") {
                // TODO Not being used yet to check version but should replace existing implementation at some point
                Florence.version = message.payload.version;
                return;
            }
            if (message.type !== "ack") {
                return;
            }
            websocket.buffer.delete(parseInt(message.payload));
        }

        websocket.socket.onclose = function() {
            console.info("Websocket has been closed");
            websocket.retrySocketDelay *= 2;
            if (websocket.retrySocketDelay >= 10000) {
                websocket.retrySocketDelay = 10000;
            }

            setTimeout(() => {
                // setTimeout sets 'this' to window wrapping 'this.open()' in a lambda function
                // (rather than passing it inline), stops it.
                // Ref: https://stackoverflow.com/questions/2130241/pass-correct-this-context-to-settimeout-callback
                websocket.open();
            }, websocket.retrySocketDelay);
        }
    },
    send: function(message) {
        websocket.messageCounter++;
        message = websocket.messageCounter + ":" + message;

        if (websocket.buffer.size >= 50) {
            console.warn(`Websocket buffer has reached it's limit, so message will not be sent to server. Message: \n`, message);
            log.add(log.eventTypes.socketBufferFull); // This has to be excluded from being sent to the server or else we'll have an infinite loop
            return;
        }

        websocket.buffer.set(websocket.messageCounter, message);

        if (websocket.socket.readyState === 1) {
            websocket.socket.send(message);
        }
    }
};<|endoftext|>


<commit_before>var websocket = {
    socket: null,
    retrySocketDelay: 1,
    buffer: new Map(),
    messageCounter: 0,
    open: function() {
        console.info("Trying to open websocket...");

        var ws = websocket.socket || new WebSocket("ws://" + location.host + "/florence/websocket");
        if (!websocket.socket) {
            websocket.socket = ws;
        }

        ws.onopen = function() {
            console.info("Websocket has been opened");
            websocket.retrySocketDelay = 1;
            websocket.buffer.forEach(function(message) {
                websocket.socket.send(message);
            });

            // FIXME we should be logging that the socket is open - but there's a horrible cyclical dependency on startup atm
        }

        ws.onmessage = function(message) {
            message = JSON.parse(message.data);
            if (message.type === "version") {
                // TODO Not being used yet to check version but should replace existing implementation at some point
                Florence.version = message.payload.version;
                return;
            }
            if (message.type !== "ack") {
                return;
            }
            websocket.buffer.delete(parseInt(message.payload));
        }

        ws.onclose = () => {
            console.info("Websocket has been closed");
            websocket.retrySocketDelay *= 2;
            if (websocket.retrySocketDelay >= 10000) {
                websocket.retrySocketDelay = 10000;
            }

            setTimeout(() => {
                // setTimeout sets 'this' to window wrapping 'this.open()' in a lambda function
                // (rather than passing it inline), stops it.
                // Ref: https://stackoverflow.com/questions/2130241/pass-correct-this-context-to-settimeout-callback
                websocket.open();
            }, websocket.retrySocketDelay);
        }
    },
    send: function(message) {
        websocket.messageCounter++;
        message = websocket.messageCounter + ":" + message;

        if (websocket.buffer.size >= 50) {
            console.warn(`Websocket buffer has reached it's limit, so message will not be sent to server. Message: \n`, message);
            log.add(log.eventTypes.socketBufferFull); // This has to be excluded from being sent to the server or else we'll have an infinite loop
            return;
        }

        websocket.buffer.set(websocket.messageCounter, message);

        if (websocket.socket.readyState === 1) {
            websocket.socket.send(message);
        }
    }
};<commit_msg>Fix websocket not attempting re-open on closure<commit_after>var websocket = {
    socket: null,
    retrySocketDelay: 1,
    buffer: new Map(),
    messageCounter: 0,
    open: function() {
        console.info("Trying to open websocket...");

        websocket.socket = new WebSocket("ws://" + location.host + "/florence/websocket");

        websocket.socket.onopen = function() {
            console.info("Websocket has been opened");
            websocket.retrySocketDelay = 1;
            websocket.buffer.forEach(function(message) {
                websocket.socket.send(message);
            });

            // FIXME we should be logging that the socket is open - but there's a horrible cyclical dependency on startup atm
        }

        websocket.socket.onerror = function() {
            console.error("Error opening websocket");
        }

        websocket.socket.onmessage = function(message) {
            message = JSON.parse(message.data);
            if (message.type === "version") {
                // TODO Not being used yet to check version but should replace existing implementation at some point
                Florence.version = message.payload.version;
                return;
            }
            if (message.type !== "ack") {
                return;
            }
            websocket.buffer.delete(parseInt(message.payload));
        }

        websocket.socket.onclose = function() {
            console.info("Websocket has been closed");
            debugger;
            websocket.retrySocketDelay *= 2;
            if (websocket.retrySocketDelay >= 10000) {
                websocket.retrySocketDelay = 10000;
            }

            setTimeout(() => {
                // setTimeout sets 'this' to window wrapping 'this.open()' in a lambda function
                // (rather than passing it inline), stops it.
                // Ref: https://stackoverflow.com/questions/2130241/pass-correct-this-context-to-settimeout-callback
                websocket.open();
            }, websocket.retrySocketDelay);
        }
    },
    send: function(message) {
        websocket.messageCounter++;
        message = websocket.messageCounter + ":" + message;

        if (websocket.buffer.size >= 50) {
            console.warn(`Websocket buffer has reached it's limit, so message will not be sent to server. Message: \n`, message);
            log.add(log.eventTypes.socketBufferFull); // This has to be excluded from being sent to the server or else we'll have an infinite loop
            return;
        }

        websocket.buffer.set(websocket.messageCounter, message);

        if (websocket.socket.readyState === 1) {
            websocket.socket.send(message);
        }
    }
};<|endoftext|>


<commit_before>import { createLogger } from 'redux-logger';
import { combineReducers } from 'redux';
import { default as thunk } from 'redux-thunk';
import { createStore, applyMiddleware, compose } from 'redux';
import ReactovaReducers from '../../reducers'

const loggerMiddleware = createLogger({ predicate: (getState, action) => __DEV__ });

export default function configureStore(initialState, reducers) {
	console.log(ReactovaReducers);
	console.log(reducers);
	const combinedReducers = combineReducers({
		ReactovaReducers: ReactovaReducers,
		AppReducers: reducers
	})
	const enhancer = compose(
		applyMiddleware(
			thunk,
			loggerMiddleware,
		)
	);
	return createStore(combinedReducers, enhancer)
}

<commit_msg>removed console.logs in configureStore.<commit_after>import { createLogger } from 'redux-logger';
import { combineReducers } from 'redux';
import { default as thunk } from 'redux-thunk';
import { createStore, applyMiddleware, compose } from 'redux';
import ReactovaReducers from '../../reducers'

const loggerMiddleware = createLogger({ predicate: (getState, action) => __DEV__ });

export default function configureStore(initialState, reducers) {

	const combinedReducers = combineReducers({ReactovaReducers: ReactovaReducers, AppReducers: reducers})

	const enhancer = compose(
		applyMiddleware(
			thunk,
			loggerMiddleware,
		)
	);
	return createStore(combinedReducers, enhancer)
}

<|endoftext|>


<commit_before>/**
 * Bootstrap Table Czech translation
 * Author: Lukas Kral (monarcha@seznam.cz)
 */
(function ($) {
    'use strict';

    $.fn.bootstrapTable.locales['cs-CZ'] = {
        formatLoadingMessage: function () {
            return 'Čekejte, prosím...';
        },
        formatRecordsPerPage: function (pageNumber) {
            return pageNumber + ' položek na stránku';
        },
        formatShowingRows: function (pageFrom, pageTo, totalRows) {
            return 'Zobrazena ' + pageFrom + '. - ' + pageTo + '. položka z celkových ' + totalRows;
        },
        formatSearch: function () {
            return 'Vyhledávání';
        },
        formatNoMatches: function () {
            return 'Nenalezena žádná vyhovující položka';
        },
        formatPaginationSwitch: function () {
            return 'Skrýt/Zobrazit stránkování';
        },
        formatRefresh: function () {
            return 'Aktualizovat';
        },
        formatToggle: function () {
            return 'Přepni';
        },
        formatColumns: function () {
            return 'Sloupce';
        }
    };

    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['cs-CZ']);

})(jQuery);
<commit_msg>Added translate for formatAllRows<commit_after>/**
 * Bootstrap Table Czech translation
 * Author: Lukas Kral (monarcha@seznam.cz)
 * Author: Jakub Svestka <svestka1999@gmail.com>
 */
(function ($) {
    'use strict';

    $.fn.bootstrapTable.locales['cs-CZ'] = {
        formatLoadingMessage: function () {
            return 'Čekejte, prosím...';
        },
        formatRecordsPerPage: function (pageNumber) {
            return pageNumber + ' položek na stránku';
        },
        formatShowingRows: function (pageFrom, pageTo, totalRows) {
            return 'Zobrazena ' + pageFrom + '. - ' + pageTo + '. položka z celkových ' + totalRows;
        },
        formatSearch: function () {
            return 'Vyhledávání';
        },
        formatNoMatches: function () {
            return 'Nenalezena žádná vyhovující položka';
        },
        formatPaginationSwitch: function () {
            return 'Skrýt/Zobrazit stránkování';
        },
        formatRefresh: function () {
            return 'Aktualizovat';
        },
        formatToggle: function () {
            return 'Přepni';
        },
        formatColumns: function () {
            return 'Sloupce';
        },
        formatAllRows: function () {
            return 'Vše';
        }
    };

    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['cs-CZ']);

})(jQuery);
<|endoftext|>


<commit_before>//import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
import position from './position';
//import Search from '../utils/Search';
//import IdentityManager from 'service-framework/dist/IdentityManager';
//import { Discovery } from 'service-framework/dist/Discovery';
//import { callbackify } from 'util';

class LocationHypertyFactory {

  constructor(hypertyURL, bus, config, factory) {
    let uri = new URI(hypertyURL);
    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
    this.syncher = factory.createSyncher(hypertyURL, bus, config);
    this.identityManager = factory.createIdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = factory.createDiscovery(hypertyURL, config.runtimeURL, bus);
    this.search = factory.createSearch(this.discovery, this.identityManager);
    this.currentPosition = null;
    this.identity = null;
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    this.reporter = null;
    this.watchID = null;

  }

  _getRegisteredUser() {
    let _this = this;

    return new Promise((resolve, reject) => {
      _this.identityManager.discoverUserRegistered().then((identity) => {
        console.log('[LocationReporter] GET MY IDENTITY:', identity);
        resolve(identity);
      }).catch((error) => {
        console.error('[LocationReporter] ERROR:', error);
        reject(error);
      });
    });

  }

  _resumeReporters() {
    let _this = this;
    //debugger;
    return new Promise((resolve, reject) => {
      _this.syncher.resumeReporters({ store: true }).then((reporters) => {
        console.log('[LocationReporter] Reporters resumed', reporters);

        let reportersList = Object.keys(reporters);

        if (reportersList.length > 0) {

          _this._getRegisteredUser().then((identity) => {

            reportersList.forEach((dataObjectReporterURL) => {
              //debugger;
              console.log(identity);
              _this.identity = identity;
              console.log('[LocationReporter] ', dataObjectReporterURL);
              console.log('[LocationReporter]', reporters[dataObjectReporterURL]);

              if (identity.userURL == reporters[dataObjectReporterURL].metadata.subscriberUsers[0] && reporters[dataObjectReporterURL].metadata.name == 'location') {
                //debugger;
                _this.reporter = reporters[dataObjectReporterURL];
                _this.reporter.onSubscription((event) => event.accept());
                return resolve(true);
              }
            });
            return resolve(false);
          });
        } else {
          return resolve(false);
        }
      }).catch((reason) => {
        console.info('[LocationReporter] Reporters:', reason);
      });
    });
  }

  //FOR invite checkin  -> hyperty://sharing-cities-dsm/checkin-rating
  invite(observer) {

    let _this = this;

    return new Promise((resolve) => {

      function keepTrying() {
        _this.reporter.invitations = [];
        _this.reporter.inviteObservers([observer]);

        let promises = _this.reporter.invitations;

        Promise.all(promises).then(result => {
          resolve();
        }).catch(e => {
          setTimeout(function () {
            keepTrying();
          }, 100);
        });
      }
      keepTrying();
    });
  }

  watchMyLocation(callback) {

    let _this = this;

    function success(position) {
      var crd = position.coords;
      callback(crd);
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
    }

    function error(err) {
      console.warn('ERROR(' + err.code + '): ' + err.message);
    }

    const options = {
      enableHighAccuracy: true

      // timeout: 5000,
      // maximumAge: 0
    };

    this.watchID = navigator.geolocation.watchPosition(success, error, options)
  }

  removeWatchMyLocation() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  getLocation() {
    return this.currentPosition;
  }

  startPositionBroadcast() {
    let _this = this;
    if (_this.reporter == null) {
      _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'], "domain_registration": false })
        .then((reporter) => {
          _this.reporter = reporter;
          console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
          reporter.onSubscription((event) => event.accept());
          _this.search.myIdentity().then(identity => {
            _this.identity = identity;
            _this.broadcastMyPosition();
          });
        });
    } else {
      _this.broadcastMyPosition();
    }

  }

  initPosition(watchPosition = true) {

    return new Promise((resolve) => {

      let _this = this;
      if (_this.reporter == null) {
        _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'], "domain_registration": false })
          .then((reporter) => {
            _this.reporter = reporter;
            console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
            reporter.onSubscription((event) => event.accept());
            _this.search.myIdentity().then(identity => {
              _this.identity = identity;
              if (watchPosition) {
                _this.setCurrentPosition();
              }
              resolve(true);
            });
          });
      } else {
        if (watchPosition)
          _this.setCurrentPosition();
        resolve(true);
      }
    });
  }

  setCurrentPosition() {
    let _this = this;
    this.watchID = navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      //debugger;
    });
  }

  broadcastMyPosition() {
    let _this = this;
    this.watchID = navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      _this.reporter.data.values = [
        { name: 'latitude', unit: 'lat', value: position.coords.latitude },
        { name: 'longitude', unit: 'lon', value: position.coords.longitude }
      ];
      _this.reporter.data.time = position.timestamp;
      _this.reporter.data.tag = _this.identity.preferred_username;
      //debugger;
    });
  }

  updateLocation() {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude }
    ];
    _this.reporter.data.time = _this.currentPosition.timestamp;
    _this.reporter.data.tag = _this.identity.preferred_username;
  }

  checkin(spotId) {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude },
      { name: 'checkin', unit: 'checkin', value: spotId }
    ];
  }

  collect(bonusID, spotID) {
    let _this = this;
    // let latitude = _this.currentPosition.coords.latitude;
    // let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'bonus', unit: 'checkin', value: bonusID },
      { name: 'checkin', unit: 'checkin', value: spotID }
    ];

  }

  // can call with 'data://sharing-cities-dsm/shops'
  retrieveSpots(spotsURL) {

    return new Promise((resolve) => {
      let _this = this;

      let createMessage = {
        type: 'forward', to: spotsURL, from: _this.hypertyURL,
        body: {
          from: _this.hypertyURL,
          type: 'read'
        }
      };

      console.log('location-reporter-retrieveSpots()', createMessage);

      _this.bus.postMessage(createMessage, (reply) => {
        resolve(reply);
        console.log('location-reporter-retrieveSpots() reply: ', reply);
      });

    });

  }

}

export default function activate(hypertyURL, bus, config, factory) {
  return {
    name: 'LocationReporter',
    instance: new LocationHypertyFactory(hypertyURL, bus, config, factory)
  };
}
<commit_msg>LocationReporter: watchMyLocation error callback<commit_after>//import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
import position from './position';
//import Search from '../utils/Search';
//import IdentityManager from 'service-framework/dist/IdentityManager';
//import { Discovery } from 'service-framework/dist/Discovery';
//import { callbackify } from 'util';

class LocationHypertyFactory {

  constructor(hypertyURL, bus, config, factory) {
    let uri = new URI(hypertyURL);
    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
    this.syncher = factory.createSyncher(hypertyURL, bus, config);
    this.identityManager = factory.createIdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = factory.createDiscovery(hypertyURL, config.runtimeURL, bus);
    this.search = factory.createSearch(this.discovery, this.identityManager);
    this.currentPosition = null;
    this.identity = null;
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    this.reporter = null;
    this.watchID = null;

  }

  _getRegisteredUser() {
    let _this = this;

    return new Promise((resolve, reject) => {
      _this.identityManager.discoverUserRegistered().then((identity) => {
        console.log('[LocationReporter] GET MY IDENTITY:', identity);
        resolve(identity);
      }).catch((error) => {
        console.error('[LocationReporter] ERROR:', error);
        reject(error);
      });
    });

  }

  _resumeReporters() {
    let _this = this;
    //debugger;
    return new Promise((resolve, reject) => {
      _this.syncher.resumeReporters({ store: true }).then((reporters) => {
        console.log('[LocationReporter] Reporters resumed', reporters);

        let reportersList = Object.keys(reporters);

        if (reportersList.length > 0) {

          _this._getRegisteredUser().then((identity) => {

            reportersList.forEach((dataObjectReporterURL) => {
              //debugger;
              console.log(identity);
              _this.identity = identity;
              console.log('[LocationReporter] ', dataObjectReporterURL);
              console.log('[LocationReporter]', reporters[dataObjectReporterURL]);

              if (identity.userURL == reporters[dataObjectReporterURL].metadata.subscriberUsers[0] && reporters[dataObjectReporterURL].metadata.name == 'location') {
                //debugger;
                _this.reporter = reporters[dataObjectReporterURL];
                _this.reporter.onSubscription((event) => event.accept());
                return resolve(true);
              }
            });
            return resolve(false);
          });
        } else {
          return resolve(false);
        }
      }).catch((reason) => {
        console.info('[LocationReporter] Reporters:', reason);
      });
    });
  }

  //FOR invite checkin  -> hyperty://sharing-cities-dsm/checkin-rating
  invite(observer) {

    let _this = this;

    return new Promise((resolve) => {

      function keepTrying() {
        _this.reporter.invitations = [];
        _this.reporter.inviteObservers([observer]);

        let promises = _this.reporter.invitations;

        Promise.all(promises).then(result => {
          resolve();
        }).catch(e => {
          setTimeout(function () {
            keepTrying();
          }, 100);
        });
      }
      keepTrying();
    });
  }

  watchMyLocation(successCallback, errorCallback) {

    let _this = this;

    function success(position) {
      var crd = position.coords;
      successCallback(crd);
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
    }

    function error(err) {
      if (errorCallback)
        errorCallback(err);
      console.warn('ERROR(' + err.code + '): ' + err.message);
    }

    const options = {
      enableHighAccuracy: true

      // timeout: 5000,
      // maximumAge: 0
    };

    this.watchID = navigator.geolocation.watchPosition(success, error, options)
  }

  removeWatchMyLocation() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  getLocation() {
    return this.currentPosition;
  }

  startPositionBroadcast() {
    let _this = this;
    if (_this.reporter == null) {
      _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'], "domain_registration": false })
        .then((reporter) => {
          _this.reporter = reporter;
          console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
          reporter.onSubscription((event) => event.accept());
          _this.search.myIdentity().then(identity => {
            _this.identity = identity;
            _this.broadcastMyPosition();
          });
        });
    } else {
      _this.broadcastMyPosition();
    }

  }

  initPosition(watchPosition = true) {

    return new Promise((resolve) => {

      let _this = this;
      if (_this.reporter == null) {
        _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'], "domain_registration": false })
          .then((reporter) => {
            _this.reporter = reporter;
            console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
            reporter.onSubscription((event) => event.accept());
            _this.search.myIdentity().then(identity => {
              _this.identity = identity;
              if (watchPosition) {
                _this.setCurrentPosition();
              }
              resolve(true);
            });
          });
      } else {
        if (watchPosition)
          _this.setCurrentPosition();
        resolve(true);
      }
    });
  }

  setCurrentPosition() {
    let _this = this;
    this.watchID = navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      //debugger;
    });
  }

  broadcastMyPosition() {
    let _this = this;
    this.watchID = navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      _this.reporter.data.values = [
        { name: 'latitude', unit: 'lat', value: position.coords.latitude },
        { name: 'longitude', unit: 'lon', value: position.coords.longitude }
      ];
      _this.reporter.data.time = position.timestamp;
      _this.reporter.data.tag = _this.identity.preferred_username;
      //debugger;
    });
  }

  updateLocation() {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude }
    ];
    _this.reporter.data.time = _this.currentPosition.timestamp;
    _this.reporter.data.tag = _this.identity.preferred_username;
  }

  checkin(spotId) {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude },
      { name: 'checkin', unit: 'checkin', value: spotId }
    ];
  }

  collect(bonusID, spotID) {
    let _this = this;
    // let latitude = _this.currentPosition.coords.latitude;
    // let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'bonus', unit: 'checkin', value: bonusID },
      { name: 'checkin', unit: 'checkin', value: spotID }
    ];

  }

  // can call with 'data://sharing-cities-dsm/shops'
  retrieveSpots(spotsURL) {

    return new Promise((resolve) => {
      let _this = this;

      let createMessage = {
        type: 'forward', to: spotsURL, from: _this.hypertyURL,
        body: {
          from: _this.hypertyURL,
          type: 'read'
        }
      };

      console.log('location-reporter-retrieveSpots()', createMessage);

      _this.bus.postMessage(createMessage, (reply) => {
        resolve(reply);
        console.log('location-reporter-retrieveSpots() reply: ', reply);
      });

    });

  }

}

export default function activate(hypertyURL, bus, config, factory) {
  return {
    name: 'LocationReporter',
    instance: new LocationHypertyFactory(hypertyURL, bus, config, factory)
  };
}
<|endoftext|>


<commit_before>var time = 0;
var blogTop = 0;
var num = 0;
$.getJSON("/category.json", function(data) {
  $.each(data, function(index, val) {
    var date = Date.parse(val.date);
    var tag = '';
    for (var i = val.tags.length - 1; i >= 0; i--) {
      tag += '' + val.tags[i] + ''
    };
    var string = '
' + format(date) + '
' + val.title + '
' + tag + '

'
    $('.ul-div ul').append(string);
  });
});
var jsonData = [{
  "date": "2015-06-10T00:00:00Z",
  "link": "2012/1/10/markdown_help_9/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-09T00:00:00Z",
  "link": "2012/1/9/markdown_help_8/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-09T00:00:00Z",
  "link": "2012/1/9/markdown_help_8/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-09T00:00:00Z",
  "link": "2012/1/9/markdown_help_13/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-09T00:00:00Z",
  "link": "2012/1/9/markdown_help_8/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-09T00:00:00Z",
  "link": "2012/1/9/markdown_help_8/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-09T00:00:00Z",
  "link": "2012/1/9/markdown_help_8/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-09T00:00:00Z",
  "link": "2012/1/9/markdown_help_8/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-08T00:00:00Z",
  "link": "2012/1/8/markdown_help_7/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-07T00:00:00Z",
  "link": "2012/1/7/markdown_help_6/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-07T00:00:00Z",
  "link": "2012/1/7/markdown_help_6/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-07T00:00:00Z",
  "link": "2012/1/7/markdown_help_6/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-07T00:00:00Z",
  "link": "2012/1/7/markdown_help_6/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-07T00:00:00Z",
  "link": "2012/1/7/markdown_help_6/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-06T00:00:00Z",
  "link": "2012/1/6/markdown_help_5/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-05T00:00:00Z",
  "link": "2012/1/5/markdown_help_4/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-04T00:00:00Z",
  "link": "2012/1/4/markdown_help_3/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-03T00:00:00Z",
  "link": "2012/1/3/markdown_help_2/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-02T00:00:00Z",
  "link": "2012/1/2/markdown_help_1/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}, {
  "date": "2012-01-01T00:00:00Z",
  "link": "2012/1/1/markdown_help_0/index.html",
  "tags": ["java", "golang"],
  "title": "Markdown help"
}];
// (function(data) {
//   $.each(data, function(index, val) {
//     var date = Date.parse(val.date);
//     var tag = '';
//     for (var i = val.tags.length - 1; i >= 0; i--) {
//       tag += '' + val.tags[i] + ''
//     };
//     var string = '
' + format(date) + '
' + val.title + '
' + tag + '

'
//     $('.ul-div ul').append(string);
//   });
// })(jsonData);

(function() {
  var a = /\b.*(iphone|ipad|android).*\b/;
  if (!(a.test(navigator.userAgent.toLowerCase()))) {

  }
}());

var toggleBlog = function() {
  // var localhref = window.location.href;
  var localhref = 'localhost://blog/2012/1/9/markdown_help_13/index.html'
  var blogList = $(".menu-li");
  var blogTop, num;
  for (var i = 0; i < blogList.length; i++) {
    if (localhref.toLowerCase().indexOf(blogList.eq(i).find('a').attr('href').toLowerCase()) >= 0) {
      blogTop = blogList.eq(i).offset().top - document.body.scrollTop;
      num = i;
      break;
    }
  }
  return {
    getTop: function() {
      return blogTop;
    },
    getNum: function() {
      return num;
    }
  };
}

var rightTop = parseInt($('.right-menu').offset().top);
$(document).scroll(function(e) {
  var pos = document.body.scrollTop;
  if (pos >= rightTop) {
    $('.right-menu').addClass('fixed');
  } else {
    $('.right-menu').removeClass('fixed');
    $('.right-menu-ul a').removeClass('active');
    $('.right-menu-ul ul').removeClass('active');
    $('.right-menu-ul li ul li').removeClass('active');
  }
});
$("#toggle").click(
        function(event) {
            event.preventDefault();
            if(time == 0){
            	$('.ul-div').animate({scrollTop: toggleBlog().getTop()}, 500);
                $('.menu-li').eq(toggleBlog().getNum()).addClass('active');
                console.log(toggleBlog().getTop());
                time += 1;
            }
             $(this).find(".top").toggleClass("active");
                $(this).find(".middle").toggleClass("active");
                $(this).find(".bottom").toggleClass("active");
                $(".main-content").toggleClass("active");
                $("#overlay").toggleClass("open");
                $(".right-menu").toggleClass("active");

    }
  ),

  $(".main-content").click(function() {
    if ($(".main-content").attr("class").split(" ").length == 2) {
      $("#toggle").trigger("click");
    };
  });
(function() {
  var getEle = $('.content').find('h2,h3');
  var a = getEle.length;
  for (var i = 0; i < a;) {
    var tag = "tag" + i;
    getEle.eq(i).addClass(tag);
    getEle.eq(i).attr('id', tag);
    var temp = '
' + getEle.eq(i).html() + '
';
    i = i + 1;
    while ((i < a) && (getEle.eq(i).is('h3'))) {
      var tag = "tag" + i;
      getEle.eq(i).addClass(tag);
      getEle.eq(i).attr('id', tag);
      temp += '
  ' + getEle.eq(i).html() + '
';
      i++;
    }
    temp += '

';
    $(".right-menu-ul").append(temp);
  }

  $('.content').find('h2,h3,article').each(function() {
    new Waypoint({
      element: this,
      handler: function(direction) {
        var num = '.a' + $(this.element).attr("class").charAt(3);
        $('.right-menu-ul a').removeClass('active');
        $('.right-menu-ul ul').removeClass('active');
        $('.right-menu-ul li ul li').removeClass('active');
        if ($(num).hasClass("sub")) {
          $(num).parent().parent().addClass("active");
          $(num).parent().parent().siblings("a").addClass('active');
        }
        $(num).addClass("active");
        $(num).siblings("ul").addClass("active");

      },
      continuous: false
    })
  })

})();

var totalList = $(".menu-li");
var input = $('.search');
input.bind('keyup', sendKeyWord);

function sendKeyWord(e) {
  dealData($.trim(input.val()));
}

function dealData(text) {
  for (var i = 0; i < totalList.length; i++) {
    if (totalList.eq(i).text().toLowerCase().indexOf(text.toLowerCase()) < 0) {
      totalList.eq(i).hide();
    } else {
      totalList.eq(i).show();
    }
  }
  $('.ul-div').scrollTop(0);
}

var scroll = function(event, scroller) {
  var k = event.wheelDelta ? event.wheelDelta : -event.detail * 10;
  scroller.scrollTop = scroller.scrollTop - k;
  return false;
};

var isUp = true;
var lastScrollTop = 0;
var searchDiv = $('.search-div')
var topThreshold = searchDiv.height();
$('.ul-div').scroll(function(e) {
  var top = parseInt($('.ps-scrollbar-y').css('top'));
  if(top==lastScrollTop) return;
  if (top < topThreshold) {
    searchDiv.fadeIn();
    return;
  }
  if (isUp ^ (top < lastScrollTop)) {
    isUp=!isUp;
    searchDiv.fadeToggle();
  }
  lastScrollTop = top;
});

$('.ul-div').perfectScrollbar();
$('.node').on('click', searchNode);

function searchNode(e) {
  if ($(".main-content").attr("class").split(" ").length == 1) {
    $("#toggle").trigger("click");
  };
  e.stopPropagation();
  $('.search').val($(e.target).html());
  dealData($(e.target).html());
}

$('.menu-li').mouseenter(function(e) {
  var target = $(e.delegateTarget);
  setTimeout(function() {
    if (target.is(':hover')) {
      target.find('div.tags').animate({
        'margin-top': '5px'
      }, 400);
    }
  }, 500);
  // $(e.delegateTarget).find('div.tags').animate({'margin-top':'5px'},200);
}).mouseleave(function(e) {
  $(e.delegateTarget).find('div.tags').animate({
    'margin-top': '-25px'
  }, 200);
});

function format(date) {
  var seconds=parseInt((Date.now()-date)/1000);
  if(seconds<60) return parseInt(seconds/60)+' secs ago';
  if(seconds/60 < 60) return parseInt(seconds/60)+' mins ago';
  if(seconds/3600 < 24) return parseInt(seconds/3600)+' hrs ago';
  if(seconds/(3600*24) < 30) return parseInt(seconds/(3600*24))+' days ago';
  return date.toString('MMM d yyyy');
}
<commit_msg>求测试js<commit_after>({
    init: function () {
        var self = this;
        self.time = 1;
        self.isRight = true;

        self.initLeftMenu(self.bindLeftEvent);
        if (self.isRight) {
            self.bindRightMenu();
        };
        self.search();
        self.bindScrollShow();
        self.bindHoverShow();
    },
    initLeftMenu: function (callback) {
        var self = this;
        $.getJSON("/category.json", function (data) {
            $.each(data, function (index, val) {
                var date = Date.parse(val.date);
                var tag = '';
                for (var i = val.tags.length - 1; i >= 0; i--) {
                    tag += '' + val.tags[i] + ''
                }
                ;
                var string = '
' + self.format(date) + '
' + val.title + '
' + tag + '

'
                $('.ul-div ul').append(string);
            });
            callback();
        });
    },
    bindLeftEvent: function () {
        var self = this;
        var toggleBlog = function () {
            // var localhref = window.location.href;
            var localhref = 'localhost://blog/2012/1/9/markdown_help_13/index.html'
            var blogList = $(".menu-li");
            var blogTop = 0, num = 0;
            for (var i = 0; i < blogList.length; i++) {
                if (localhref.toLowerCase().indexOf(blogList.eq(i).find('a').attr('href').toLowerCase()) >= 0) {
                    blogTop = blogList.eq(i).offset().top - document.body.scrollTop;
                    num = i;
                    break;
                }
            };
            return {
                getTop: function () {
                    return blogTop;
                },
                getNum: function () {
                    return num;
                }
            };
        };
        $("#toggle").click(
            function (event) {
                event.preventDefault();
                if (self.time == 0) {
                    $('.ul-div').animate({scrollTop: toggleBlog().getTop()}, 500);
                    $('.menu-li').eq(toggleBlog().getNum()).addClass('active');
                    console.log(toggleBlog().getTop());
                    time += 1;
                }
                $(this).find(".top").toggleClass("active");
                $(this).find(".middle").toggleClass("active");
                $(this).find(".bottom").toggleClass("active");
                $(".main-content").toggleClass("active");
                $("#overlay").toggleClass("open");
                $(".right-menu").toggleClass("active");
            }
        );

        $(".main-content").click(function () {
            if ($(".main-content").attr("class").split(" ").length == 2) {
                $("#toggle").trigger("click");
            };
        });
        var scroll = function (event, scroller) {
            var k = event.wheelDelta ? event.wheelDelta : -event.detail * 10;
            scroller.scrollTop = scroller.scrollTop - k;
            return false;
        };
        $('.ul-div').perfectScrollbar();
    },
    bindRightMenu: function () {
        var getEle = $('.content').find('h2,h3');
        var a = getEle.length;
        for (var i = 0; i < a;) {
            var tag = "tag" + i;
            getEle.eq(i).addClass(tag);
            getEle.eq(i).attr('id', tag);
            var temp = '
' + getEle.eq(i).html() + '
';
            i = i + 1;
            while ((i < a) && (getEle.eq(i).is('h3'))) {
                var tag = "tag" + i;
                getEle.eq(i).addClass(tag);
                getEle.eq(i).attr('id', tag);
                temp += '
  ' + getEle.eq(i).html() + '
';
                i++;
            }
            temp += '

';
            $(".right-menu-ul").append(temp);
        };

        $('.content').find('h2,h3,article').each(function () {
            new Waypoint({
                element: this,
                handler: function (direction) {
                    var num = '.a' + $(this.element).attr("class").charAt(3);
                    $('.right-menu-ul a').removeClass('active');
                    $('.right-menu-ul ul').removeClass('active');
                    $('.right-menu-ul li ul li').removeClass('active');
                    if ($(num).hasClass("sub")) {
                        $(num).parent().parent().addClass("active");
                        $(num).parent().parent().siblings("a").addClass('active');
                    }
                    $(num).addClass("active");
                    $(num).siblings("ul").addClass("active");

                },
                continuous: false
            });
        });
        var rightTop = parseInt($('.right-menu').offset().top);
        $(document).scroll(function (e) {
            var pos = document.body.scrollTop;
            if (pos >= rightTop) {
                $('.right-menu').addClass('fixed');
            } else {
                $('.right-menu').removeClass('fixed');
                $('.right-menu-ul a').removeClass('active');
                $('.right-menu-ul ul').removeClass('active');
                $('.right-menu-ul li ul li').removeClass('active');
            }
        });
    },
    search: function () {
        var totalList = $(".menu-li");
        var input = $('.search');
        input.bind('keyup', sendKeyWord);

        function sendKeyWord(e) {
            dealData($.trim(input.val()));
        };
        function dealData(text) {
            for (var i = 0; i < totalList.length; i++) {
                if (totalList.eq(i).text().toLowerCase().indexOf(text.toLowerCase()) < 0) {
                    totalList.eq(i).hide();
                } else {
                    totalList.eq(i).show();
                }
            }
            $('.ul-div').scrollTop(0);
        };

        $('.node').on('click', searchNode);

        function searchNode(e) {
            if ($(".main-content").attr("class").split(" ").length == 1) {
                $("#toggle").trigger("click");
            };
            e.stopPropagation();
            $('.search').val($(e.target).html());
            dealData($(e.target).html());
        };
    },
    bindScrollShow: function () {
        var isUp = true;
        var lastScrollTop = 0;
        var searchDiv = $('.search-div')
        var topThreshold = searchDiv.height();
        $('.ul-div').scroll(function (e) {
            var top = parseInt($('.ps-scrollbar-y').css('top'));
            if (top == lastScrollTop) return;
            if (top < topThreshold) {
                searchDiv.fadeIn();
                return;
            }
            if (isUp ^ (top < lastScrollTop)) {
                isUp = !isUp;
                searchDiv.fadeToggle();
            }
            lastScrollTop = top;
        });
    },
    bindHoverShow: function () {
        $('.menu-li').mouseenter(function (e) {
            var target = $(e.delegateTarget);
            setTimeout(function () {
                if (target.is(':hover')) {
                    target.find('div.tags').animate({
                        'margin-top': '5px'
                    }, 400);
                }
            }, 500);
            // $(e.delegateTarget).find('div.tags').animate({'margin-top':'5px'},200);
        }).mouseleave(function (e) {
            $(e.delegateTarget).find('div.tags').animate({
                'margin-top': '-25px'
            }, 200);
        });
    },
    format: function (date) {
        var seconds = parseInt((Date.now() - date) / 1000);
        if (seconds < 60) return parseInt(seconds / 60) + ' secs ago';
        if (seconds / 60 < 60) return parseInt(seconds / 60) + ' mins ago';
        if (seconds / 3600 < 24) return parseInt(seconds / 3600) + ' hrs ago';
        if (seconds / (3600 * 24) < 30) return parseInt(seconds / (3600 * 24)) + ' days ago';
        return date.toString('MMM d yyyy');
    }

}).init();<|endoftext|>


<commit_before>// Abstract Persistence driver

'use strict';

var aFrom          = require('es5-ext/array/from')
  , clear          = require('es5-ext/array/#/clear')
  , isCopy         = require('es5-ext/array/#/is-copy')
  , ensureArray    = require('es5-ext/array/valid-array')
  , assign         = require('es5-ext/object/assign')
  , ensureCallable = require('es5-ext/object/valid-callable')
  , ensureObject   = require('es5-ext/object/valid-object')
  , ensureString   = require('es5-ext/object/validate-stringifiable-value')
  , isSet          = require('es6-set/is-set')
  , deferred       = require('deferred')
  , emitError      = require('event-emitter/emit-error')
  , d              = require('d')
  , autoBind       = require('d/auto-bind')
  , lazy           = require('d/lazy')
  , debug          = require('debug-ext')('db')
  , ee             = require('event-emitter')
  , getStamp       = require('time-uuid/time')
  , ensureDatabase = require('dbjs/valid-dbjs')
  , ensureType     = require('dbjs/valid-dbjs-type')
  , Event          = require('dbjs/_setup/event')
  , unserialize    = require('dbjs/_setup/unserialize/value')
  , serialize      = require('dbjs/_setup/serialize/value')
  , resolveKeyPath = require('dbjs/_setup/utils/resolve-property-path')
  , once           = require('timers-ext/once')
  , ensureDriver   = require('./ensure')

  , isArray = Array.isArray
  , isModelId = RegExp.prototype.test.bind(/^[A-Z]/)
  , tokenize = resolveKeyPath.tokenize, resolveObject = resolveKeyPath.resolveObject
  , create = Object.create;

var PersistenceDriver = module.exports = Object.defineProperties(function (dbjs/*, options*/) {
	var autoSaveFilter, options;
	if (!(this instanceof PersistenceDriver)) return new PersistenceDriver(dbjs, arguments[1]);
	options = Object(arguments[1]);
	this.db = ensureDatabase(dbjs);
	autoSaveFilter = (options.autoSaveFilter != null)
		? ensureCallable(options.autoSaveFilter) : this.constructor.defaultAutoSaveFilter;
	dbjs.objects.on('update', function (event) {
		if (event.sourceId === 'persistentLayer') return;
		if (!autoSaveFilter(event)) return;
		debug("persistent update %s %s", event.object.__valueId__, event.stamp);
		this._eventsToStore.push(event);
		this._exportEvents();
	}.bind(this));
}, {
	defaultAutoSaveFilter: d(function (event) { return !isModelId(event.object.master.__id__); })
});

var notImplemented = function () { throw new Error("Not implemented"); };

ee(Object.defineProperties(PersistenceDriver.prototype, assign({
	_importValue: d(function (id, value, stamp) {
		var proto;
		if (this._loadedEventsMap[id + '.' + stamp]) return;
		this._loadedEventsMap[id + '.' + stamp] = true;
		value = unserialize(value, this.db.objects);
		if (value && value.__id__ && (value.constructor.prototype === value)) proto = value.constructor;
		return new Event(this.db.objects.unserialize(id, proto), value, stamp, 'persistentLayer');
	}),
	_ensureOpen: d(function () {
		if (this.isClosed) throw new Error("Database not accessible");
	}),
	isClosed: d(false),
	getCustom: d(function (key) {
		this._ensureOpen();
		return this._getCustom(ensureString(key));
	}),
	_getCustom: d(notImplemented),
	loadValue: d(function (id) {
		this._ensureOpen();
		return this._loadValue(ensureString(id));
	}),
	_loadValue: d(notImplemented),
	loadObject: d(function (id) {
		this._ensureOpen();
		id = ensureString(id);
		return this._loadObject(id);
	}),
	_loadObject: d(notImplemented),
	loadAll: d(function () {
		this._ensureOpen();
		return this._loadAll();
	}),
	_loadAll: d(notImplemented),
	storeCustom: d(function (key, value) {
		this._ensureOpen();
		return this._storeCustom(ensureString(key), value);
	}),
	_storeCustom: d(notImplemented),
	storeEvent: d(function (event) {
		this._ensureOpen();
		return this._storeEvent(ensureObject(event));
	}),
	_storeEvent: d(notImplemented),
	storeEvents: d(function (events) {
		this._ensureOpen();
		return this._storeEvents(ensureArray(events));
	}),
	_storeEvents: d(notImplemented),
	trackComputed: d(function (type, keyPath) {
		var names, key, onAdd, onDelete, eventName, mapPromise, listener;
		ensureType(type);
		names = tokenize(ensureString(keyPath));
		this._ensureOpen();
		key = names[names.length - 1];
		eventName = 'computed:' + type.__id__ + '#/' + keyPath;
		mapPromise = this._getAllComputed(keyPath);
		listener = function (event) {
			var sValue, id = event.target.dbId, stamp;
			if (event.target.object.constructor === event.target.object.database.Base) return;
			if (isSet(event.target)) {
				sValue = [];
				event.target.forEach(function (value) { sValue.push(serialize(value)); });
			} else {
				sValue = serialize(event.newValue);
			}
			stamp = event.dbjs ? event.dbjs.stamp : getStamp();
			mapPromise.aside(function (map) {
				map[id].value = sValue;
				map[id].stamp = stamp;
				this.emit(eventName, map[id]);
				this._storeComputed(id, sValue, stamp).done();
			});
		}.bind(this);
		onAdd = function (obj) {
			var observable, value, stamp, id, objId, sValue;
			obj = resolveObject(obj, names);
			if (!obj) return null;
			objId = obj.__id__;
			if (obj.isKeyStatic(key)) {
				value = obj[key];
				stamp = 0;
			} else {
				value = obj._get_(key);
				observable = obj._getObservable_(key);
				stamp = observable.lastModified;
				if (isSet(value)) value.on('change', listener);
				else observable.on('change', listener);
			}
			id = objId + '/' + key;
			if (isSet(value)) {
				sValue = [];
				value.forEach(function (value) { sValue.push(serialize(value)); });
			} else {
				sValue = serialize(value);
			}
			return this._getComputed(id)(function (old) {
				return mapPromise(function (map) {
					if (old) {
						map[objId] = old;
						if (old.stamp === stamp) {
							if (isArray(sValue)) {
								if (isCopy.call(old.value, sValue)) return;
							} else {
								if (old.value === sValue) return;
							}
							++stamp; // most likely model update
						} else if (old.stamp > stamp) {
							stamp = old.stamp + 1;
						}
					}
					if (map[objId]) {
						map[objId].value = sValue;
						map[objId].stamp = stamp;
					} else {
						map[objId] = {
							value: sValue,
							stamp: stamp
						};
					}
					this.emit(eventName, map[objId]);
					return this._storeComputed(id, sValue, stamp);
				}.bind(this));
			}.bind(this));
		}.bind(this);
		onDelete = function (obj) {
			obj = resolveObject(obj, names);
			if (!obj) return null;
			if (obj.isKeyStatic(key)) return;
			obj._getObservable_(key).off('change', listener);
		}.bind(this);
		type.instances.on('change', function (event) {
			if (event.type === 'add') {
				onAdd(event.value).done();
				return;
			}
			if (event.type === 'delete') {
				onDelete(event.value);
				return;
			}
			if (event.type === 'batch') {
				if (event.added) deferred.map(event.added, onAdd).done();
				if (event.deleted) event.deleted.forEach(onDelete);
			}
		});
		return deferred.map(aFrom(type.instances), onAdd)(mapPromise);
	}),
	_getComputed: d(notImplemented),
	_getAllComputed: d(notImplemented),
	_storeComputed: d(notImplemented),
	export: d(function (externalStore) {
		ensureDriver(externalStore);
		this._ensureOpen();
		return this._exportAll(externalStore);
	}),
	_storeRaw: d(notImplemented),
	_exportAll: d(notImplemented),
	close: d(function () {
		this._ensureOpen();
		this.isClosed = true;
		return this._close();
	}),
	_close: d(notImplemented)
}, autoBind({
	emitError: d(emitError)
}), lazy({
	_loadedEventsMap: d(function () { return create(null); }),
	_eventsToStore: d(function () { return []; }),
	_exportEvents: d(function () {
		return once(function () {
			this.storeEvents(this._eventsToStore);
			clear.call(this._eventsToStore);
		}.bind(this));
	})
}))));
<commit_msg>Fix id resolution<commit_after>// Abstract Persistence driver

'use strict';

var aFrom          = require('es5-ext/array/from')
  , clear          = require('es5-ext/array/#/clear')
  , isCopy         = require('es5-ext/array/#/is-copy')
  , ensureArray    = require('es5-ext/array/valid-array')
  , assign         = require('es5-ext/object/assign')
  , ensureCallable = require('es5-ext/object/valid-callable')
  , ensureObject   = require('es5-ext/object/valid-object')
  , ensureString   = require('es5-ext/object/validate-stringifiable-value')
  , isSet          = require('es6-set/is-set')
  , deferred       = require('deferred')
  , emitError      = require('event-emitter/emit-error')
  , d              = require('d')
  , autoBind       = require('d/auto-bind')
  , lazy           = require('d/lazy')
  , debug          = require('debug-ext')('db')
  , ee             = require('event-emitter')
  , getStamp       = require('time-uuid/time')
  , ensureDatabase = require('dbjs/valid-dbjs')
  , ensureType     = require('dbjs/valid-dbjs-type')
  , Event          = require('dbjs/_setup/event')
  , unserialize    = require('dbjs/_setup/unserialize/value')
  , serialize      = require('dbjs/_setup/serialize/value')
  , resolveKeyPath = require('dbjs/_setup/utils/resolve-property-path')
  , once           = require('timers-ext/once')
  , ensureDriver   = require('./ensure')

  , isArray = Array.isArray
  , isModelId = RegExp.prototype.test.bind(/^[A-Z]/)
  , tokenize = resolveKeyPath.tokenize, resolveObject = resolveKeyPath.resolveObject
  , create = Object.create;

var PersistenceDriver = module.exports = Object.defineProperties(function (dbjs/*, options*/) {
	var autoSaveFilter, options;
	if (!(this instanceof PersistenceDriver)) return new PersistenceDriver(dbjs, arguments[1]);
	options = Object(arguments[1]);
	this.db = ensureDatabase(dbjs);
	autoSaveFilter = (options.autoSaveFilter != null)
		? ensureCallable(options.autoSaveFilter) : this.constructor.defaultAutoSaveFilter;
	dbjs.objects.on('update', function (event) {
		if (event.sourceId === 'persistentLayer') return;
		if (!autoSaveFilter(event)) return;
		debug("persistent update %s %s", event.object.__valueId__, event.stamp);
		this._eventsToStore.push(event);
		this._exportEvents();
	}.bind(this));
}, {
	defaultAutoSaveFilter: d(function (event) { return !isModelId(event.object.master.__id__); })
});

var notImplemented = function () { throw new Error("Not implemented"); };

ee(Object.defineProperties(PersistenceDriver.prototype, assign({
	_importValue: d(function (id, value, stamp) {
		var proto;
		if (this._loadedEventsMap[id + '.' + stamp]) return;
		this._loadedEventsMap[id + '.' + stamp] = true;
		value = unserialize(value, this.db.objects);
		if (value && value.__id__ && (value.constructor.prototype === value)) proto = value.constructor;
		return new Event(this.db.objects.unserialize(id, proto), value, stamp, 'persistentLayer');
	}),
	_ensureOpen: d(function () {
		if (this.isClosed) throw new Error("Database not accessible");
	}),
	isClosed: d(false),
	getCustom: d(function (key) {
		this._ensureOpen();
		return this._getCustom(ensureString(key));
	}),
	_getCustom: d(notImplemented),
	loadValue: d(function (id) {
		this._ensureOpen();
		return this._loadValue(ensureString(id));
	}),
	_loadValue: d(notImplemented),
	loadObject: d(function (id) {
		this._ensureOpen();
		id = ensureString(id);
		return this._loadObject(id);
	}),
	_loadObject: d(notImplemented),
	loadAll: d(function () {
		this._ensureOpen();
		return this._loadAll();
	}),
	_loadAll: d(notImplemented),
	storeCustom: d(function (key, value) {
		this._ensureOpen();
		return this._storeCustom(ensureString(key), value);
	}),
	_storeCustom: d(notImplemented),
	storeEvent: d(function (event) {
		this._ensureOpen();
		return this._storeEvent(ensureObject(event));
	}),
	_storeEvent: d(notImplemented),
	storeEvents: d(function (events) {
		this._ensureOpen();
		return this._storeEvents(ensureArray(events));
	}),
	_storeEvents: d(notImplemented),
	trackComputed: d(function (type, keyPath) {
		var names, key, onAdd, onDelete, eventName, mapPromise, listener;
		ensureType(type);
		names = tokenize(ensureString(keyPath));
		this._ensureOpen();
		key = names[names.length - 1];
		eventName = 'computed:' + type.__id__ + '#/' + keyPath;
		mapPromise = this._getAllComputed(keyPath);
		listener = function (event) {
			var sValue, id = event.target.dbId, stamp;
			if (event.target.object.constructor === event.target.object.database.Base) return;
			if (isSet(event.target)) {
				sValue = [];
				event.target.forEach(function (value) { sValue.push(serialize(value)); });
			} else {
				sValue = serialize(event.newValue);
			}
			stamp = event.dbjs ? event.dbjs.stamp : getStamp();
			mapPromise.aside(function (map) {
				map[id].value = sValue;
				map[id].stamp = stamp;
				this.emit(eventName, map[id]);
				this._storeComputed(id, sValue, stamp).done();
			});
		}.bind(this);
		onAdd = function (obj) {
			var observable, value, stamp, id, objId, sValue;
			obj = resolveObject(obj, names);
			if (!obj) return null;
			objId = obj.__id__;
			if (obj.isKeyStatic(key)) {
				value = obj[key];
				stamp = 0;
			} else {
				value = obj._get_(key);
				observable = obj._getObservable_(key);
				stamp = observable.lastModified;
				if (isSet(value)) value.on('change', listener);
				else observable.on('change', listener);
			}
			id = objId + '/' + keyPath;
			if (isSet(value)) {
				sValue = [];
				value.forEach(function (value) { sValue.push(serialize(value)); });
			} else {
				sValue = serialize(value);
			}
			return this._getComputed(id)(function (old) {
				return mapPromise(function (map) {
					if (old) {
						map[objId] = old;
						if (old.stamp === stamp) {
							if (isArray(sValue)) {
								if (isCopy.call(old.value, sValue)) return;
							} else {
								if (old.value === sValue) return;
							}
							++stamp; // most likely model update
						} else if (old.stamp > stamp) {
							stamp = old.stamp + 1;
						}
					}
					if (map[objId]) {
						map[objId].value = sValue;
						map[objId].stamp = stamp;
					} else {
						map[objId] = {
							value: sValue,
							stamp: stamp
						};
					}
					this.emit(eventName, map[objId]);
					return this._storeComputed(id, sValue, stamp);
				}.bind(this));
			}.bind(this));
		}.bind(this);
		onDelete = function (obj) {
			obj = resolveObject(obj, names);
			if (!obj) return null;
			if (obj.isKeyStatic(key)) return;
			obj._getObservable_(key).off('change', listener);
		}.bind(this);
		type.instances.on('change', function (event) {
			if (event.type === 'add') {
				onAdd(event.value).done();
				return;
			}
			if (event.type === 'delete') {
				onDelete(event.value);
				return;
			}
			if (event.type === 'batch') {
				if (event.added) deferred.map(event.added, onAdd).done();
				if (event.deleted) event.deleted.forEach(onDelete);
			}
		});
		return deferred.map(aFrom(type.instances), onAdd)(mapPromise);
	}),
	_getComputed: d(notImplemented),
	_getAllComputed: d(notImplemented),
	_storeComputed: d(notImplemented),
	export: d(function (externalStore) {
		ensureDriver(externalStore);
		this._ensureOpen();
		return this._exportAll(externalStore);
	}),
	_storeRaw: d(notImplemented),
	_exportAll: d(notImplemented),
	close: d(function () {
		this._ensureOpen();
		this.isClosed = true;
		return this._close();
	}),
	_close: d(notImplemented)
}, autoBind({
	emitError: d(emitError)
}), lazy({
	_loadedEventsMap: d(function () { return create(null); }),
	_eventsToStore: d(function () { return []; }),
	_exportEvents: d(function () {
		return once(function () {
			this.storeEvents(this._eventsToStore);
			clear.call(this._eventsToStore);
		}.bind(this));
	})
}))));
<|endoftext|>


<commit_before>// Abstract Persistence driver

'use strict';

var aFrom               = require('es5-ext/array/from')
  , clear               = require('es5-ext/array/#/clear')
  , isCopy              = require('es5-ext/array/#/is-copy')
  , ensureArray         = require('es5-ext/array/valid-array')
  , assign              = require('es5-ext/object/assign')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , isSet               = require('es6-set/is-set')
  , deferred            = require('deferred')
  , emitError           = require('event-emitter/emit-error')
  , d                   = require('d')
  , autoBind            = require('d/auto-bind')
  , lazy                = require('d/lazy')
  , debug               = require('debug-ext')('db')
  , ee                  = require('event-emitter')
  , getStamp            = require('time-uuid/time')
  , ensureObservableSet = require('observable-set/valid-observable-set')
  , ensureDatabase      = require('dbjs/valid-dbjs')
  , Event               = require('dbjs/_setup/event')
  , unserialize         = require('dbjs/_setup/unserialize/value')
  , serialize           = require('dbjs/_setup/serialize/value')
  , resolveKeyPath      = require('dbjs/_setup/utils/resolve-property-path')
  , once                = require('timers-ext/once')
  , ensureDriver        = require('./ensure')

  , isArray = Array.isArray
  , isModelId = RegExp.prototype.test.bind(/^[A-Z]/)
  , tokenize = resolveKeyPath.tokenize, resolveObject = resolveKeyPath.resolveObject
  , create = Object.create;

var PersistenceDriver = module.exports = Object.defineProperties(function (dbjs/*, options*/) {
	var autoSaveFilter, options;
	if (!(this instanceof PersistenceDriver)) return new PersistenceDriver(dbjs, arguments[1]);
	options = Object(arguments[1]);
	this.db = ensureDatabase(dbjs);
	autoSaveFilter = (options.autoSaveFilter != null)
		? ensureCallable(options.autoSaveFilter) : this.constructor.defaultAutoSaveFilter;
	dbjs.objects.on('update', function (event) {
		if (event.sourceId === 'persistentLayer') return;
		if (!autoSaveFilter(event)) return;
		debug("persistent update %s %s", event.object.__valueId__, event.stamp);
		this._cueEvent(event);
	}.bind(this));
}, {
	defaultAutoSaveFilter: d(function (event) { return !isModelId(event.object.master.__id__); })
});

var notImplemented = function () { throw new Error("Not implemented"); };

ee(Object.defineProperties(PersistenceDriver.prototype, assign({
	// Database data
	_importValue: d(function (id, value, stamp) {
		var proto;
		if (this._loadedEventsMap[id + '.' + stamp]) return;
		this._loadedEventsMap[id + '.' + stamp] = true;
		value = unserialize(value, this.db.objects);
		if (value && value.__id__ && (value.constructor.prototype === value)) proto = value.constructor;
		return new Event(this.db.objects.unserialize(id, proto), value, stamp, 'persistentLayer');
	}),
	getValue: d(function (id) {
		id = ensureString(id);
		this._ensureOpen();
		++this._runningOperations;
		return this._getRaw(id).finally(this._onOperationEnd);
	}),
	loadValue: d(function (id) {
		id = ensureString(id);
		this._ensureOpen();
		++this._runningOperations;
		return this._loadValue(id).finally(this._onOperationEnd);
	}),
	loadObject: d(function (id) {
		id = ensureString(id);
		this._ensureOpen();
		++this._runningOperations;
		return this._loadObject(id).finally(this._onOperationEnd);
	}),
	loadAll: d(function () {
		this._ensureOpen();
		++this._runningOperations;
		return this._loadAll().finally(this._onOperationEnd);
	}),
	storeEvent: d(function (event) {
		event = ensureObject(event);
		this._ensureOpen();
		++this._runningOperations;
		return this._storeEvent(event).finally(this._onOperationEnd);
	}),
	storeEvents: d(function (events) {
		events = ensureArray(events);
		this._ensureOpen();
		++this._runningOperations;
		return this._storeEvents(events).finally(this._onOperationEnd);
	}),
	_cueEvent: d(function (event) {
		if (!this._eventsToStore.length) {
			++this._runningOperations;
			this._exportEvents();
		}
		this._eventsToStore.push(event);
	}),
	_loadValue: d(notImplemented),
	_loadObject: d(notImplemented),
	_loadAll: d(notImplemented),
	_storeEvent: d(notImplemented),
	_storeEvents: d(notImplemented),

	// Indexed database data
	indexKeyPath: d(function (keyPath/*, set*/) {
		var names, key, onAdd, onDelete, eventName, listener, set = arguments[1];
		if (set != null) ensureObservableSet(set);
		else set = this.db.Object.instances;
		names = tokenize(ensureString(keyPath));
		this._ensureOpen();
		key = names[names.length - 1];
		eventName = 'computed:' + keyPath;
		++this._runningOperations;
		return this._getIndexedMap(keyPath)(function (map) {
			listener = function (event) {
				var sValue, stamp, objId = event.target.object.master.__id__;
				if (event.target.object.constructor === event.target.object.database.Base) return;
				if (isSet(event.target)) {
					sValue = [];
					event.target.forEach(function (value) { sValue.push(serialize(value)); });
				} else {
					sValue = serialize(event.newValue);
				}
				stamp = event.dbjs ? event.dbjs.stamp : getStamp();
				map[objId].value = sValue;
				map[objId].stamp = stamp;
				this.emit(eventName, map[objId]);
				++this._runningOperations;
				this._storeIndexedValue(objId, keyPath, map[objId]).finally(this._onOperationEnd).done();
			}.bind(this);
			onAdd = function (obj) {
				var observable, value, stamp, objId, sValue, old;
				obj = resolveObject(obj, names);
				if (!obj) return null;
				objId = obj.__id__;
				if (obj.isKeyStatic(key)) {
					value = obj[key];
					stamp = 0;
				} else {
					value = obj._get_(key);
					observable = obj._getObservable_(key);
					stamp = observable.lastModified;
					if (isSet(value)) value.on('change', listener);
					else observable.on('change', listener);
				}
				if (isSet(value)) {
					sValue = [];
					value.forEach(function (value) { sValue.push(serialize(value)); });
				} else {
					sValue = serialize(value);
				}
				old = map[objId];
				if (old) {
					if (old.stamp === stamp) {
						if (isArray(sValue)) {
							if (isCopy.call(old.value, sValue)) return;
						} else {
							if (old.value === sValue) return;
						}
						++stamp; // most likely model update
					} else if (old.stamp > stamp) {
						stamp = old.stamp + 1;
					}
					old.value = sValue;
					old.stamp = stamp;
				} else {
					map[objId] = {
						value: sValue,
						stamp: stamp
					};
				}
				this.emit(eventName, map[objId]);
				return this._storeIndexedValue(objId, keyPath, map[objId]);
			}.bind(this);
			onDelete = function (obj) {
				obj = resolveObject(obj, names);
				if (!obj) return null;
				if (obj.isKeyStatic(key)) return;
				obj._getObservable_(key).off('change', listener);
			}.bind(this);
			set.on('change', function (event) {
				if (event.type === 'add') {
					++this._runningOperations;
					onAdd(event.value).finally(this._onOperationEnd).done();
					return;
				}
				if (event.type === 'delete') {
					onDelete(event.value);
					return;
				}
				if (event.type === 'batch') {
					if (event.added) {
						++this._runningOperations;
						deferred.map(event.added, onAdd).finally(this._onOperationEnd).done();
					}
					if (event.deleted) event.deleted.forEach(onDelete);
				}
			}.bind(this));
			return deferred.map(aFrom(set), onAdd)(map);
		}.bind(this)).finally(this._onOperationEnd);
	}),
	_getIndexedValue: d(notImplemented),
	_getIndexedMap: d(notImplemented),
	_storeIndexedValue: d(notImplemented),

	// Custom data
	getCustom: d(function (key) {
		key = ensureString(key);
		this._ensureOpen();
		++this._runningOperations;
		return this._getCustom(key).finally(this._onOperationEnd);
	}),
	storeCustom: d(function (key, value) {
		key = ensureString(key);
		this._ensureOpen();
		++this._runningOperations;
		return this._storeCustom(ensureString(key), value).finally(this._onOperationEnd);
	}),
	_getCustom: d(notImplemented),
	_storeCustom: d(notImplemented),

	// Any data
	_getRaw: d(notImplemented),
	_storeRaw: d(notImplemented),

	// Storage export/import
	export: d(function (externalStore) {
		ensureDriver(externalStore);
		this._ensureOpen();
		++this._runningOperations;
		return this._exportAll(externalStore).finally(this._onOperationEnd);
	}),
	_exportAll: d(notImplemented),

	// Clonnection related
	isClosed: d(false),
	close: d(function () {
		this._ensureOpen();
		this.isClosed = true;
		if (this._runningOperations) {
			this._closeDeferred = deferred();
			return this._closeDeferred.promise;
		}
		return this._close();
	}),
	_ensureOpen: d(function () {
		if (this.isClosed) throw new Error("Database not accessible");
	}),
	_runningOperations: d(0),
	_close: d(notImplemented)
}, autoBind({
	emitError: d(emitError),
	_onOperationEnd: d(function () {
		if (--this._runningOperations) return;
		if (!this._closeDeferred) return;
		this._closeDeferred.resolve(this._close());
	})
}), lazy({
	_loadedEventsMap: d(function () { return create(null); }),
	_eventsToStore: d(function () { return []; }),
	_exportEvents: d(function () {
		return once(function () {
			var promise = this._storeEvents(this._eventsToStore);
			clear.call(this._eventsToStore);
			promise.finally(this._onOperationEnd).done();
		}.bind(this));
	})
}))));
<commit_msg>Improve function signature<commit_after>// Abstract Persistence driver

'use strict';

var aFrom               = require('es5-ext/array/from')
  , clear               = require('es5-ext/array/#/clear')
  , isCopy              = require('es5-ext/array/#/is-copy')
  , ensureArray         = require('es5-ext/array/valid-array')
  , assign              = require('es5-ext/object/assign')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , isSet               = require('es6-set/is-set')
  , deferred            = require('deferred')
  , emitError           = require('event-emitter/emit-error')
  , d                   = require('d')
  , autoBind            = require('d/auto-bind')
  , lazy                = require('d/lazy')
  , debug               = require('debug-ext')('db')
  , ee                  = require('event-emitter')
  , getStamp            = require('time-uuid/time')
  , ensureObservableSet = require('observable-set/valid-observable-set')
  , ensureDatabase      = require('dbjs/valid-dbjs')
  , Event               = require('dbjs/_setup/event')
  , unserialize         = require('dbjs/_setup/unserialize/value')
  , serialize           = require('dbjs/_setup/serialize/value')
  , resolveKeyPath      = require('dbjs/_setup/utils/resolve-property-path')
  , once                = require('timers-ext/once')
  , ensureDriver        = require('./ensure')

  , isArray = Array.isArray
  , isModelId = RegExp.prototype.test.bind(/^[A-Z]/)
  , tokenize = resolveKeyPath.tokenize, resolveObject = resolveKeyPath.resolveObject
  , create = Object.create;

var PersistenceDriver = module.exports = Object.defineProperties(function (dbjs/*, options*/) {
	var autoSaveFilter, options;
	if (!(this instanceof PersistenceDriver)) return new PersistenceDriver(dbjs, arguments[1]);
	options = Object(arguments[1]);
	this.db = ensureDatabase(dbjs);
	autoSaveFilter = (options.autoSaveFilter != null)
		? ensureCallable(options.autoSaveFilter) : this.constructor.defaultAutoSaveFilter;
	dbjs.objects.on('update', function (event) {
		if (event.sourceId === 'persistentLayer') return;
		if (!autoSaveFilter(event)) return;
		debug("persistent update %s %s", event.object.__valueId__, event.stamp);
		this._cueEvent(event);
	}.bind(this));
}, {
	defaultAutoSaveFilter: d(function (event) { return !isModelId(event.object.master.__id__); })
});

var notImplemented = function () { throw new Error("Not implemented"); };

ee(Object.defineProperties(PersistenceDriver.prototype, assign({
	// Database data
	_importValue: d(function (id, value, stamp) {
		var proto;
		if (this._loadedEventsMap[id + '.' + stamp]) return;
		this._loadedEventsMap[id + '.' + stamp] = true;
		value = unserialize(value, this.db.objects);
		if (value && value.__id__ && (value.constructor.prototype === value)) proto = value.constructor;
		return new Event(this.db.objects.unserialize(id, proto), value, stamp, 'persistentLayer');
	}),
	getValue: d(function (id) {
		id = ensureString(id);
		this._ensureOpen();
		++this._runningOperations;
		return this._getRaw(id).finally(this._onOperationEnd);
	}),
	loadValue: d(function (id) {
		id = ensureString(id);
		this._ensureOpen();
		++this._runningOperations;
		return this._loadValue(id).finally(this._onOperationEnd);
	}),
	loadObject: d(function (objId) {
		objId = ensureString(objId);
		this._ensureOpen();
		++this._runningOperations;
		return this._loadObject(objId).finally(this._onOperationEnd);
	}),
	loadAll: d(function () {
		this._ensureOpen();
		++this._runningOperations;
		return this._loadAll().finally(this._onOperationEnd);
	}),
	storeEvent: d(function (event) {
		event = ensureObject(event);
		this._ensureOpen();
		++this._runningOperations;
		return this._storeEvent(event).finally(this._onOperationEnd);
	}),
	storeEvents: d(function (events) {
		events = ensureArray(events);
		this._ensureOpen();
		++this._runningOperations;
		return this._storeEvents(events).finally(this._onOperationEnd);
	}),
	_cueEvent: d(function (event) {
		if (!this._eventsToStore.length) {
			++this._runningOperations;
			this._exportEvents();
		}
		this._eventsToStore.push(event);
	}),
	_loadValue: d(notImplemented),
	_loadObject: d(notImplemented),
	_loadAll: d(notImplemented),
	_storeEvent: d(notImplemented),
	_storeEvents: d(notImplemented),

	// Indexed database data
	indexKeyPath: d(function (keyPath/*, set*/) {
		var names, key, onAdd, onDelete, eventName, listener, set = arguments[1];
		if (set != null) ensureObservableSet(set);
		else set = this.db.Object.instances;
		names = tokenize(ensureString(keyPath));
		this._ensureOpen();
		key = names[names.length - 1];
		eventName = 'computed:' + keyPath;
		++this._runningOperations;
		return this._getIndexedMap(keyPath)(function (map) {
			listener = function (event) {
				var sValue, stamp, objId = event.target.object.master.__id__;
				if (event.target.object.constructor === event.target.object.database.Base) return;
				if (isSet(event.target)) {
					sValue = [];
					event.target.forEach(function (value) { sValue.push(serialize(value)); });
				} else {
					sValue = serialize(event.newValue);
				}
				stamp = event.dbjs ? event.dbjs.stamp : getStamp();
				map[objId].value = sValue;
				map[objId].stamp = stamp;
				this.emit(eventName, map[objId]);
				++this._runningOperations;
				this._storeIndexedValue(objId, keyPath, map[objId]).finally(this._onOperationEnd).done();
			}.bind(this);
			onAdd = function (obj) {
				var observable, value, stamp, objId, sValue, old;
				obj = resolveObject(obj, names);
				if (!obj) return null;
				objId = obj.__id__;
				if (obj.isKeyStatic(key)) {
					value = obj[key];
					stamp = 0;
				} else {
					value = obj._get_(key);
					observable = obj._getObservable_(key);
					stamp = observable.lastModified;
					if (isSet(value)) value.on('change', listener);
					else observable.on('change', listener);
				}
				if (isSet(value)) {
					sValue = [];
					value.forEach(function (value) { sValue.push(serialize(value)); });
				} else {
					sValue = serialize(value);
				}
				old = map[objId];
				if (old) {
					if (old.stamp === stamp) {
						if (isArray(sValue)) {
							if (isCopy.call(old.value, sValue)) return;
						} else {
							if (old.value === sValue) return;
						}
						++stamp; // most likely model update
					} else if (old.stamp > stamp) {
						stamp = old.stamp + 1;
					}
					old.value = sValue;
					old.stamp = stamp;
				} else {
					map[objId] = {
						value: sValue,
						stamp: stamp
					};
				}
				this.emit(eventName, map[objId]);
				return this._storeIndexedValue(objId, keyPath, map[objId]);
			}.bind(this);
			onDelete = function (obj) {
				obj = resolveObject(obj, names);
				if (!obj) return null;
				if (obj.isKeyStatic(key)) return;
				obj._getObservable_(key).off('change', listener);
			}.bind(this);
			set.on('change', function (event) {
				if (event.type === 'add') {
					++this._runningOperations;
					onAdd(event.value).finally(this._onOperationEnd).done();
					return;
				}
				if (event.type === 'delete') {
					onDelete(event.value);
					return;
				}
				if (event.type === 'batch') {
					if (event.added) {
						++this._runningOperations;
						deferred.map(event.added, onAdd).finally(this._onOperationEnd).done();
					}
					if (event.deleted) event.deleted.forEach(onDelete);
				}
			}.bind(this));
			return deferred.map(aFrom(set), onAdd)(map);
		}.bind(this)).finally(this._onOperationEnd);
	}),
	_getIndexedValue: d(notImplemented),
	_getIndexedMap: d(notImplemented),
	_storeIndexedValue: d(notImplemented),

	// Custom data
	getCustom: d(function (key) {
		key = ensureString(key);
		this._ensureOpen();
		++this._runningOperations;
		return this._getCustom(key).finally(this._onOperationEnd);
	}),
	storeCustom: d(function (key, value) {
		key = ensureString(key);
		this._ensureOpen();
		++this._runningOperations;
		return this._storeCustom(ensureString(key), value).finally(this._onOperationEnd);
	}),
	_getCustom: d(notImplemented),
	_storeCustom: d(notImplemented),

	// Any data
	_getRaw: d(notImplemented),
	_storeRaw: d(notImplemented),

	// Storage export/import
	export: d(function (externalStore) {
		ensureDriver(externalStore);
		this._ensureOpen();
		++this._runningOperations;
		return this._exportAll(externalStore).finally(this._onOperationEnd);
	}),
	_exportAll: d(notImplemented),

	// Clonnection related
	isClosed: d(false),
	close: d(function () {
		this._ensureOpen();
		this.isClosed = true;
		if (this._runningOperations) {
			this._closeDeferred = deferred();
			return this._closeDeferred.promise;
		}
		return this._close();
	}),
	_ensureOpen: d(function () {
		if (this.isClosed) throw new Error("Database not accessible");
	}),
	_runningOperations: d(0),
	_close: d(notImplemented)
}, autoBind({
	emitError: d(emitError),
	_onOperationEnd: d(function () {
		if (--this._runningOperations) return;
		if (!this._closeDeferred) return;
		this._closeDeferred.resolve(this._close());
	})
}), lazy({
	_loadedEventsMap: d(function () { return create(null); }),
	_eventsToStore: d(function () { return []; }),
	_exportEvents: d(function () {
		return once(function () {
			var promise = this._storeEvents(this._eventsToStore);
			clear.call(this._eventsToStore);
			promise.finally(this._onOperationEnd).done();
		}.bind(this));
	})
}))));
<|endoftext|>