<commit_before>/* global describe, it, xit */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai');
chai.use(require("chai-as-promised"));
const assert = chai.assert;
const expect = chai.expect;
const should = chai.should();

let path = require('path');
let uti = require('../index.js');

describe('uti', function () {

  describe('buildin UTIs', function () {
    it('should be present', function (done) {
      uti.initialize().then(function () {
        const u1 = uti.getUTI('public.json');
        should.exist(u1);
        assert(u1.toJSON().name === 'public.json');
        done();
      }, done);
    });

    describe('getUTIsForFileName', function () {
      it('simple', function (done) {
        uti.initialize().then(function () {
          assert(uti.getUTIsForFileName('a.txt')[0] === 'public.plain-text');
          assert(uti.getUTIsForFileName('a') === undefined);
          done();
        }, done);
      });
    });

    describe('getUTIsMimeType', function () {
      it('simple', function (done) {
        uti.initialize().then(function () {
          assert(uti.getUTIsForMimeType('text/plain')[0] === 'public.plain-text');
          done();
        }, done);
      });
    });

    describe('conformsTo', function () {
      it('positive', function (done) {
        uti.initialize().then(function () {
          try {
            assert(uti.conformsTo('public.image', 'public.data'));
            assert(uti.conformsTo('public.image', 'public.content'));
            assert(uti.conformsTo('public.plain-text', 'public.data'));
            assert(uti.conformsTo('public.tar-archive', 'public.data'));
            assert(uti.conformsTo('public.volume', 'public.folder'));
            assert(uti.conformsTo('public.volume', 'public.directory'));
            assert(uti.conformsTo('public.volume', 'public.item'));
            done();
          } catch (e) {
            done(e);
          }
        }, done);
      });
      it('negative', function (done) {
        uti.initialize().then(function () {
          try {
            assert(!uti.conformsTo('undefined.uti', 'public.xml'));
            assert(!uti.conformsTo('public.image', 'public.xml'));
            done();
          } catch (e) {
            done(e);
          }
        }, done);
      });
    });
  });

  describe('load additional UTIs', function () {
    it('should be present', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'uti.json')
      }).then(function () {
        const json = uti.getUTI('public.json');
        should.exist(json);
        const myUTI = uti.getUTI('com.mydomain.sample');
        should.exist(myUTI, `is present ${myUTI}`);
        done();
      }, done);
    });

    it('chained request should work', function (done) {
      uti.initialize({
          definitionFileName: path.join(__dirname, 'fixtures', 'uti.json')
        })
        .then(function () {
          return uti.loadDefinitionsFromFile(path.join(__dirname, 'fixtures', 'uti2.json'));
        })
        .then(function () {
          try {
            const json = uti.getUTI('public.json');
            should.exist(json);

            const myUTI = uti.getUTI('com.mydomain.sample2');
            should.exist(myUTI, 'com.mydomain.sample2');
            done();
          } catch (e) {
            done(e);
          }
        }, done);
    });
  });

  describe('loading errors', function () {
    it('should fail on missing file', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'missing_file.json')
      }).then(function () {
        done(new Error('should have failed with missing file'));
      }, function (error) {
        assert(error.toString().match(/ENOENT/));
        done();
      });
    });

    it('should fail with json syntax error', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'invalid.json')
      }).then(function () {
        done(new Error('should have failed with SyntaxError'));
      }, function (error) {
        assert(error.toString().match(/SyntaxError/));
        done();
      });
    });

    it('should fail with referene error', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'missing_reference.json')
      }).then(function () {
        done(new Error('should have failed with reference error'));
      }, function (error) {
        assert(error.toString().match(/Referenced/));
        done();
      });
    });
  });
});
<commit_msg>test: make more use of chai assert .isTrue, .equals, ...<commit_after>/* global describe, it, xit */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai');
chai.use(require("chai-as-promised"));
const assert = chai.assert;
const expect = chai.expect;
const should = chai.should();

let path = require('path');
let uti = require('../index.js');

describe('uti', function () {

  describe('buildin UTIs', function () {
    it('should be present', function (done) {
      uti.initialize().then(function () {
        const u1 = uti.getUTI('public.json');
        should.exist(u1);
        assert.equal(u1.toJSON().name, 'public.json');
        done();
      }, done);
    });

    describe('getUTIsForFileName', function () {
      it('simple', function (done) {
        uti.initialize().then(function () {
          assert.equal(uti.getUTIsForFileName('a.txt')[0], 'public.plain-text');
          assert.isUndefined(uti.getUTIsForFileName('a'));
          done();
        }, done);
      });
    });

    describe('getUTIsMimeType', function () {
      it('simple', function (done) {
        uti.initialize().then(function () {
          assert.equal(uti.getUTIsForMimeType('text/plain')[0], 'public.plain-text');
          done();
        }, done);
      });
    });

    describe('conformsTo', function () {
      it('positive', function (done) {
        uti.initialize().then(function () {
          try {
            assert.isTrue(uti.conformsTo('public.image', 'public.data'));
            assert.isTrue(uti.conformsTo('public.image', 'public.content'));
            assert.isTrue(uti.conformsTo('public.plain-text', 'public.data'));
            assert.isTrue(uti.conformsTo('public.tar-archive', 'public.data'));
            assert.isTrue(uti.conformsTo('public.volume', 'public.folder'));
            assert.isTrue(uti.conformsTo('public.volume', 'public.directory'));
            assert.isTrue(uti.conformsTo('public.volume', 'public.item'));
            done();
          } catch (e) {
            done(e);
          }
        }, done);
      });
      it('negative', function (done) {
        uti.initialize().then(function () {
          try {
            assert.isFalse(uti.conformsTo('undefined.uti', 'public.xml'));
            assert.isFalse(uti.conformsTo('public.image', 'public.xml'));
            done();
          } catch (e) {
            done(e);
          }
        }, done);
      });
    });
  });

  describe('load additional UTIs', function () {
    it('should be present', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'uti.json')
      }).then(function () {
        const json = uti.getUTI('public.json');
        should.exist(json);
        const myUTI = uti.getUTI('com.mydomain.sample');
        should.exist(myUTI, `is present ${myUTI}`);
        done();
      }, done);
    });

    it('chained request should work', function (done) {
      uti.initialize({
          definitionFileName: path.join(__dirname, 'fixtures', 'uti.json')
        })
        .then(function () {
          return uti.loadDefinitionsFromFile(path.join(__dirname, 'fixtures', 'uti2.json'));
        })
        .then(function () {
          try {
            const json = uti.getUTI('public.json');
            should.exist(json);

            const myUTI = uti.getUTI('com.mydomain.sample2');
            should.exist(myUTI, 'com.mydomain.sample2');
            done();
          } catch (e) {
            done(e);
          }
        }, done);
    });
  });

  describe('loading errors', function () {
    it('should fail on missing file', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'missing_file.json')
      }).then(function () {
        done(new Error('should have failed with missing file'));
      }, function (error) {
        assert(error.toString().match(/ENOENT/));
        done();
      });
    });

    it('should fail with json syntax error', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'invalid.json')
      }).then(function () {
        done(new Error('should have failed with SyntaxError'));
      }, function (error) {
        assert(error.toString().match(/SyntaxError/));
        done();
      });
    });

    it('should fail with referene error', function (done) {
      uti.initialize({
        definitionFileName: path.join(__dirname, 'fixtures', 'missing_reference.json')
      }).then(function () {
        done(new Error('should have failed with reference error'));
      }, function (error) {
        assert(error.toString().match(/Referenced/));
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 * Stores information on sip devices currently registered in the server.
 * This implementation won't scale to thousands of devices.
 *
 * @author Pedro Sanders
 * @since v1
 */
import isEmpty from 'utils/obj_util'
import { Status } from 'location/status'
import { Status as RStatus } from 'data_api/status'

const HashMap = Packages.java.util.HashMap
const LogManager = Packages.org.apache.logging.log4j.LogManager
const LOG = LogManager.getLogger()
const SipFactory = Packages.javax.sip.SipFactory

/**
 * NOTE #1: Notice that addressOfRecord.toString !eq to this.aorAsString(addressOfRecord). This is important to ensure
 * the location of the devices regardless of any additional parameters that they may have.
 */
export default class Locator {

    constructor(dataAPIs, checkExpiresTime = 1) {
        this.checkExpiresTime = checkExpiresTime
        this.db = new HashMap()
        this.didsAPI = dataAPIs.DIDsAPI
        this.domainsAPI = dataAPIs.DomainsAPI
        this.gatewaysAPI = dataAPIs.GatewaysAPI
        this.addressFactory = SipFactory.getInstance().createAddressFactory()
    }

    aorAsString(addressOfRecord) {
        if (addressOfRecord instanceof Packages.javax.sip.address.TelURL) {
            return 'tel:' + addressOfRecord.getPhoneNumber()
        } else if (addressOfRecord instanceof Packages.javax.sip.address.SipURI) {
            if (addressOfRecord.isSecure()) {
                return 'sips:' + addressOfRecord.getUser() + '@' + addressOfRecord.getHost()
            } else {
                return 'sip:' + addressOfRecord.getUser() + '@' + addressOfRecord.getHost()
            }
        } else {
            if (/sips?:.*@.*/.test(addressOfRecord) ||
                /tel:\d+/.test(addressOfRecord)) {
                return addressOfRecord
            }
           LOG.error('Invalid AOR: ' + addressOfRecord)
        }

        throw 'Invalid AOR: ' + addressOfRecord
    }

    addEndpoint(addressOfRecord, route) {
        const response = this.findEndpoint(addressOfRecord)
        let routes

        // ThruGw is not available in db. We obtain that from api
        if (response.status == Status.OK && !response.result.thruGw) {
            routes = response.result
        } else {
            routes = new HashMap()
        }

        // Not using aorAsString because we need to consider the port, etc.
        const routeKey = route.contactURI.toString()
        routes.put(routeKey, route)

        // See NOTE #1
        this.db.put(this.aorAsString(addressOfRecord), routes)
    }

    findEndpoint(addressOfRecord) {
        let response

        if (addressOfRecord instanceof Packages.javax.sip.address.TelURL) {
            response = this.didsAPI.getDIDByTelUrl(addressOfRecord)
            if (response.status == Status.OK) {
                const did = response.result
                const route = this.db.get(this.aorAsString(did.spec.location.aorLink))

                if (route != null) {
                    return {
                        status: Status.OK,
                        message: Status.message[Status.OK].value,
                        result: route
                    }
                }
            }
        } else if (addressOfRecord instanceof Packages.javax.sip.address.SipURI) {

            // First just check the db for such addressOfRecord
            let routes = this.db.get(this.aorAsString(addressOfRecord))

            if (routes != null) {
                return {
                    status: Status.OK,
                    message: Status.message[Status.OK].value,
                    result: routes
                }
            }

            // Check peer's route by host
            response = this.getPeerRouteByHost(addressOfRecord)

            if (response.status == Status.OK) {
                return {
                    status: Status.OK,
                    message: Status.message[Status.OK].value,
                    result: response.result
                }
            }

            // Then search for a DID
            try {
                const telUrl = this.addressFactory.createTelURL(addressOfRecord.getUser())
                response = this.didsAPI.getDIDByTelUrl(telUrl)

                if (response.status == Status.OK) {
                    const did = response.result
                    const route = this.db.get(this.aorAsString(did.spec.location.aorLink))

                    if (route != null) {
                        return {
                            status: Status.OK,
                            message: Status.message[Status.OK].value,
                            result: route
                        }
                    }
                }
            } catch(e) {
                // Ignore error
            }

            // Endpoint can only be reach thru a gateway
            response = this.getEgressRouteForAOR(addressOfRecord)

            if (response.status == Status.OK) {
                return {
                    status: Status.OK,
                    message: Status.message[Status.OK].value,
                    result: response.result
                }
            }
        }

        return {
            status: Status.NOT_FOUND,
            message: Status.message[Status.NOT_FOUND].value
        }
    }

    listAsJSON (domainUri) {
        let s = []
        const aors = this.db.keySet().iterator()

        while(aors.hasNext()) {
            let key = aors.next()
            let routes = this.db.get(key)
            let contactInfo = ''
            let i = routes.values().iterator()

            if (i.hasNext()) {
                const rObj = i.next()
                let r = rObj.contactURI + ';nat=' + rObj.nat + ';expires=' + rObj.expires

                if (i.hasNext()) r = r + ' [...]'
                contactInfo = contactInfo + r
            }

            let tmp = {
                'addressOfRecord': key,
                'contactInfo': contactInfo
            }
            s.push(tmp)
        }

        return JSON.stringify(s)
    }

    // See NOTE #1
    removeEndpoint(addressOfRecord, contactURI) {
        const aor = this.aorAsString(addressOfRecord)
        // Remove all bindings
        if (contactURI == null) {
            return this.db.remove(aor)
        }
        // Not using aorAsString because we need to consider the port, etc.
        this.db.get(aor).remove(contactURI.toString())

        if (this.db.get(aor).isEmpty()) this.db.remove(aor)
    }

    getPeerRouteByHost(addressOfRecord) {
        const aors = this.db.keySet().iterator()

        while(aors.hasNext()) {
            let key = aors.next()
            let routes = this.db.get(key)
            let i = routes.values().iterator()

            if (i.hasNext()) {
                const rObj = i.next()
                rObj.contactURI
                const h1 = rObj.contactURI.getHost().toString()
                const h2 = addressOfRecord.getHost().toString()
                const p1 = rObj.contactURI.getPort() == -1? 5060 : rObj.contactURI.getPort()
                const p2 = addressOfRecord.getPort() == -1? 5060 : addressOfRecord.getPort()
                if (h1.equals(h2) && p1 == p2) {
                    return {
                        status: Status.OK,
                        message: Status.message[Status.OK].value,
                        result: rObj
                    }
                }
            }
        }

        return {
            status: Status.NOT_FOUND,
            message: Status.message[Status.NOT_FOUND].value
        }
    }

    getEgressRouteForAOR(addressOfRecord) {
        if (!(addressOfRecord instanceof Packages.javax.sip.address.SipURI)) throw 'AOR must be an instance of javax.sip.address.SipURI'

        const didsAPI = this.didsAPI
        const domainsAPI = this.domainsAPI
        const gatewaysAPI = this.gatewaysAPI
        const addressFactory = this.addressFactory

        let response = domainsAPI.getDomains()
        let route

        if (response.status == RStatus.OK) {
            const domains = response.result

            domains.forEach(domain => {
                if (!isEmpty(domain.spec.context.egressPolicy)) {
                    // Get DID and Gateway info
                    response = didsAPI.getDID(domain.spec.context.egressPolicy.didRef)

                    if (response.status == RStatus.OK) {
                        const did = response.result
                        response = gatewaysAPI.getGateway(did.metadata.gwRef)

                        if (response.status == RStatus.OK) {
                            const gw = response.result
                            const gwHost = gw.spec.regService.host
                            const gwUsername = gw.spec.regService.credentials.username
                            const gwRef = gw.metadata.ref
                            const egressRule = domain.spec.context.egressPolicy.rule
                            const pattern = 'sip:' + egressRule + '@' + domain.spec.context.domainUri

                            if (new RegExp(pattern).test(addressOfRecord.toString())) {
                                const contactURI = addressFactory.createSipURI(addressOfRecord.getUser(), gwHost)
                                contactURI.setSecure(addressOfRecord.isSecure())

                                route = {
                                    isLinkAOR: false,
                                    thruGw: true,
                                    rule: egressRule,
                                    gwUsername: gwUsername,
                                    gwRef: gwRef,
                                    gwHost: gwHost,
                                    didRef: did.metadata.didRef,
                                    did: did.spec.location.telUrl.split(':')[1],
                                    contactURI: contactURI
                                }
                            }
                        }
                    }
                }
            })
        }

        if(route) {
            return {
                status: RStatus.OK,
                message: RStatus.message[RStatus.OK].value,
                result: route
            }
        }

        return {
            status: RStatus.NOT_FOUND,
            message: RStatus.message[RStatus.NOT_FOUND].value
        }
    }

    getEgressRouteForPeer(addressOfRecord, didRef) {
        const addressFactory = this.addressFactory
        let response = this.didsAPI.getDID(didRef)
        let route

        if (response.status == Status.OK) {
            const did = response.result
            response = this.gatewaysAPI.getGateway(did.metadata.gwRef)

            if (response.status == Status.OK) {
                const gw = response.result
                const gwHost = gw.spec.regService.host
                const gwUsername = gw.spec.regService.credentials.username
                const gwRef = gw.metadata.ref

                const contactURI = addressFactory.createSipURI(addressOfRecord.getUser(), gwHost)

                route = {
                    isLinkAOR: false,
                    thruGw: true,
                    gwUsername: gwUsername,
                    gwRef: gwRef,
                    gwHost: gwHost,
                    didRef: didRef,
                    did: did.spec.location.telUrl.split(':')[1],
                    contactURI: contactURI
                }
           }
        }

        if(route) {
            return {
                status: RStatus.OK,
                message: RStatus.message[RStatus.OK].value,
                result: route
            }
        }

        return {
            status: RStatus.NOT_FOUND,
            message: RStatus.message[RStatus.NOT_FOUND].value
        }
    }

    start() {
        LOG.info('Starting Location service')
        var locDB = this.db

        let unbindExpiredTask = new java.util.TimerTask({
            run: function() {
                const e = locDB.values().iterator()

                while(e.hasNext()) {
                    let routes = e.next()
                    let i = routes.values().iterator()

                    while (i.hasNext()) {
                        const route = i.next()
                        const elapsed = (Date.now() - route.registeredOn) / 1000
                        if ((route.expires - elapsed) <= 0) {
                            i.remove()
                        }

                        if (routes.size() == 0) e.remove()
                    }
                }
            }
        })

        new java.util.Timer().schedule(unbindExpiredTask, 5000, this.checkExpiresTime * 60 * 1000)
    }

    stop() {
        // ??
    }
}
<commit_msg>Change function to return an object instead of a string<commit_after>/**
 * Stores information on sip devices currently registered in the server.
 * This implementation won't scale to thousands of devices.
 *
 * @author Pedro Sanders
 * @since v1
 */
import isEmpty from 'utils/obj_util'
import { Status } from 'location/status'
import { Status as RStatus } from 'data_api/status'

const HashMap = Packages.java.util.HashMap
const LogManager = Packages.org.apache.logging.log4j.LogManager
const LOG = LogManager.getLogger()
const SipFactory = Packages.javax.sip.SipFactory

/**
 * NOTE #1: Notice that addressOfRecord.toString !eq to this.aorAsString(addressOfRecord). This is important to ensure
 * the location of the devices regardless of any additional parameters that they may have.
 */
export default class Locator {

    constructor(dataAPIs, checkExpiresTime = 1) {
        this.checkExpiresTime = checkExpiresTime
        this.db = new HashMap()
        this.didsAPI = dataAPIs.DIDsAPI
        this.domainsAPI = dataAPIs.DomainsAPI
        this.gatewaysAPI = dataAPIs.GatewaysAPI
        this.addressFactory = SipFactory.getInstance().createAddressFactory()
    }

    aorAsString(addressOfRecord) {
        if (addressOfRecord instanceof Packages.javax.sip.address.TelURL) {
            return 'tel:' + addressOfRecord.getPhoneNumber()
        } else if (addressOfRecord instanceof Packages.javax.sip.address.SipURI) {
            if (addressOfRecord.isSecure()) {
                return 'sips:' + addressOfRecord.getUser() + '@' + addressOfRecord.getHost()
            } else {
                return 'sip:' + addressOfRecord.getUser() + '@' + addressOfRecord.getHost()
            }
        } else {
            if (/sips?:.*@.*/.test(addressOfRecord) ||
                /tel:\d+/.test(addressOfRecord)) {
                return addressOfRecord
            }
           LOG.error('Invalid AOR: ' + addressOfRecord)
        }

        throw 'Invalid AOR: ' + addressOfRecord
    }

    addEndpoint(addressOfRecord, route) {
        const response = this.findEndpoint(addressOfRecord)
        let routes

        // ThruGw is not available in db. We obtain that from api
        if (response.status == Status.OK && !response.result.thruGw) {
            routes = response.result
        } else {
            routes = new HashMap()
        }

        // Not using aorAsString because we need to consider the port, etc.
        const routeKey = route.contactURI.toString()
        routes.put(routeKey, route)

        // See NOTE #1
        this.db.put(this.aorAsString(addressOfRecord), routes)
    }

    findEndpoint(addressOfRecord) {
        let response

        if (addressOfRecord instanceof Packages.javax.sip.address.TelURL) {
            response = this.didsAPI.getDIDByTelUrl(addressOfRecord)
            if (response.status == Status.OK) {
                const did = response.result
                const route = this.db.get(this.aorAsString(did.spec.location.aorLink))

                if (route != null) {
                    return {
                        status: Status.OK,
                        message: Status.message[Status.OK].value,
                        result: route
                    }
                }
            }
        } else if (addressOfRecord instanceof Packages.javax.sip.address.SipURI) {

            // First just check the db for such addressOfRecord
            let routes = this.db.get(this.aorAsString(addressOfRecord))

            if (routes != null) {
                return {
                    status: Status.OK,
                    message: Status.message[Status.OK].value,
                    result: routes
                }
            }

            // Check peer's route by host
            response = this.getPeerRouteByHost(addressOfRecord)

            if (response.status == Status.OK) {
                return {
                    status: Status.OK,
                    message: Status.message[Status.OK].value,
                    result: response.result
                }
            }

            // Then search for a DID
            try {
                const telUrl = this.addressFactory.createTelURL(addressOfRecord.getUser())
                response = this.didsAPI.getDIDByTelUrl(telUrl)

                if (response.status == Status.OK) {
                    const did = response.result
                    const route = this.db.get(this.aorAsString(did.spec.location.aorLink))

                    if (route != null) {
                        return {
                            status: Status.OK,
                            message: Status.message[Status.OK].value,
                            result: route
                        }
                    }
                }
            } catch(e) {
                // Ignore error
            }

            // Endpoint can only be reach thru a gateway
            response = this.getEgressRouteForAOR(addressOfRecord)

            if (response.status == Status.OK) {
                return {
                    status: Status.OK,
                    message: Status.message[Status.OK].value,
                    result: response.result
                }
            }
        }

        return {
            status: Status.NOT_FOUND,
            message: Status.message[Status.NOT_FOUND].value
        }
    }

    listAsJSON (domainUri) {
        let s = []
        const aors = this.db.keySet().iterator()

        while(aors.hasNext()) {
            let key = aors.next()
            let routes = this.db.get(key)
            let contactInfo = ''
            let i = routes.values().iterator()

            if (i.hasNext()) {
                const rObj = i.next()
                let r = rObj.contactURI + ';nat=' + rObj.nat + ';expires=' + rObj.expires

                if (i.hasNext()) r = r + ' [...]'
                contactInfo = contactInfo + r
            }

            let tmp = {
                'addressOfRecord': key,
                'contactInfo': contactInfo
            }
            s.push(tmp)
        }

        return s
    }

    // See NOTE #1
    removeEndpoint(addressOfRecord, contactURI) {
        const aor = this.aorAsString(addressOfRecord)
        // Remove all bindings
        if (contactURI == null) {
            return this.db.remove(aor)
        }
        // Not using aorAsString because we need to consider the port, etc.
        this.db.get(aor).remove(contactURI.toString())

        if (this.db.get(aor).isEmpty()) this.db.remove(aor)
    }

    getPeerRouteByHost(addressOfRecord) {
        const aors = this.db.keySet().iterator()

        while(aors.hasNext()) {
            let key = aors.next()
            let routes = this.db.get(key)
            let i = routes.values().iterator()

            if (i.hasNext()) {
                const rObj = i.next()
                rObj.contactURI
                const h1 = rObj.contactURI.getHost().toString()
                const h2 = addressOfRecord.getHost().toString()
                const p1 = rObj.contactURI.getPort() == -1? 5060 : rObj.contactURI.getPort()
                const p2 = addressOfRecord.getPort() == -1? 5060 : addressOfRecord.getPort()
                if (h1.equals(h2) && p1 == p2) {
                    return {
                        status: Status.OK,
                        message: Status.message[Status.OK].value,
                        result: rObj
                    }
                }
            }
        }

        return {
            status: Status.NOT_FOUND,
            message: Status.message[Status.NOT_FOUND].value
        }
    }

    getEgressRouteForAOR(addressOfRecord) {
        if (!(addressOfRecord instanceof Packages.javax.sip.address.SipURI)) throw 'AOR must be an instance of javax.sip.address.SipURI'

        const didsAPI = this.didsAPI
        const domainsAPI = this.domainsAPI
        const gatewaysAPI = this.gatewaysAPI
        const addressFactory = this.addressFactory

        let response = domainsAPI.getDomains()
        let route

        if (response.status == RStatus.OK) {
            const domains = response.result

            domains.forEach(domain => {
                if (!isEmpty(domain.spec.context.egressPolicy)) {
                    // Get DID and Gateway info
                    response = didsAPI.getDID(domain.spec.context.egressPolicy.didRef)

                    if (response.status == RStatus.OK) {
                        const did = response.result
                        response = gatewaysAPI.getGateway(did.metadata.gwRef)

                        if (response.status == RStatus.OK) {
                            const gw = response.result
                            const gwHost = gw.spec.regService.host
                            const gwUsername = gw.spec.regService.credentials.username
                            const gwRef = gw.metadata.ref
                            const egressRule = domain.spec.context.egressPolicy.rule
                            const pattern = 'sip:' + egressRule + '@' + domain.spec.context.domainUri

                            if (new RegExp(pattern).test(addressOfRecord.toString())) {
                                const contactURI = addressFactory.createSipURI(addressOfRecord.getUser(), gwHost)
                                contactURI.setSecure(addressOfRecord.isSecure())

                                route = {
                                    isLinkAOR: false,
                                    thruGw: true,
                                    rule: egressRule,
                                    gwUsername: gwUsername,
                                    gwRef: gwRef,
                                    gwHost: gwHost,
                                    didRef: did.metadata.didRef,
                                    did: did.spec.location.telUrl.split(':')[1],
                                    contactURI: contactURI
                                }
                            }
                        }
                    }
                }
            })
        }

        if(route) {
            return {
                status: RStatus.OK,
                message: RStatus.message[RStatus.OK].value,
                result: route
            }
        }

        return {
            status: RStatus.NOT_FOUND,
            message: RStatus.message[RStatus.NOT_FOUND].value
        }
    }

    getEgressRouteForPeer(addressOfRecord, didRef) {
        const addressFactory = this.addressFactory
        let response = this.didsAPI.getDID(didRef)
        let route

        if (response.status == Status.OK) {
            const did = response.result
            response = this.gatewaysAPI.getGateway(did.metadata.gwRef)

            if (response.status == Status.OK) {
                const gw = response.result
                const gwHost = gw.spec.regService.host
                const gwUsername = gw.spec.regService.credentials.username
                const gwRef = gw.metadata.ref

                const contactURI = addressFactory.createSipURI(addressOfRecord.getUser(), gwHost)

                route = {
                    isLinkAOR: false,
                    thruGw: true,
                    gwUsername: gwUsername,
                    gwRef: gwRef,
                    gwHost: gwHost,
                    didRef: didRef,
                    did: did.spec.location.telUrl.split(':')[1],
                    contactURI: contactURI
                }
           }
        }

        if(route) {
            return {
                status: RStatus.OK,
                message: RStatus.message[RStatus.OK].value,
                result: route
            }
        }

        return {
            status: RStatus.NOT_FOUND,
            message: RStatus.message[RStatus.NOT_FOUND].value
        }
    }

    start() {
        LOG.info('Starting Location service')
        var locDB = this.db

        let unbindExpiredTask = new java.util.TimerTask({
            run: function() {
                const e = locDB.values().iterator()

                while(e.hasNext()) {
                    let routes = e.next()
                    let i = routes.values().iterator()

                    while (i.hasNext()) {
                        const route = i.next()
                        const elapsed = (Date.now() - route.registeredOn) / 1000
                        if ((route.expires - elapsed) <= 0) {
                            i.remove()
                        }

                        if (routes.size() == 0) e.remove()
                    }
                }
            }
        })

        new java.util.Timer().schedule(unbindExpiredTask, 5000, this.checkExpiresTime * 60 * 1000)
    }

    stop() {
        // ??
    }
}
<|endoftext|>


<commit_before>var x, y, l, bx, by, g, c, player = [],
  stop = 0,
  brickx, bricky,
  brick = [],
  ball = [];

function setup() {
  createCanvas(780, 550);
  background(100);
  by = height - 100;
  bx = width / 2;
  var r = random(1, 2);
  r = round(r);
  layout(r);
  for (var a = 0; a < 1; a++) {
    player.push(new Player());
  }
  for (var b = 0; b < 1; b++) {
    ball.push(new Ball());
  }
  for (var i = 0; i < g; i++) {
    brick.push(new Brick());
  }
  layout2(r);
}

function draw() {
    if (brick.length < 1) {
     x, y, l, bx, by, g, c, player = [],
      stop = 0,
      brickx, bricky,
      brick = [],
      ball = [];
    by = height - 100;
    bx = width / 2;
    var r = random(1, 2);
    r = round(r);
    layout(r);
    for (var a = 0; a < 1; a++) {
      player.push(new Player());
    }
    for (var b = 0; b < 1; b++) {
      ball.push(new Ball());
    }
    for (var i = 0; i < g; i++) {
      brick.push(new Brick());
    }
    layout2(r);
  }
  background(100);
  if (stop == 0) {
    for (var a = 0; a < player.length; a++) {
      player[a].display();
    }
    for (var b = 0; b < ball.length; b++) {
      ball[b].display();
      ball[b].move();
      ball[b].hit();
    }
    for (var i = brick.length - 1; i > -1; i--) {
      brick[i].display();
      brick[i].hit();
    }
  }
  if (stop === 1) {
    button();
  }
}

function Brick() {
  this.display = function() {
    fill(150, 80, 30);
    rect(this.x, this.y, 60, 20);
  };
  this.hit = function() {
    for (var q = brick.length - 1; q > -1; q--) {
      if (bx > brick[q].x - 7 && bx < brick[q].x + 67 && by > brick[q].y - 7 && by < brick[q].y + 27) {
        brick.splice(q, 1);
        ball[0].diry = ball[0].diry * (-1) + 1;
        break;
      }
    }
  };
}

function layout(l) {
  if (l === 1) {
    g = 208;
  }
  if (l === 2) {
    g = 27 * 2;
  }
}

function layout2(l) {
  c = 0;
  if (l === 1) {
    for (var h = 1; h < 17; h++) {
      for (var w = 0; w < g / 16; w++) {
        brick[c].x = w * 60;
        brick[c].y = h * 20;
        c++;
      }
    }
  }
  if (l === 2) {
    for (var c = 0; c < g / 2; c++) {
      brick[c].y = c * 20 + 5;
      brick[c].x = c * 27 + 5;
    }
    for (c = 0; c < g / 2; c++) {
      brick[c + g / 2].y = c * 20 + 5;
      brick[c + g / 2].x = (width - 65) - (c * 27 + 5);
    }
  }
}

function Player() {
  this.display = function() {
    x = mouseX - 30;
    y = height - 25;
    fill(255);
    rect(x, y, 80, 10);
  };
}

function Ball() {
  this.dirx = random(-3, 3);
  this.diry = random(3);
  this.display = function() {
    fill(255);
    ellipse(bx, by, 15, 15);
  };
  this.move = function() {
    bx = bx + this.dirx;
    by = by + this.diry;
  };
  this.hit = function() {
    if (bx > width - 7) {
      this.dirx = random(-3, 1);
    }
    if (bx < 7) {
      this.dirx = random(1, 3);
    }
    if (by < 7) {
      this.diry = random(1, 3);
    }
    if (bx < x + 80 && bx > x && by > y && by < y + 15) {
      this.diry = random(-3, -1);
      this.dirx = random(-3, 3);
      while (by < y) {
        y--;
      }
    }
    if (by > height + 15) {
      stop = 1;
    }
  };
}
<commit_msg>Update sketch.js<commit_after>var x, y, l, bx, by, g, c, player = [],
  stop = 0,
  brickx, bricky,
  brick = [],
  ball = [];

function setup() {
  createCanvas(780, 550);
  background(100);
  by = height - 100;
  bx = width / 2;
  var r = random(1, 2);
  r = round(r);
  layout(r);
  for (var a = 0; a < 1; a++) {
    player.push(new Player());
  }
  for (var b = 0; b < 1; b++) {
    ball.push(new Ball());
  }
  for (var i = 0; i < g; i++) {
    brick.push(new Brick());
  }
  layout2(r);
}

function draw() {
    if (brick.length < 1) {
     x, y, l, bx, by, g, c, player = [],
      stop = 0,
      brickx, bricky,
      brick = [],
      ball = [];
    by = height - 100;
    bx = width / 2;
    var r = random(1, 2);
    r = round(r);
    layout(r);
    for (var a = 0; a < 1; a++) {
      player.push(new Player());
    }
    for (var b = 0; b < 1; b++) {
      ball.push(new Ball());
    }
    for (var i = 0; i < g; i++) {
      brick.push(new Brick());
    }
    layout2(r);
  }
  background(100);
  textSize(20);
  fill(255);
  text("©Javi", width - 55, height - 10);
  if (stop == 0) {
    for (var a = 0; a < player.length; a++) {
      player[a].display();
    }
    for (var b = 0; b < ball.length; b++) {
      ball[b].display();
      ball[b].move();
      ball[b].hit();
    }
    for (var i = brick.length - 1; i > -1; i--) {
      brick[i].display();
      brick[i].hit();
    }
  }
  if (stop === 1) {
    button();
  }
}

function Brick() {
  this.display = function() {
    fill(150, 80, 30);
    rect(this.x, this.y, 60, 20);
  };
  this.hit = function() {
    for (var q = brick.length - 1; q > -1; q--) {
      if (bx > brick[q].x - 7 && bx < brick[q].x + 67 && by > brick[q].y - 7 && by < brick[q].y + 27) {
        brick.splice(q, 1);
        ball[0].diry = ball[0].diry * (-1) + 1;
        break;
      }
    }
  };
}

function layout(l) {
  if (l === 1) {
    g = 208;
  }
  if (l === 2) {
    g = 27 * 2;
  }
}

function layout2(l) {
  c = 0;
  if (l === 1) {
    for (var h = 1; h < 17; h++) {
      for (var w = 0; w < g / 16; w++) {
        brick[c].x = w * 60;
        brick[c].y = h * 20;
        c++;
      }
    }
  }
  if (l === 2) {
    for (var c = 0; c < g / 2; c++) {
      brick[c].y = c * 20 + 5;
      brick[c].x = c * 27 + 5;
    }
    for (c = 0; c < g / 2; c++) {
      brick[c + g / 2].y = c * 20 + 5;
      brick[c + g / 2].x = (width - 65) - (c * 27 + 5);
    }
  }
}

function Player() {
  this.display = function() {
    x = mouseX - 30;
    y = height - 25;
    fill(255);
    rect(x, y, 80, 10);
  };
}

function Ball() {
  this.dirx = random(-3, 3);
  this.diry = random(3);
  this.display = function() {
    fill(255);
    ellipse(bx, by, 15, 15);
  };
  this.move = function() {
    bx = bx + this.dirx;
    by = by + this.diry;
  };
  this.hit = function() {
    if (bx > width - 7) {
      this.dirx = random(-3, 1);
    }
    if (bx < 7) {
      this.dirx = random(1, 3);
    }
    if (by < 7) {
      this.diry = random(1, 3);
    }
    if (bx < x + 80 && bx > x && by > y && by < y + 15) {
      this.diry = random(-3, -1);
      this.dirx = random(-3, 3);
      while (by < y) {
        y--;
      }
    }
    if (by > height + 15) {
      stop = 1;
    }
  };
}
<|endoftext|>


<commit_before>//    Copyright (c) 2015, Thomas E. Dunn
//    Copyright (c) 2017, Matt Godbolt
//    Copyright (c) 2018, Forschungzentrum Juelich GmbH
//                        Juelich Supercomputing Centre
//    All rights reserved.
//
//    Redistribution and use in source and binary forms, with or without
//    modification, are permitted provided that the following conditions are met:
//
//        * Redistributions of source code must retain the above copyright notice,
//          this list of conditions and the following disclaimer.
//        * Redistributions in binary form must reproduce the above copyright
//          notice, this list of conditions and the following disclaimer in the
//          documentation and/or other materials provided with the distribution.
//
//    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
//    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//    POSSIBILITY OF SUCH DAMAGE.
//
// The lists of keywords, operator, functions, and subroutines have been adopted from
//    vs.language.fortran by Thomas E. Dunn
"use strict";

function definition() {
    return {
        // Fortran is case insensitive, so ignore case...
        ignoreCase: true,

        defaultToken: 'invalid',

        keywords: [
            'abstract',
            'all',
            'allocatable',
            'allocate',
            'assign',
            'assignment',
            'asynchronous',
            'backspace',
            'bind',
            'block',
            'blockdata',
            'character',
            'close',
            'common',
            'complex',
            'concurrent',
            'contiguous',
            'call',
            'case',
            'class',
            'codimension',
            'contains',
            'continue',
            'cycle',
            'data',
            'deallocate',
            'deferred',
            'dimension',
            'do',
            'double',
            'doubleprecision',
            'elemental',
            'else',
            'elsewhere',
            'end',
            'endblock',
            'endblockdata',
            'enddo',
            'endenum',
            'endfile',
            'endforall',
            'endfunction',
            'endif',
            'endinterface',
            'endmodule',
            'endprogram',
            'endselect',
            'endsubmodule',
            'endsubroutine',
            'endtype',
            'endwhere',
            'endwhile',
            'entry',
            'enum',
            'enumerator',
            'equivalence',
            'error',
            'exit',
            'external',
            'final',
            'flush',
            'forall',
            'format',
            'function',
            'generic',
            'go',
            'goto',
            'if',
            'implicit',
            'import',
            'in',
            'include',
            'inout',
            'inquire',
            'intent',
            'interface',
            'intrinsic',
            'is',
            'logical',
            'module',
            'non_overridable',
            'none',
            'nopass',
            'nullify',
            'only',
            'open',
            'operator',
            'optional',
            'out',
            'parameter',
            'pass',
            'pause',
            'pointer',
            'precision',
            'print',
            'private',
            'procedure',
            'program',
            'protected',
            'public',
            'pure',
            'read',
            'real',
            'recursive',
            'result',
            'return',
            'rewind',
            'save',
            'select',
            'sequence',
            'stop',
            'submodule',
            'subroutine',
            'target',
            'then',
            'to',
            'type',
            'use',
            'value',
            'volatile',
            'wait',
            'where',
            'while',
            'write'
        ],

        typeKeywords: [
            'logical',
            'character',
            'real',
            'integer',
            'complex',
            'type',
            'class',
            // add non-type keywords that make sense when combined w/ types
            'intent',
            'dimension',
            'allocatable',
            'parameter',
            'private',
            'public'
        ],

        operators: [
            '=',
            '==',
            '/=',
            '>',
            '>=',
            '<',
            '<=',
            '=>',
            '+',
            '-',
            '*',
            '/',
            '**',
            '//',
            '.and.',
            '.eq.',
            '.eqv.',
            '.le.',
            '.lt.',
            '.ge.',
            '.gt.',
            '.ne.',
            '.neqv.',
            '.not.',
            '.or.'
        ],

        functions: [
            'abs',
            'achar',
            'acos',
            'acosh',
            'adjustl',
            'adjustr',
            'aimag',
            'aint',
            'all',
            'allocated',
            'anint',
            'any',
            'asin',
            'asinh',
            'associated',
            'atan',
            'atan2',
            'atanh',
            'bessel_j0',
            'bessel_j1',
            'bessel_jn',
            'bessel_y0',
            'bessel_y1',
            'bessel_yn',
            'bge',
            'bgt',
            'bit_size',
            'ble',
            'blt',
            'btest',
            'c_associated',
            'c_funloc',
            'c_loc',
            'c_sizeof',
            'ceiling',
            'char',
            'cmplx',
            'command_argument_count',
            'compiler_options',
            'compiler_version',
            'conjg',
            'cos',
            'cosh',
            'count',
            'cshift',
            'dble',
            'digits',
            'dim',
            'dot_product',
            'dprod',
            'dshiftl',
            'dshiftr',
            'eoshift',
            'epsilon',
            'erf',
            'erfc',
            'erfc_scaled',
            'exp',
            'exponent',
            'extends_type_of',
            'findloc',
            'floor',
            'fraction',
            'gamma',
            'huge',
            'hypot',
            'iachar',
            'iall',
            'iand',
            'iany',
            'ibclr',
            'ibits',
            'ibset',
            'ichar',
            'ieee_class',
            'ieee_copy_sign',
            'ieee_is_finite',
            'ieee_is_nan',
            'ieee_is_normal',
            'ieee_logb',
            'ieee_next_after',
            'ieee_rem',
            'ieee_rint',
            'ieee_scalb',
            'ieee_selected_real_kind',
            'ieee_support_datatype',
            'ieee_support_denormal',
            'ieee_support_divide',
            'ieee_support_flag',
            'ieee_support_halting',
            'ieee_support_inf',
            'ieee_support_io',
            'ieee_support_nan',
            'ieee_support_rounding',
            'ieee_support_sqrt',
            'ieee_support_standard',
            'ieee_support_underflow_control',
            'ieee_unordered',
            'ieee_value',
            'ieor',
            'image_index',
            'index',
            'int',
            'ior',
            'iparity',
            'ishft',
            'ishftc',
            'is_contiguous',
            'is_iostat_end',
            'is_iostat_eor',
            'kind',
            'lbound',
            'lcobound',
            'leadz',
            'len',
            'len_trim',
            'lge',
            'lgt',
            'lle',
            'llt',
            'log',
            'log_gamma',
            'log10',
            'logical',
            'maskl',
            'maskr',
            'matmul',
            'max',
            'maxexponent',
            'maxloc',
            'maxval',
            'merge',
            'merge_bits',
            'min',
            'minexponent',
            'minloc',
            'minval',
            'mod',
            'modulo',
            'nearest',
            'new_line',
            'nint',
            'norm2',
            'not',
            'null',
            'num_images',
            'pack',
            'parity',
            'popcnt',
            'poppar',
            'precision',
            'present',
            'product',
            'radix',
            'range',
            'real',
            'repeat',
            'reshape',
            'rrspacing',
            'same_type_as',
            'scale',
            'scan',
            'selected_char_kind',
            'selected_int_kind',
            'selected_real_kind',
            'set_exponent',
            'shape',
            'shifta',
            'shiftl',
            'shiftr',
            'sign',
            'sin',
            'sinh',
            'size',
            'spacing',
            'spread',
            'sqrt',
            'storage_size',
            'sum',
            'tan',
            'tanh',
            'this_image',
            'tiny',
            'trailz',
            'transfer',
            'transpose',
            'trim',
            'ubound',
            'ucobound',
            'unpack',
            'verify'
        ],

        subroutines: [
            'c_f_pointer',
            'c_f_procpointer',
            'cpu_time',
            'date_and_time',
            'execute_command_line',
            'get_command',
            'get_command_argument',
            'get_environment_variable',
            'ieee_get_flag',
            'ieee_get_halting_mode',
            'ieee_get_rounding_mode',
            'ieee_get_status',
            'ieee_get_underflow_mode',
            'ieee_set_flag',
            'ieee_set_halting_mode',
            'ieee_set_rounding_mode',
            'ieee_set_status',
            'ieee_set_underflow_mode',
            'move_alloc',
            'mvbits',
            'random_number',
            'random_seed',
            'system_clock'
        ],

        // we include these common regular expressions
        symbols: /[=><!~?:&|+\-*/^%]+/,
        escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,

        // The main tokenizer for our languages
        tokenizer: {
            root: [
                // identify type declarations (also functions)
                [/[a-zA-Z][\w$]*(?=.*(::|function))/, {
                    cases: {
                        '@typeKeywords': 'type.identifier',
                        '@keywords': 'keyword',
                        '@default': 'identifier'
                    }
                }],
                // identifiers and keywords
                [/[a-zA-Z][\w$]*/, {
                    cases: {
                        '@keywords': 'keyword',
                        '@functions': 'keyword',
                        '@subroutines': 'keyword',
                        '@default': 'identifier'
                    }
                }],

                // comments
                [/!.*$/, 'comment'],

                // whitespace
                {include: '@whitespace'},

                // delimiters and operators
                [/[{}()[\]]/, '@brackets'],
                [/[<>](?!@symbols)/, '@brackets'],
                [/@symbols/, {
                    cases: {
                        '@operators': 'operator',
                        '@default': ''
                    }
                }],

                // numbers
                [/\d*\.\d+([eEdD][-+]?\d+)?/, 'number.float'],
                [/[zZ]['"][0-9a-fA-F]*[0-9a-fA-F]['"]/, 'number.hex'],
                [/[oO]['"][0-7]*[0-7]['"]/, 'number.octal'],
                [/[bB]['"][0-1]*[0-1]['"]/, 'number.binary'],
                [/\d/, 'number'],

                // delimiter: after number because of .\d floats
                [/[;,.]/, 'delimiter'],

                // strings
                [/"([^"\\]|\\.)*$/, 'string.invalid'],  // non-teminated string
                [/"/, 'string', '@string'],

                // characters
                [/'[^\\']'/, 'string'],
                [/(')(@escapes)(')/, ['string', 'string.escape', 'string']],
                [/'/, 'string.invalid']
            ],

            whitespace: [
                [/[ \t\r\n]+/, 'white']
            ],

            comment: [
                [/!/, 'comment']
            ],

            string: [
                [/[^\\"]+/, 'string'],
                [/@escapes/, 'string.escape'],
                [/\\./, 'string.escape.invalid'],
                [/"/, 'string', '@pop']
            ],
        }
    };
}

function configuration() {
    return {
        comments: {
            lineComment: '!',
        },

        brackets: [
            ['(/', '/)'],
            ['[', ']'],
            ['(', ')']
        ],

        autoClosingPairs: [
            {open: '[', close: ']'},
            {open: '(', close: ')'},
            {open: '`', close: '`', notIn: ['string','comment']},
            {open: "'", close: "'", notIn: ['string','comment']},
            {open: '"', close: '"', notIn: ['string']}
        ],

        surroundingPairs: [
            {open: '[', close: ']'},
            {open: '(', close: ')'},
            {open: '`', close: '`'},
            {open: "'", close: "'"},
            {open: '"', close: '"'}
        ],

        indentationRules: {
            decreaseIndentPattern: /(end\s*(do|if|function|subroutine|program|block|associate|forall|select))|else|(^((?!select).)*(case))/,
            increaseIndentPattern: /(^((?!end).)*(do\s|if(\s|\().*then|function\s|subroutine\s|program\s|block\s*|associate(\s|\()|forall|case)|else)/,
            unIndentedLinePattern: null
        }
    };
}

var def = definition();

monaco.languages.register({id: 'fortran'});
monaco.languages.setMonarchTokensProvider('fortran', def);
monaco.languages.setLanguageConfiguration('fortran', configuration());

module.exports = def;
<commit_msg>Update fortran-mode.js<commit_after>//    Copyright (c) 2015, Thomas E. Dunn
//    Copyright (c) 2017, Matt Godbolt
//    Copyright (c) 2018, Forschungzentrum Juelich GmbH
//                        Juelich Supercomputing Centre
//    All rights reserved.
//
//    Redistribution and use in source and binary forms, with or without
//    modification, are permitted provided that the following conditions are met:
//
//        * Redistributions of source code must retain the above copyright notice,
//          this list of conditions and the following disclaimer.
//        * Redistributions in binary form must reproduce the above copyright
//          notice, this list of conditions and the following disclaimer in the
//          documentation and/or other materials provided with the distribution.
//
//    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
//    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//    POSSIBILITY OF SUCH DAMAGE.
//
// The lists of keywords, operator, functions, and subroutines have been adopted from
//    vs.language.fortran by Thomas E. Dunn
"use strict";

function definition() {
    return {
        // Fortran is case insensitive, so ignore case...
        ignoreCase: true,

        defaultToken: 'invalid',

        keywords: [
            'abstract',
            'all',
            'allocatable',
            'allocate',
            'assign',
            'assignment',
            'asynchronous',
            'backspace',
            'bind',
            'block',
            'blockdata',
            'character',
            'close',
            'common',
            'complex',
            'concurrent',
            'contiguous',
            'call',
            'case',
            'class',
            'codimension',
            'contains',
            'continue',
            'cycle',
            'data',
            'deallocate',
            'deferred',
            'dimension',
            'do',
            'double',
            'doubleprecision',
            'elemental',
            'else',
            'elsewhere',
            'end',
            'endblock',
            'endblockdata',
            'enddo',
            'endenum',
            'endfile',
            'endforall',
            'endfunction',
            'endif',
            'endinterface',
            'endmodule',
            'endprogram',
            'endselect',
            'endsubmodule',
            'endsubroutine',
            'endtype',
            'endwhere',
            'endwhile',
            'entry',
            'enum',
            'enumerator',
            'equivalence',
            'error',
            'exit',
            'external',
            'final',
            'flush',
            'forall',
            'format',
            'function',
            'generic',
            'go',
            'goto',
            'if',
            'implicit',
            'import',
            'in',
            'include',
            'inout',
            'inquire',
            'intent',
            'interface',
            'intrinsic',
            'is',
            'logical',
            'module',
            'non_overridable',
            'none',
            'nopass',
            'nullify',
            'only',
            'open',
            'operator',
            'optional',
            'out',
            'parameter',
            'pass',
            'pause',
            'pointer',
            'precision',
            'print',
            'private',
            'procedure',
            'program',
            'protected',
            'public',
            'pure',
            'read',
            'real',
            'recursive',
            'result',
            'return',
            'rewind',
            'save',
            'select',
            'sequence',
            'stop',
            'submodule',
            'subroutine',
            'target',
            'then',
            'to',
            'type',
            'use',
            'value',
            'volatile',
            'wait',
            'where',
            'while',
            'write'
        ],

        typeKeywords: [
            'logical',
            'character',
            'real',
            'integer',
            'complex',
            'type',
            'class',
            // add non-type keywords that make sense when combined w/ types
            'intent',
            'dimension',
            'allocatable',
            'parameter',
            'private',
            'public'
        ],

        operators: [
            '=',
            '==',
            '/=',
            '>',
            '>=',
            '<',
            '<=',
            '=>',
            '+',
            '-',
            '*',
            '/',
            '**',
            '//',
            '.and.',
            '.eq.',
            '.eqv.',
            '.le.',
            '.lt.',
            '.ge.',
            '.gt.',
            '.ne.',
            '.neqv.',
            '.not.',
            '.or.'
        ],

        functions: [
            'abs',
            'achar',
            'acos',
            'acosh',
            'adjustl',
            'adjustr',
            'aimag',
            'aint',
            'all',
            'allocated',
            'anint',
            'any',
            'asin',
            'asinh',
            'associated',
            'atan',
            'atan2',
            'atanh',
            'bessel_j0',
            'bessel_j1',
            'bessel_jn',
            'bessel_y0',
            'bessel_y1',
            'bessel_yn',
            'bge',
            'bgt',
            'bit_size',
            'ble',
            'blt',
            'btest',
            'c_associated',
            'c_funloc',
            'c_loc',
            'c_sizeof',
            'ceiling',
            'char',
            'cmplx',
            'command_argument_count',
            'compiler_options',
            'compiler_version',
            'conjg',
            'cos',
            'cosh',
            'count',
            'cshift',
            'dble',
            'digits',
            'dim',
            'dot_product',
            'dprod',
            'dshiftl',
            'dshiftr',
            'eoshift',
            'epsilon',
            'erf',
            'erfc',
            'erfc_scaled',
            'exp',
            'exponent',
            'extends_type_of',
            'findloc',
            'floor',
            'fraction',
            'gamma',
            'huge',
            'hypot',
            'iachar',
            'iall',
            'iand',
            'iany',
            'ibclr',
            'ibits',
            'ibset',
            'ichar',
            'ieee_class',
            'ieee_copy_sign',
            'ieee_is_finite',
            'ieee_is_nan',
            'ieee_is_normal',
            'ieee_logb',
            'ieee_next_after',
            'ieee_rem',
            'ieee_rint',
            'ieee_scalb',
            'ieee_selected_real_kind',
            'ieee_support_datatype',
            'ieee_support_denormal',
            'ieee_support_divide',
            'ieee_support_flag',
            'ieee_support_halting',
            'ieee_support_inf',
            'ieee_support_io',
            'ieee_support_nan',
            'ieee_support_rounding',
            'ieee_support_sqrt',
            'ieee_support_standard',
            'ieee_support_underflow_control',
            'ieee_unordered',
            'ieee_value',
            'ieor',
            'image_index',
            'index',
            'int',
            'ior',
            'iparity',
            'ishft',
            'ishftc',
            'is_contiguous',
            'is_iostat_end',
            'is_iostat_eor',
            'kind',
            'lbound',
            'lcobound',
            'leadz',
            'len',
            'len_trim',
            'lge',
            'lgt',
            'lle',
            'llt',
            'log',
            'log_gamma',
            'log10',
            'logical',
            'maskl',
            'maskr',
            'matmul',
            'max',
            'maxexponent',
            'maxloc',
            'maxval',
            'merge',
            'merge_bits',
            'min',
            'minexponent',
            'minloc',
            'minval',
            'mod',
            'modulo',
            'nearest',
            'new_line',
            'nint',
            'norm2',
            'not',
            'null',
            'num_images',
            'pack',
            'parity',
            'popcnt',
            'poppar',
            'precision',
            'present',
            'product',
            'radix',
            'range',
            'real',
            'repeat',
            'reshape',
            'rrspacing',
            'same_type_as',
            'scale',
            'scan',
            'selected_char_kind',
            'selected_int_kind',
            'selected_real_kind',
            'set_exponent',
            'shape',
            'shifta',
            'shiftl',
            'shiftr',
            'sign',
            'sin',
            'sinh',
            'size',
            'spacing',
            'spread',
            'sqrt',
            'storage_size',
            'sum',
            'tan',
            'tanh',
            'this_image',
            'tiny',
            'trailz',
            'transfer',
            'transpose',
            'trim',
            'ubound',
            'ucobound',
            'unpack',
            'verify'
        ],

        subroutines: [
            'c_f_pointer',
            'c_f_procpointer',
            'cpu_time',
            'date_and_time',
            'execute_command_line',
            'get_command',
            'get_command_argument',
            'get_environment_variable',
            'ieee_get_flag',
            'ieee_get_halting_mode',
            'ieee_get_rounding_mode',
            'ieee_get_status',
            'ieee_get_underflow_mode',
            'ieee_set_flag',
            'ieee_set_halting_mode',
            'ieee_set_rounding_mode',
            'ieee_set_status',
            'ieee_set_underflow_mode',
            'move_alloc',
            'mvbits',
            'random_number',
            'random_seed',
            'system_clock'
        ],

        // we include these common regular expressions
        symbols: /[=><!~?:&|+\-*/^%]+/,
        escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,

        // The main tokenizer for our languages
        tokenizer: {
            root: [
                // identify type declarations (also functions)
                [/[a-zA-Z][\w$]*(?=.*(::|function))/, {
                    cases: {
                        '@typeKeywords': 'type.identifier',
                        '@keywords': 'keyword',
                        '@default': 'identifier'
                    }
                }],
                // identifiers and keywords
                [/[a-zA-Z][\w$]*/, {
                    cases: {
                        '@keywords': 'keyword',
                        '@functions': 'keyword',
                        '@subroutines': 'keyword',
                        '@default': 'identifier'
                    }
                }],

                // comments
                [/!.*$/, 'comment'],

                // whitespace
                {include: '@whitespace'},

                // delimiters and operators
                [/[{}()[\]]/, '@brackets'],
                [/[<>](?!@symbols)/, '@brackets'],
                [/@symbols/, {
                    cases: {
                        '@operators': 'operator',
                        '@default': ''
                    }
                }],

                // numbers
                [/\d*\.\d+([eEdD][-+]?\d+)?/, 'number.float'],
                [/[zZ]['"][0-9a-fA-F]*[0-9a-fA-F]['"]/, 'number.hex'],
                [/[oO]['"][0-7]*[0-7]['"]/, 'number.octal'],
                [/[bB]['"][0-1]*[0-1]['"]/, 'number.binary'],
                [/\d/, 'number'],

                // delimiter: after number because of .\d floats
                [/[;,.]/, 'delimiter'],

                // strings
                [/"([^"\\]|\\.)*$/, 'string.invalid'],  // non-teminated string
                [/"/, 'string', '@string'],

                // characters
                [/'[^\\']'/, 'string'],
                [/(')(@escapes)(')/, ['string', 'string.escape', 'string']],
                [/'/, 'string.invalid']
            ],

            whitespace: [
                [/[ \t\r\n]+/, 'white']
            ],

            comment: [
                [/!/, 'comment']
            ],

            string: [
                [/[^\\"]+/, 'string'],
                [/@escapes/, 'string.escape'],
                [/\\./, 'string.escape.invalid'],
                [/"/, 'string', '@pop']
            ],
        }
    };
}

function configuration() {
    return {
        comments: {
            lineComment: '!',
        },

        brackets: [
            ['(/', '/)'],
            ['[', ']'],
            ['(', ')']
        ],

        autoClosingPairs: [
            {open: '[', close: ']'},
            {open: '(', close: ')'},
            {open: '`', close: '`', notIn: ['string','comment']},
            {open: "'", close: "'", notIn: ['string','comment']},
            {open: '"', close: '"', notIn: ['string']}
        ],

        surroundingPairs: [
            {open: '[', close: ']'},
            {open: '(', close: ')'},
            {open: '`', close: '`'},
            {open: "'", close: "'"},
            {open: '"', close: '"'}
        ],

        indentationRules: {
            decreaseIndentPattern: /(end\s*(do|if|function|subroutine|program|module|block|associate|forall|select))|else|(^((?!select).)*(case))/,
            increaseIndentPattern: /(^((?!end).)*(do\s|if(\s|\().*then|function\s|subroutine\s|program\s|module\s|block\s*|associate(\s|\()|forall|case)|else)/,
            unIndentedLinePattern: null
        }
    };
}

var def = definition();

monaco.languages.register({id: 'fortran'});
monaco.languages.setMonarchTokensProvider('fortran', def);
monaco.languages.setLanguageConfiguration('fortran', configuration());

module.exports = def;
<|endoftext|>


<commit_before>

import * as firebase from 'firebase';
import * as Config from '/Users/yd/React/Project/Project/Team4of5/src/Team4of5_Service/Config.js';

firebase.initializeApp(Config.firebase_config);

export const create_user = function (user_email, user_pass) {
    return firebase.auth().createUserWithEmailAndPassword(user_email, user_pass);
}

export const sign_in_user = function (user_email, user_pass) {
    return firebase.auth().signInWithEmailAndPassword(user_email, user_pass);
}

// this reset password applies to when the user is signed in, not when the user is logged out
export const resetPwd = function(user_email){
    return firebase.auth().sendPasswordResetEmail(user_email);
}

export const updateUserDisplayName = function(user_display_name, user_uid){
        var thisUserRef = firebase.child(user_uid);
              thisUserRef.update({
              display_name: user_display_name,
              last_login_dtm: Date.now(),
        })
}

    // .then(function (user) {
    //     // user signed in
    //     return null;
    // }).catch(function (error) {
    //     console.log(error);
    //     //var errorCode = error.code;
    //     //var errorMessage = error.message;
    //     console.log(error.message);
    //     return error.message;
    // });

    // firebase.auth().onAuthStateChanged(function (user) {
    //     if (user) {
    //         console.log("user " + user.uid + " logged in");
    //         let user_uid = user.uid;
    //         let thisUserRef = firebase.app().database().ref().child('users').child(user_uid);

    //         thisUserRef.update({
    //             display_name: user.displayName,
    //             last_login_dtm: Date.now(),
    //         });
    //         return;
    //     }
    // });
    // return;
<commit_msg>adding more user functions<commit_after>

import * as firebase from 'firebase';
import * as Config from './Config.js';

firebase.initializeApp(Config.firebase_config);

export const create_user = function (user_email, user_pass) {
    return firebase.auth().createUserWithEmailAndPassword(user_email, user_pass);
}

export const sign_in_user = function (user_email, user_pass) {
    return firebase.auth().signInWithEmailAndPassword(user_email, user_pass);
}

// this is reset password
//it shouldn't need any parameters if the user is logged in
export const resetPwd = function(user_email){
    return firebase.auth().sendPasswordResetEmail(user_email);
}

// this allows a user to update their display name in the settings tab
export const updateUserDisplayName = function(user_display_name, user_uid){
        var thisUserRef = firebase.child(user_uid);
              thisUserRef.update({
              display_name: user_display_name,
              last_login_dtm: Date.now(),
        });
}

// this allows a user to update their role in the settings tab
export const updateRole = function(user_role, user_uid){
        var thisUserRef = firebase.child(user_uid);
              thisUserRef.update({
              role: user_role,
              last_login_dtm: Date.now(),
        });
}

// this allows a user to logout
// it shouldn't need any parameters if the user is logged in
export const logoutUser = function(){
    return firebase.auth().signOut();
}

    // .then(function (user) {
    //     // user signed in
    //     return null;
    // }).catch(function (error) {
    //     console.log(error);
    //     //var errorCode = error.code;
    //     //var errorMessage = error.message;
    //     console.log(error.message);
    //     return error.message;
    // });

    // firebase.auth().onAuthStateChanged(function (user) {
    //     if (user) {
    //         console.log("user " + user.uid + " logged in");
    //         let user_uid = user.uid;
    //         let thisUserRef = firebase.app().database().ref().child('users').child(user_uid);

    //         thisUserRef.update({
    //             display_name: user.displayName,
    //             last_login_dtm: Date.now(),
    //         });
    //         return;
    //     }
    // });
    // return;
<|endoftext|>


<commit_before>angular.module('cesium.es.notification.services', ['cesium.services', 'cesium.es.http.services'])
.config(function(PluginServiceProvider, csConfig) {
    'ngInject';

    var enable = csConfig.plugins && csConfig.plugins.es;
    if (enable) {
      // Will force to load this service
      PluginServiceProvider.registerEagerLoadingService('esNotification');
    }

  })

.factory('esNotification', function($rootScope, $q, $timeout, esHttp, csConfig, csSettings, csWallet, csWot, UIUtils, BMA, CryptoUtils, Device, Api, esUser) {
  'ngInject';

  var
    constants = {
      MESSAGE_CODES: ['MESSAGE_RECEIVED'],
      INVITATION_CODES: ['INVITATION_TO_CERTIFY'],
      DEFAULT_LOAD_SIZE: 20
    },

    fields = {
      commons: ["type", "code", "params", "reference", "recipient", "time", "hash", "read_signature"]
    },
    that = this,
    listeners,
    api = new Api(this, 'esNotification')
  ;

  constants.EXCLUDED_CODES = constants.MESSAGE_CODES.concat(constants.INVITATION_CODES);

  that.raw = {
    postCount: esHttp.post('/user/event/_count'),
    postSearch: esHttp.post('/user/event/_search'),
    postReadById: esHttp.post('/user/event/:id/_read'),
    ws: {
      getUserEvent: esHttp.ws('/ws/event/user/:pubkey/:locale'),
      getChanges: esHttp.ws('/ws/_changes')
    }
  };

  // Create the filter query
  function createFilterQuery(pubkey, options) {
    options = options || {};
    options.codes = options.codes || {};
    options.codes.excludes = options.codes.excludes || constants.EXCLUDED_CODES;
    var query = {
      bool: {
        must: [
          {term: {recipient: pubkey}}
        ]
      }
    };

    // Includes codes
    if (options.codes && options.codes.includes) {
      query.bool.must.push({terms: { code: options.codes.includes}});
    }
    else {
      // Excludes codes
      var excludesCodes = [];
      if (!csSettings.getByPath('plugins.es.notifications.txSent', false)) {
        excludesCodes.push('TX_SENT');
      }
      if (!csSettings.getByPath('plugins.es.notifications.txReceived', true)) {
        excludesCodes.push('TX_RECEIVED');
      }
      if (!csSettings.getByPath('plugins.es.notifications.certSent', false)) {
        excludesCodes.push('CERT_SENT');
      }
      if (!csSettings.getByPath('plugins.es.notifications.certReceived', true)) {
        excludesCodes.push('CERT_RECEIVED');
      }
      if (options.codes.excludes) {
        _.forEach(options.codes.excludes, function(code) {
          excludesCodes.push(code);
        });
      }
      if (excludesCodes.length) {
        query.bool.must_not = {terms: { code: excludesCodes}};
      }
    }

    // Filter on time
    if (options.readTime) {
      query.bool.must.push({range: {time: {gt: options.readTime}}});
    }
    return query;
  }

  // Load unread notifications count
  function loadUnreadNotificationsCount(pubkey, options) {
    var request = {
      query: createFilterQuery(pubkey, options)
    };
    // Filter unread only
    request.query.bool.must.push({missing: { field : "read_signature" }});
    return that.raw.postCount(request)
      .then(function(res) {
        return res.count;
      });
  }

  // Load user notifications
  function loadNotifications(pubkey, options) {
    options = options || {};
    options.from = options.from || 0;
    options.size = options.size || constants.DEFAULT_LOAD_SIZE;
    var request = {
      query: createFilterQuery(pubkey, options),
      sort : [
        { "time" : {"order" : "desc"}}
      ],
      from: options.from,
      size: options.size,
      _source: fields.commons
    };

    return that.raw.postSearch(request)
      .then(function(res) {
        if (!res.hits || !res.hits.total) return [];
        var notifications = res.hits.hits.reduce(function(res, hit) {
          var item = new Notification(hit._source, markNotificationAsRead);
          item.id = hit._id;
          return res.concat(item);
        }, []);

        return esUser.profile.fillAvatars(notifications);
      });
  }

  function onNewUserEvent(event) {
    if (!event || !csWallet.isLogin()) return;

    // If notification is an invitation
    if (_.contains(constants.INVITATION_CODES, event.code)) {
      api.event.raise.newInvitation(event);
      return;
    }

    // If notification is a message
    if (_.contains(constants.MESSAGE_CODES, event.code)) {
      api.event.raise.newMessage(event);
      return;
    }

    var notification = new Notification(event, markNotificationAsRead);

    // Extend the notification entity
    return csWot.extendAll([notification])
      .then(function() {
        if (!$rootScope.$$phase) {
          $rootScope.$apply(function() {
            addNewNotification(notification);
          });
        }
        else {
          addNewNotification(notification);
        }
      });
  }

  function addNewNotification(notification) {
    csWallet.data.notifications = csWallet.data.notifications || {};
    csWallet.data.notifications.unreadCount++;
    api.data.raise.new(notification);
  }

  // Mark a notification as read
  function markNotificationAsRead(notification) {
    if (notification.read) return; // avoid multi call
    notification.read = true;
    CryptoUtils.sign(notification.hash, csWallet.data.keypair)
      .then(function(signature){
        return that.raw.postReadById(signature, {id:notification.id});
      })
      .catch(function(err) {
        console.error('[ES] [notification] Error while trying to mark event as read.', err);
      });
  }

  function onWalletReset(data) {
    data.notifications = data.notifications || {};
    data.notifications.unreadCount = null;
    // Stop listening notification
    that.raw.ws.getUserEvent().close();
  }

  function onWalletLogin(data, deferred) {
    deferred = deferred || $q.defer();
    if (!data || !data.pubkey || !data.keypair) {
      deferred.resolve();
      return deferred.promise;
    }

    console.debug('[ES] [notification] Loading count...');
    var now = new Date().getTime();

    // Load unread notifications count
    loadUnreadNotificationsCount(
        data.pubkey, {
          readTime: csSettings.data.wallet ? csSettings.data.wallet.notificationReadTime : 0,
          excludeCodes: constants.EXCLUDED_CODES
        })
      .then(function(unreadCount) {
        data.notifications = data.notifications || {};
        data.notifications.unreadCount = unreadCount;
        console.debug('[ES] [notification] Loaded count (' + unreadCount + ') in '+(new Date().getTime()-now)+'ms');
        deferred.resolve(data);
      })
      .catch(function(err){
        deferred.reject(err);
      })

      // Listen new events
      .then(function(){
        console.debug('[ES] [notification] Starting listen user event...');
        var userEventWs = that.raw.ws.getUserEvent();
        listeners.push(userEventWs.close);
        return userEventWs.on(onNewUserEvent,
            {pubkey: data.pubkey, locale: csSettings.data.locale.id}
          )
          .catch(function(err) {
            console.error('[ES] [notification] Unable to listen user event', err);

            // TODO : send a event to csHttp instead ?
            // And display such connectivity errors in UI
            UIUtils.alert.error('ACCOUNT.ERROR.WS_CONNECTION_FAILED');
          });
      });

    return deferred.promise;
  }

  function addListeners() {
    // Listen some events
    listeners = [
      csWallet.api.data.on.login($rootScope, onWalletLogin, this),
      csWallet.api.data.on.init($rootScope, onWalletReset, this),
      csWallet.api.data.on.reset($rootScope, onWalletReset, this)
    ];
  }

  function removeListeners() {
    _.forEach(listeners, function(remove){
      remove();
    });
    listeners = [];
  }

  function refreshState() {
    var enable = esHttp.alive;
    if (!enable && listeners && listeners.length > 0) {
      console.debug("[ES] [notification] Disable");
      removeListeners();
      if (csWallet.isLogin()) {
        onWalletReset(csWallet.data);
      }
    }
    else if (enable && (!listeners || listeners.length === 0)) {
      console.debug("[ES] [notification] Enable");
      addListeners();
      if (csWallet.isLogin()) {
        return onWalletLogin(csWallet.data);
      }
    }
  }

  // Register extension points
  api.registerEvent('data', 'new');
  api.registerEvent('event', 'newInvitation');
  api.registerEvent('event', 'newMessage');

  // Default actions
  Device.ready().then(function() {
    esHttp.api.node.on.start($rootScope, refreshState, this);
    esHttp.api.node.on.stop($rootScope, refreshState, this);
    return refreshState();
  });

  // Exports
  that.load = loadNotifications;
  that.unreadCount = loadUnreadNotificationsCount;
  that.api = api;
  that.websocket = {
      event: that.raw.ws.getUserEvent,
      change: that.raw.ws.getChanges
    };
  that.constants = constants;

  return that;
})
;
<commit_msg>make sure ntofication.id is always set, before wending read notification<commit_after>angular.module('cesium.es.notification.services', ['cesium.services', 'cesium.es.http.services'])
.config(function(PluginServiceProvider, csConfig) {
    'ngInject';

    var enable = csConfig.plugins && csConfig.plugins.es;
    if (enable) {
      // Will force to load this service
      PluginServiceProvider.registerEagerLoadingService('esNotification');
    }

  })

.factory('esNotification', function($rootScope, $q, $timeout, esHttp, csConfig, csSettings, csWallet, csWot, UIUtils, BMA, CryptoUtils, Device, Api, esUser) {
  'ngInject';

  var
    constants = {
      MESSAGE_CODES: ['MESSAGE_RECEIVED'],
      INVITATION_CODES: ['INVITATION_TO_CERTIFY'],
      DEFAULT_LOAD_SIZE: 20
    },

    fields = {
      commons: ["type", "code", "params", "reference", "recipient", "time", "hash", "read_signature"]
    },
    that = this,
    listeners,
    api = new Api(this, 'esNotification')
  ;

  constants.EXCLUDED_CODES = constants.MESSAGE_CODES.concat(constants.INVITATION_CODES);

  that.raw = {
    postCount: esHttp.post('/user/event/_count'),
    postSearch: esHttp.post('/user/event/_search'),
    postReadById: esHttp.post('/user/event/:id/_read'),
    ws: {
      getUserEvent: esHttp.ws('/ws/event/user/:pubkey/:locale'),
      getChanges: esHttp.ws('/ws/_changes')
    }
  };

  // Create the filter query
  function createFilterQuery(pubkey, options) {
    options = options || {};
    options.codes = options.codes || {};
    options.codes.excludes = options.codes.excludes || constants.EXCLUDED_CODES;
    var query = {
      bool: {
        must: [
          {term: {recipient: pubkey}}
        ]
      }
    };

    // Includes codes
    if (options.codes && options.codes.includes) {
      query.bool.must.push({terms: { code: options.codes.includes}});
    }
    else {
      // Excludes codes
      var excludesCodes = [];
      if (!csSettings.getByPath('plugins.es.notifications.txSent', false)) {
        excludesCodes.push('TX_SENT');
      }
      if (!csSettings.getByPath('plugins.es.notifications.txReceived', true)) {
        excludesCodes.push('TX_RECEIVED');
      }
      if (!csSettings.getByPath('plugins.es.notifications.certSent', false)) {
        excludesCodes.push('CERT_SENT');
      }
      if (!csSettings.getByPath('plugins.es.notifications.certReceived', true)) {
        excludesCodes.push('CERT_RECEIVED');
      }
      if (options.codes.excludes) {
        _.forEach(options.codes.excludes, function(code) {
          excludesCodes.push(code);
        });
      }
      if (excludesCodes.length) {
        query.bool.must_not = {terms: { code: excludesCodes}};
      }
    }

    // Filter on time
    if (options.readTime) {
      query.bool.must.push({range: {time: {gt: options.readTime}}});
    }
    return query;
  }

  // Load unread notifications count
  function loadUnreadNotificationsCount(pubkey, options) {
    var request = {
      query: createFilterQuery(pubkey, options)
    };
    // Filter unread only
    request.query.bool.must.push({missing: { field : "read_signature" }});
    return that.raw.postCount(request)
      .then(function(res) {
        return res.count;
      });
  }

  // Load user notifications
  function loadNotifications(pubkey, options) {
    options = options || {};
    options.from = options.from || 0;
    options.size = options.size || constants.DEFAULT_LOAD_SIZE;
    var request = {
      query: createFilterQuery(pubkey, options),
      sort : [
        { "time" : {"order" : "desc"}}
      ],
      from: options.from,
      size: options.size,
      _source: fields.commons
    };

    return that.raw.postSearch(request)
      .then(function(res) {
        if (!res.hits || !res.hits.total) return [];
        var notifications = res.hits.hits.reduce(function(res, hit) {
          var item = new Notification(hit._source, markNotificationAsRead);
          item.id = hit._id;
          return res.concat(item);
        }, []);

        return esUser.profile.fillAvatars(notifications);
      });
  }

  function onNewUserEvent(event) {
    if (!event || !csWallet.isLogin()) return;

    // If notification is an invitation
    if (_.contains(constants.INVITATION_CODES, event.code)) {
      api.event.raise.newInvitation(event);
      return;
    }

    // If notification is a message
    if (_.contains(constants.MESSAGE_CODES, event.code)) {
      api.event.raise.newMessage(event);
      return;
    }

    var notification = new Notification(event, markNotificationAsRead);

    // Extend the notification entity
    return csWot.extendAll([notification])
      .then(function() {
        if (!$rootScope.$$phase) {
          $rootScope.$apply(function() {
            addNewNotification(notification);
          });
        }
        else {
          addNewNotification(notification);
        }
      });
  }

  function addNewNotification(notification) {
    csWallet.data.notifications = csWallet.data.notifications || {};
    csWallet.data.notifications.unreadCount++;
    api.data.raise.new(notification);
  }

  // Mark a notification as read
  function markNotificationAsRead(notification) {
    if (notification.read || !notification.id) return; // avoid multi call
    // Should never append (fix in Duniter4j issue #12)
    if (!notification.id) {
      console.error('[ES] [notification] Could not mark as read: no \'id\' found!', notification);
      return;
    }
    notification.read = true;
    CryptoUtils.sign(notification.hash, csWallet.data.keypair)
      .then(function(signature){
        return that.raw.postReadById(signature, {id:notification.id});
      })
      .catch(function(err) {
        console.error('[ES] [notification] Error while trying to mark event as read.', err);
      });
  }

  function onWalletReset(data) {
    data.notifications = data.notifications || {};
    data.notifications.unreadCount = null;
    // Stop listening notification
    that.raw.ws.getUserEvent().close();
  }

  function onWalletLogin(data, deferred) {
    deferred = deferred || $q.defer();
    if (!data || !data.pubkey || !data.keypair) {
      deferred.resolve();
      return deferred.promise;
    }

    console.debug('[ES] [notification] Loading count...');
    var now = new Date().getTime();

    // Load unread notifications count
    loadUnreadNotificationsCount(
        data.pubkey, {
          readTime: csSettings.data.wallet ? csSettings.data.wallet.notificationReadTime : 0,
          excludeCodes: constants.EXCLUDED_CODES
        })
      .then(function(unreadCount) {
        data.notifications = data.notifications || {};
        data.notifications.unreadCount = unreadCount;
        console.debug('[ES] [notification] Loaded count (' + unreadCount + ') in '+(new Date().getTime()-now)+'ms');
        deferred.resolve(data);
      })
      .catch(function(err){
        deferred.reject(err);
      })

      // Listen new events
      .then(function(){
        console.debug('[ES] [notification] Starting listen user event...');
        var userEventWs = that.raw.ws.getUserEvent();
        listeners.push(userEventWs.close);
        return userEventWs.on(onNewUserEvent,
            {pubkey: data.pubkey, locale: csSettings.data.locale.id}
          )
          .catch(function(err) {
            console.error('[ES] [notification] Unable to listen user event', err);

            // TODO : send a event to csHttp instead ?
            // And display such connectivity errors in UI
            UIUtils.alert.error('ACCOUNT.ERROR.WS_CONNECTION_FAILED');
          });
      });

    return deferred.promise;
  }

  function addListeners() {
    // Listen some events
    listeners = [
      csWallet.api.data.on.login($rootScope, onWalletLogin, this),
      csWallet.api.data.on.init($rootScope, onWalletReset, this),
      csWallet.api.data.on.reset($rootScope, onWalletReset, this)
    ];
  }

  function removeListeners() {
    _.forEach(listeners, function(remove){
      remove();
    });
    listeners = [];
  }

  function refreshState() {
    var enable = esHttp.alive;
    if (!enable && listeners && listeners.length > 0) {
      console.debug("[ES] [notification] Disable");
      removeListeners();
      if (csWallet.isLogin()) {
        onWalletReset(csWallet.data);
      }
    }
    else if (enable && (!listeners || listeners.length === 0)) {
      console.debug("[ES] [notification] Enable");
      addListeners();
      if (csWallet.isLogin()) {
        return onWalletLogin(csWallet.data);
      }
    }
  }

  // Register extension points
  api.registerEvent('data', 'new');
  api.registerEvent('event', 'newInvitation');
  api.registerEvent('event', 'newMessage');

  // Default actions
  Device.ready().then(function() {
    esHttp.api.node.on.start($rootScope, refreshState, this);
    esHttp.api.node.on.stop($rootScope, refreshState, this);
    return refreshState();
  });

  // Exports
  that.load = loadNotifications;
  that.unreadCount = loadUnreadNotificationsCount;
  that.api = api;
  that.websocket = {
      event: that.raw.ws.getUserEvent,
      change: that.raw.ws.getChanges
    };
  that.constants = constants;

  return that;
})
;
<|endoftext|>