190. EPMO Open Source Coordination Office Redaction File Detail Report

Produced by Araxis Merge on 10/3/2017 11:15:28 AM Central Daylight Time. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.

190.1 Files compared

# Location File Last Modified
1 ehmp.zip\ehmp\ehmp\product\production\NodeMockServices\mockHdrPubSub mockHdr.js Tue Jan 10 16:20:50 2017 UTC
2 ehmp.zip\ehmp\ehmp\product\production\NodeMockServices\mockHdrPubSub mockHdr.js Mon Oct 2 19:38:58 2017 UTC

190.2 Comparison summary

Description Between
Files 1 and 2
Text Blocks Lines
Unchanged 5 1670
Changed 4 8
Inserted 0 0
Removed 0 0

190.3 Comparison options

Whitespace
Character case Differences in character case are significant
Line endings Differences in line endings (CR and LF characters) are ignored
CR/LF characters Not shown in the comparison detail

190.4 Active regular expressions

No regular expressions were active.

190.5 Comparison detail

  1   'use stric t';
  2  
  3   var yargs  = require( 'yargs');
  4   var expres s = requir e('express ');
  5   var bodyPa rser = req uire('body -parser');
  6   var _ = re quire('und erscore');
  7   var moment  = require ('moment') ;
  8   var fs = r equire('fs ');
  9   var config  = require ('./config ');
  10  
  11   var log =  require('b unyan').cr eateLogger (config.lo gger);
  12  
  13   var port =  config.po rt;
  14  
  15   log.debug( 'mockHdr:  Starting u p...');
  16  
  17   var app =  express();
  18  
  19   var statio nNumbersTo SiteHash =  {};
  20  
  21   var sites  = initiali zeSites();
  22   //Example  of sites s tructure:
  23   /*
  24   sites = {
  25       '84F0' : {
  26           's tationNumb er': 578,
  27           's iteId': '8 4F0',
  28           '_ lastUpdate ': {
  29                prefix:  '3',
  30                moment:  moment().f ormat('YYM MDD'),
  31                hits: 0
  32           },
  33           'd omain': 'R APHAEL.VIS TACORE.US' ,
  34           'l astUpdate' : 0,
  35           'u pdated': m oment().fo rmat('YYYY MMDDHHmmss '),
  36           'w aitingPids ': [],
  37           'p rocessingP ids': [],
  38           'w aitingIcns ': [],
  39           'w aitingPoll Data': [],
  40           'p atientsSub scribed':  {
  41                '1-578-U SVHA': {
  42                    'ide ntifier':  '1-578-USV HA',
  43                    'pid ': '84F0;1 ',
  44                    'dom ainsSynced ': {
  45                         'allergy':  '20150826 121648'
  46                    }
  47                }
  48           }
  49       }
  50   }
  51   */
  52  
  53   var domain s = config .domains | | ['allerg y', 'patie nt'];
  54  
  55   process.on ('exit', f unction()  {
  56       saveAn dExit();
  57   });
  58  
  59   process.on ('SIGINT',  function( ) {
  60       saveAn dExit();
  61   });
  62  
  63   process.on ('SIGQUIT' , function () {
  64       saveAn dExit();
  65   });
  66  
  67   process.on ('SIGTERM' , function () {
  68       saveAn dExit();
  69   });
  70  
  71   app.use(bo dyParser.j son());
  72  
  73   app.get('/ ping', fun ction(req,  res) {
  74       res.se nd('pong') ;
  75   });
  76  
  77   //HDR inte rface
  78   //Subscrib e
  79   app.post(' /repositor ies. URL         /fpds/vpr/ subscribe' , [validat eSubscribe Params, ha ndleSubscr ibe]);
  80   //Poll
  81   app.get('/ repositori es. URL         /fpds/vpr/ patientdat a/:siteId' , [validat ePollParam s, handleP oll]);
  82   //Unsubscr ibe
  83   app.post(' /repositor ies. URL         /fpds/vpr/ cancel', [ validateUn subscribeP arams, han dleUnsubsc ribe]);
  84  
  85   //Not part  of the re al HDR int erface
  86   //Clear al l subscrip tions
  87   app.post(' /repositor ies. URL         /fpds/vpr/ cancel/all ', handleU nsubscribe All);
  88   //Unsolici ted update
  89   app.post(' /update',  [validateU nsolicited Update, ha ndleUnsoli citedUpdat e]);
  90  
  91   app.listen (port);
  92   log.debug( 'mockHdr:  Listening  on port %s ', port);
  93  
  94   function i nitializeS ites() {
  95       var si tes;
  96       log.de bug('Check ing if sav e data fil e exists.. .');
  97       try {
  98           si tes = requ ire(config .saveDataP ath + '/da ta');
  99           if  (sites) {
  100                log.debu g('Success fully load ed subscri ption data .');
  101           }
  102       } catc h (e) {
  103           lo g.debug('C ould not o pen save d ata file.  (Got error : %s) Init ializing d ata...', e );
  104           si tes = requ ire('./ini tializeDat a');
  105  
  106           _. each(sites , function (site) {
  107                site._la stUpdate =  {
  108                    pref ix: '3',
  109                    mome nt: moment ().format( 'YYMMDD'),
  110                    hits : 0
  111                };
  112                site.upd ated = mom ent().form at('YYYYMM DDHHmmss') ;
  113  
  114                site.las tUpdate =  getLastUpd ate(site);
  115           }) ;
  116       }
  117  
  118       _.each (sites, fu nction(sit e) {
  119           st ationNumbe rsToSiteHa sh[site.st ationNumbe r] = site. siteId;
  120       });
  121  
  122       log.de bug('Sites : %s', JSO N.stringif y(sites));
  123       return  sites;
  124   }
  125  
  126   function s aveAndExit () {
  127       try {
  128           fs .writeFile Sync(confi g.saveData Path + '/d ata.json',  JSON.stri ngify(site s));
  129       } catc h (e) {
  130           lo g.debug('E rror: Coul d not save  data. Got : %s', e);
  131       }
  132  
  133       proces s.exit();
  134   }
  135  
  136   function g etLastUpda te(site) {
  137       var la stUpdate =  site._las tUpdate;
  138       return  lastUpdat e.prefix +  lastUpdat e.moment.t oString()  + '-' + la stUpdate.h its;
  139   }
  140  
  141   function v alidateCom monRequest Params(req , res) {
  142       if (!r eq.param(' server'))  { // check ing the se rver param eter
  143           re s.status(4 00).send(' Missing re quired par ameter: \' server\'') ;
  144           re turn false ;
  145       }
  146       if (!r eq.param(' clientName ')) { // c hecking th e clientNa me paramet er
  147           re s.status(4 00).send(' Missing re quired par ameter: \' clientName \'');
  148           re turn false ;
  149       }
  150       if (!r eq.param(' requestId' )) {
  151           re s.status(4 00).send(' Missing re quired par ameter: \' requestId\ '');
  152           re turn false ;
  153       }
  154       if (!r eq.param(' clientRequ estInitiat ionTime'))  {
  155           re s.status(4 00).send(' Missing re quired par ameter: \' clientRequ estInitiat ionTime\'' );
  156           re turn false ;
  157       }
  158       return  true;
  159   }
  160  
  161   function v alidateSub scribePara ms(req, re s, next) {
  162       if (!v alidateCom monRequest Params(req , res)) {
  163           re turn;
  164       }
  165       if (!r eq.param(' resolvedId entifier')  || !verif yResolvedI dentifier( req.param( 'resolvedI dentifier' ))) {
  166           re turn res.s tatus(400) .send('Mis sing patie nt identif ier in for mat DFN-St ationNumbe r-USVHA');
  167       }
  168       if (!r eq.param(' rootJobId' )) {
  169           re turn res.s tatus(400) .send('Mis sing requi red parame ter: \'roo tJobId\'') ;
  170       }
  171       // log ic to hand le the ver sion infor mation
  172       if (ha sVersionIn fo(req)) {
  173           va r jobDomai nId = getJ obDomainId (req);
  174           if  (_.isEmpt y(jobDomai nId)) {
  175                return r es.status( 400).send( 'Missing r equired pa rameter: \ 'jobDomain Id-domain\ '');
  176           }
  177       }
  178       else i f (!req.pa ram('jobId ')) {
  179           re turn res.s tatus(400) .send('Mis sing requi red parame ter: \'job Id\'');
  180       }
  181  
  182       next() ;
  183   }
  184  
  185   // Utility  function  to check i f there is  any domai n job id i nformation
  186   function h asVersionI nfo(req) {
  187       return  req.param ('HMPSVERS ');
  188   }
  189  
  190   // this fu nction wil l look up  for jobDom ainId-<dom ain> param s in req.p arams, bod y, and que ry
  191   function g etJobDomai nId(req) {
  192       var jo bDomainId  = {};
  193       var do mainPrefix  = 'jobDom ainId-';
  194       _.each ([req.para ms, req.bo dy, req.qu ery], func tion(reqPa ram){
  195           _. each(reqPa ram, funct ion(val, k ey){
  196                if (key. substring( 0, domainP refix.leng th) === do mainPrefix ) {
  197                    var  domainName  = key.sub string(dom ainPrefix. length);
  198                    jobD omainId[do mainName]  = val;
  199                }
  200           }) ;
  201       });
  202       return  jobDomain Id;
  203   }
  204  
  205   function v erifyResol vedIdentif ier(resolv edIdentifi er) {
  206       return  /^[0-9]+- [0-9]+-USV HA/.test(r esolvedIde ntifier);
  207   }
  208  
  209   function e xtractStat ionNumberF romResolve dIdentifie r(resolved Identifier ) {
  210       return  resolvedI dentifier. split('-') [1];
  211   }
  212  
  213   function e xtractDfnF romResolve dIdentifie r(resolved Identifier ) {
  214       return  resolvedI dentifier. split('-') [0];
  215   }
  216  
  217   function e xtractSite HashFromPi d(pid) {
  218       return  pid.split (';')[0];
  219   }
  220  
  221   function h andleSubsc ribe(req,  res) {
  222       var pa tientId =  req.param( 'resolvedI dentifier' );
  223       var cl ientName =  req.param ('clientNa me');
  224       log.de bug('mockH dr: subscr ibe patien t %s, clie nt: %s', p atientId,  clientName );
  225  
  226       var st ationNumbe r = extrac tStationNu mberFromRe solvedIden tifier(pat ientId);
  227  
  228       var si teHash = s tationNumb ersToSiteH ash[statio nNumber];
  229  
  230       if(!si teHash){
  231           re turn res.s tatus(404) .send('Sit e with sta tion numbe r ' + stat ionNumber  + ' not fo und. Canno t subscrib e patient  ' + patien tId);
  232       }
  233       var ro otJobId =  req.param( 'rootJobId ');
  234       var jo bId = req. param('job Id') || ge tJobDomain Id(req);
  235       var mo ckResponse  = {};
  236       var si te = sites [siteHash] ;
  237       if (jo bId) {
  238           lo g.debug('m ockHdr: su bscribe pa tient %s,  rootJobId:  %s, jobId : %j', pat ientId, ro otJobId, j obId);
  239  
  240           mo ckResponse  = {
  241                sites: [ subscribeP atientToMo ckSite(req , site, pa tientId, r ootJobId,  jobId)]
  242           };
  243       }
  244       res.js on(mockRes ponse);
  245   }
  246  
  247  
  248   function s ubscribePa tientToMoc kSite(req,  site, ide ntifier, r ootJobId,  jobId) {
  249       var si teId = sit e.siteId;
  250       var lo calId = ex tractDfnFr omResolved Identifier (identifie r);
  251       var pi d = siteId  + ';' + l ocalId;
  252  
  253       if ( / *patientIs AtSite(sit eId) && */  !site.pat ientsSubsc ribed[iden tifier]) {
  254           va r newPatie ntObj = {} ;
  255           ne wPatientOb j.pid = pi d;
  256           ne wPatientOb j.identifi er = ident ifier;
  257           ne wPatientOb j.domainsS ynced = {} ;
  258           ne wPatientOb j.localId  = localId;
  259           ne wPatientOb j.isSubscr ibed = tru e;
  260           ne wPatientOb j.rootJobI d = rootJo bId;
  261           ne wPatientOb j.jobId =  jobId;
  262           si te.patient sSubscribe d[identifi er] = newP atientObj;
  263           si te.waiting Pids.push( newPatient Obj.pid);
  264           si te.waiting Icns.push( identifier );
  265  
  266           lo g.debug('m ockHdr.sub scribePati entToMockS ite: gener ated and s ubscribed  new patien t identifi er %s for  site %s',  identifier , siteId);
  267           re turn const ructMockSu bscribeRes ponse(req,  site, pid );
  268       } else  /*if*/ {
  269           lo g.debug('m ockHdr: su bscribed p atient ide ntifier %s  that exis ts on site  %s.', ide ntifier, s iteId);
  270           if  (!_.conta ins(site.w aitingIcns , identifi er)) {
  271                site.pat ientsSubsc ribed[iden tifier].is Subscribed  = true;
  272                site.pat ientsSubsc ribed[iden tifier].ro otJobId =  rootJobId;
  273                site.pat ientsSubsc ribed[iden tifier].jo bId = jobI d;
  274                site.wai tingPids.p ush(site.p atientsSub scribed[id entifier]. pid);
  275                site.wai tingIcns.p ush(site.p atientsSub scribed[id entifier]. identifier );
  276           }
  277           re turn const ructMockSu bscribeRes ponse(req,  site, sit e.patients Subscribed [identifie r].pid);
  278       }
  279       /*else   {
  280               //Patient  is not at  this site
  281               return {a piVersion:  '1.0', er ror: { mes sage: 'Pat ient not f ound' }};
  282          }*/
  283  
  284       log.de bug('mockH dr.handleS ubscribe:  Patients c urrently s ubscribed  to site %s : %s', sit e.siteId,  _.filter(s ite.patien tsSubscrib ed, functi on(patient ) {
  285           re turn patie nt.isSubsc ribed;
  286       }).map (function( patient) {
  287           re turn patie nt.identif ier;
  288       }));
  289   }
  290  
  291   function c onstructMo ckSubscrib eResponse( req, site,  pid) {
  292       return  {
  293           ap iVersion:  "1.0",
  294           lo cation: "/ hmp/subscr iption/" +  req.param ('server')  + '/patie nt/' + pid ,
  295           wa itingPids:  site.wait ingPids,
  296           pr ocessingPi ds: site.p rocessingP ids,
  297           re mainingObj ects: 0
  298       };
  299   }
  300  
  301   function v alidatePol lParams(re q, res, ne xt) {
  302       if (!v alidateCom monRequest Params(req , res)) {
  303           re turn;
  304       }
  305       if (!r eq.param(' extractSch ema')) {
  306           re turn res.s tatus(400) .send('Mis sing requi red parame ter: \'ext ractSchema \'');
  307       }
  308       if (!r eq.param(' last')) {
  309           re turn res.s tatus(400) .send('Mis sing requi red parame ter: \'las t\'');
  310       }
  311       if (!r eq.param(' max')) {
  312           re turn res.s tatus(400) .send('Mis sing requi red parame ter: \'max \'');
  313       }
  314       if (!r eq.param(' siteId'))  {
  315           re turn res.s tatus(400) .send('Mis sing requi red parame ter: \'sit eId\'');
  316       }
  317  
  318       next() ;
  319   }
  320  
  321   function h andlePoll( req, res)  {
  322       //log. debug('moc kHdr: poll  site with  station n umber %s',  req.param ('siteId') );
  323  
  324       var si teHash = s tationNumb ersToSiteH ash[req.pa ram('siteI d')];
  325  
  326       if (!s iteHash) {
  327           re s.status(4 04).send(' Site with  station nu mber ' + r eq.param(' siteId') +  ' not fou nd.');
  328           re turn;
  329       }
  330  
  331       var mo ckResponse  = {
  332           si tes: [getS yncDataFro mMockSite( sites[site Hash])]
  333       };
  334  
  335       res.js on(mockRes ponse);
  336   }
  337  
  338   function g etSyncData FromMockSi te(site) {
  339       var da taForAllWa itingPids  = [];
  340       _.each (site.wait ingIcns, f unction(id entifier)  {
  341           da taForAllWa itingPids  = dataForA llWaitingP ids.concat (getSyncDa taForPatie nt(site.pa tientsSubs cribed[ide ntifier],  site));
  342       });
  343  
  344       dataFo rAllWaitin gPids = da taForAllWa itingPids. concat(sit e.waitingP ollData);
  345  
  346       site.w aitingIcns  = [];
  347       site.w aitingPids  = [];
  348       site.w aitingPoll Data = [];
  349  
  350       return  {
  351           ap iVersion:  '1.0',
  352           pa rams: {
  353                domain:  site.domai n,
  354                systemId : site.sit eId
  355           },
  356           da ta: {
  357                updated:  site.upda ted,
  358                totalIte ms: dataFo rAllWaitin gPids.leng th,
  359                lastUpda te: site.l astUpdate,
  360                waitingP ids: site. waitingPid s,
  361                processi ngPids: si te.process ingPids,
  362                remainin gObjects:  0,
  363                items: d ataForAllW aitingPids
  364           }
  365       };
  366   }
  367  
  368   function g etSyncData ForPatient (patient,  site) {
  369       var me ssageTriad  = [];
  370       var pa tientData  = [];
  371       var si teId = sit e.siteId;
  372  
  373       var st ampTime =  moment().f ormat('YYY YMMDDHHmms s'); //FUT URETODO: F igure out  whether th is is supp osed to eq ual lastUp dateTime.. .
  374       var me taStamp =  {};
  375  
  376       log.de bug('mockH dr.getSync DataForPat ient: Gene rating syn cStatus ob ject for p atient %s' , patient. pid);
  377       var sy ncStatusOb ject = gen erateSyncS tatusTempl ate(patien t, siteId) ;
  378  
  379       log.de bug('mockH dr.getSync DataForPat ient: Gene rating syn cStart obj ect for pa tient %s',  patient.p id);
  380       var sy ncStartObj ect = {};
  381       if (!_ .isObject( patient.jo bId)) {
  382           me taStamp =  generateMe taStamp(st ampTime, p atient, si teId);
  383           sy ncStartObj ect = gene rateSyncSt artTemplat e(patient,  siteId);
  384  
  385           if  (_.isEmpt y(patient. domainsSyn ced)) {
  386                log.debu g('mockHdr .getSyncDa taForPatie nt: Includ ing demogr aphics obj ect in syn cStart mes sage for p atient %s' , patient. pid);
  387                addDemog raphicData ForSyncSta rt(patient , site, sy ncStartObj ect);
  388           }
  389  
  390           _. each(domai ns, functi on(domain)  {
  391                if (!pat ient.domai nsSynced[d omain] ||  domain ===  'patient' ) {
  392                    log. debug('moc kHdr.getSy ncDataForP atient: Ge tting %s d ata for pa tient %s',  domain, p atient.pid );
  393                    addD omainDataA ndMetaStam p(stampTim e, patient , site, do main, meta Stamp, pat ientData,  syncStatus Object);
  394                }
  395           }) ;
  396  
  397           sy ncStartObj ect.metaSt amp = meta Stamp;
  398           lo g.debug('m ockHdr.get SyncDataFo rPatient:  Compiling  final poll  response  for patien t %s', pat ient.pid);
  399           me ssageTriad .push(sync StartObjec t);
  400       }
  401       else {
  402           _. each(patie nt.jobId,  function(j obId, doma in){
  403                metaStam p = genera teMetaStam p(stampTim e, patient , siteId);
  404                syncStar tObject =  generateSy ncStartTem plate(pati ent, siteI d, jobId);
  405                if (_.is Empty(pati ent.domain sSynced))  {
  406                    log. debug('moc kHdr.getSy ncDataForP atient: In cluding de mographics  object in  syncStart  message f or patient  %s', pati ent.pid);
  407                    addD emographic DataForSyn cStart(pat ient, site , syncStar tObject);
  408                }
  409                if (!pat ient.domai nsSynced[d omain] ||  domain ===  'patient' ) {
  410                    log. debug('moc kHdr.getSy ncDataForP atient: Ge tting %s d ata for pa tient %s',  domain, p atient.pid );
  411                    addD omainDataA ndMetaStam p(stampTim e, patient , site, do main, meta Stamp, pat ientData,  syncStatus Object);
  412                }
  413                syncStar tObject.me taStamp =  metaStamp;
  414                messageT riad.push( syncStartO bject);
  415           }) ;
  416       }
  417  
  418       _.each (patientDa ta, functi on(item) {
  419           me ssageTriad .push(item );
  420       });
  421       messag eTriad.pus h(syncStat usObject);
  422  
  423       return  messageTr iad;
  424   }
  425  
  426   function a ddDemograp hicDataFor SyncStart( patient, s ite, syncS tartObject ) {
  427       var de mographics Template =  require(' ./data/tem plates/pat ient');
  428       var de mographics Data = JSO N.parse(JS ON.stringi fy(demogra phicsTempl ate));
  429       fillIn ObjectData (demograph icsData.ob ject, pati ent, site,  'patient' );
  430       syncSt artObject. object = d emographic sData.obje ct;
  431   }
  432  
  433   function a ddDomainDa taAndMetaS tamp(stamp Time, pati ent, site,  domain, m etaStamp,  patientDat a, syncSta tusObject)  {
  434       var si teId = sit e.siteId;
  435       var do mainTempla te;
  436       try {
  437           do mainTempla te = requi re('./data /templates /' + domai n);
  438       } catc h (e){
  439           //    not nee ded,  not  an error
  440           //  log.info( 'Error get ting data  for domain : %s: erro r: %s , Se nding and  empty meta Stamp indi cating tha t there is  no data f or that do main', dom ain, e);
  441           //  send out  empty doma inStamp
  442           me taStamp.so urceMetaSt amp[siteId ].domainMe taStamp[do main] = ge tDomainMet aStamp(sta mpTime, do main);
  443           pa tient.doma insSynced[ domain] =  stampTime;
  444           re turn;
  445       }
  446  
  447       var do mainData =  JSON.pars e(JSON.str ingify(dom ainTemplat e));
  448       fillIn Collection Data(domai nData, pat ient, site Id);
  449       fillIn ObjectData (domainDat a.object,  patient, s ite, domai n);
  450       domain Data.objec t.stampTim e = domain Data.objec t.lastUpda teTime.toS tring();
  451       var do mainMetaSt amp = getD omainMetaS tamp(stamp Time, doma in, domain Data.objec t);
  452  
  453       metaSt amp.source MetaStamp[ siteId].do mainMetaSt amp[domain ] = domain MetaStamp;
  454       patien tData.push (domainDat a);
  455       patien t.domainsS ynced[doma in] = stam pTime;
  456       syncSt atusObject .object.do mainTotals [domain] =  1;
  457   }
  458  
  459   function f illInColle ctionData( data, pati ent, siteI d) {
  460       if (da ta.pid) {
  461           da ta.pid = p atient.pid ;
  462       }
  463       if (da ta.systemI d) {
  464           da ta.systemI d = siteId ;
  465       }
  466       if (da ta.localId ) {
  467           da ta.localId  = patient .localId;
  468       }
  469   }
  470  
  471   function f illInObjec tData(data , patient,  site, dom ain) {
  472       var pa tientLocal Id = patie nt.localId ;
  473       var si teId = sit e.siteId;
  474  
  475       if (da ta.pid) {
  476           da ta.pid = p atient.pid ;
  477       }
  478       if (da ta.systemI d) {
  479           da ta.systemI d = siteId ;
  480       }
  481  
  482       if (da ta.comment s) {
  483           _. each(data. comments,  function(c omment) {
  484                if (comm ent.entere dByUid) {
  485                    comm ent.entere dByUid = f ixSiteInUi d(comment. enteredByU id, siteId );
  486                }
  487  
  488                if (comm ent.entere dByCode) {
  489                    comm ent.entere dByCode =  fixSiteInU id(comment .enteredBy Code, site Id);
  490                }
  491           }) ;
  492       }
  493  
  494       if (da ta.locatio nUid) {
  495           da ta.locatio nUid = fix SiteInUid( data.locat ionUid, si teId);
  496       }
  497  
  498       if (da ta.facilit yCode) {
  499           da ta.facilit yCode = si te.station Number;
  500       }
  501  
  502       if (da ta.provide rs) {
  503           _. each(data. providers,  function( provider)  {
  504                provider .providerU id = fixSi teInUid(pr ovider.pro viderUid,  siteId);
  505           }) ;
  506       }
  507  
  508       if (da ta.orderUi d) {
  509           da ta.orderUi d = fixSit eAndDfnInU id(data.or derUid, pa tientLocal Id, siteId );
  510       }
  511  
  512       if (da ta.encount erUid) {
  513           da ta.encount erUid = fi xSiteAndDf nInUid(dat a.encounte rUid, pati entLocalId , siteId);
  514       }
  515  
  516       if (da ta.text) {
  517           _. each(data. text, func tion(text)  {
  518                if (text .clinician s) {
  519                    _.ea ch(text.cl inicians,  function(c linician)  {
  520                         clinician. uid = fixS iteInUid(c linician.u id, siteId );
  521                         clinician. summary =  fixSiteInU id(clinici an.summary , siteId);
  522                    });
  523                }
  524                text.sum mary = fix SiteAndDfn InUid(text .summary,  patientLoc alId, site Id);
  525                text.uid  = fixSite AndDfnInUi d(text.uid , patientL ocalId, si teId);
  526           }) ;
  527       }
  528  
  529       if (da ta.clinici ans) {
  530           _. each(data. clinicians , function (clinician ) {
  531                clinicia n.uid = fi xSiteInUid (clinician .uid, site Id);
  532                clinicia n.summary  = fixSiteI nUid(clini cian.summa ry, siteId );
  533           }) ;
  534       }
  535  
  536       if (da ta.documen tDefUid) {
  537           da ta.documen tDefUid =  fixSiteInU id(data.do cumentDefU id, siteId );
  538       }
  539  
  540       if (da ta.locatio nUid) {
  541           da ta.locatio nUid = fix SiteInUid( data.locat ionUid, si teId);
  542       }
  543  
  544       if (da ta.perform erUid) {
  545           da ta.perform erUid = fi xSiteInUid (data.perf ormerUid,  siteId);
  546       }
  547  
  548       if (da ta.provide rUid) {
  549           da ta.provide rUid = fix SiteInUid( data.provi derUid, si teId);
  550       }
  551  
  552       if (da ta.results ) {
  553           _. each(data. results, f unction(re sult) {
  554                result.u id = fixSi teAndDfnIn Uid(result .uid, pati entLocalId , siteId);
  555           }) ;
  556       }
  557  
  558       if (da ta.groupUi d) {
  559           da ta.groupUi d = fixSit eInUid(dat a.groupUid , siteId);
  560       }
  561  
  562       if (da ta.orders)  {
  563           _. each(data. orders, fu nction(ord er) {
  564                order.lo cationUid  = fixSiteI nUid(order .locationU id, siteId );
  565                order.or derUid = f ixSiteAndD fnInUid(or der.orderU id, patien tLocalId,  siteId);
  566                order.ph armacistUi d = fixSit eInUid(ord er.pharmac istUid, si teId);
  567                order.pr oviderUid  = fixSiteI nUid(order .providerU id, siteId );
  568           }) ;
  569       }
  570  
  571       if (da ta.facilit y && domai n === 'pat ient') {
  572           va r facility  = _.find( data.facil ity, funct ion(facili ty) {
  573                return f acility.co de === 451 ;
  574           }) ;
  575  
  576           if  (facility ) {
  577                facility .code = si te.station Number;
  578                facility .localPati entId = pa tientLocal Id;
  579                facility .systemId  = siteId;
  580           }
  581       }
  582  
  583       if (da ta.teamInf o && data. teamInfo.t eam) {
  584           da ta.teamInf o.team.uid  = fixSite InUid(data .teamInfo. team.uid,  siteId);
  585       }
  586  
  587       var lo calId;
  588       if (do main === ' patient')  {
  589           lo calId = pa tientLocal Id;
  590           da ta.localId  = localId ;
  591       } else  {
  592           lo calId = _. last(data. uid.split( ':'));
  593       }
  594  
  595       var ui d = getUid ForPidAndD omain(pati ent.pid, d omain, loc alId);
  596       data.u id = uid;
  597   }
  598  
  599   function f ixSiteInUi d(uid, sit eId) {
  600       return  uid.repla ce(/ABCD/,  siteId);
  601   }
  602  
  603   function f ixSiteAndD fnInUid(ui d, patient LocalId, s iteId) {
  604       return  uid.repla ce(/ABCD:[ 0-9]+/, si teId + ':'  + patient LocalId);
  605   }
  606  
  607   function g etUidForPi dAndDomain (pid, doma in, localI d) {
  608       return  'urn:va:'  + domain  + ':' + pi d.replace( /;/, ':')  + ':' + lo calId;
  609   }
  610  
  611   function v alidateUns ubscribePa rams(req,  res, next)  {
  612       if (!v alidateCom monRequest Params(req , res)) {
  613           re turn;
  614       }
  615       if (!r eq.param(' resolvedId entifier')  || !verif yResolvedI dentifier( req.param( 'resolvedI dentifier' ))) {
  616           re turn res.s tatus(400) .send('Mis sing patie nt identif ier in for mat DFN-St ationNumbe r-USVHA');
  617       }
  618       next() ;
  619   }
  620  
  621   function h andleUnsub scribe(req , res) {
  622       var pa tientId =  req.param( 'resolvedI dentifier' );
  623       log.de bug('mockH dr: unsubs cribe pati ent %s', p atientId);
  624       var si te = sites [stationNu mbersToSit eHash[extr actStation NumberFrom ResolvedId entifier(p atientId)] ];
  625       var mo ckResponse  = {
  626           si tes: [unsu bscribePat ient(site,  patientId )]
  627       };
  628  
  629       res.js on(mockRes ponse);
  630   }
  631  
  632   function u nsubscribe Patient(si te, identi fier) {
  633       log.de bug('mockH dr.unsubsc ribePatien t: unsubsc ribing pat ient with  identifier  %s from s ite %s', i dentifier,  site.site Id);
  634       var pa tient = si te.patient sSubscribe d[identifi er];
  635       if (pa tient) {
  636           pa tient.doma insSynced  = {};
  637           pa tient.isSu bscribed =  false;
  638           si te.waiting Pids = _.w ithout(sit e.waitingP ids, patie nt.pid);
  639           si te.waiting Icns = _.w ithout(sit e.waitingI cns, patie nt.identif ier);
  640           si te.waiting PollData =  _.filter( site.waiti ngPollData , function (item){ret urn item.p id !== pat ient.pid;} );
  641           lo g.debug('m ockHdr.uns ubscribePa tient: Rem aining pat ients at s ite %s: %s ', site.si teId, _.fi lter(site. patientsSu bscribed,  function(p atient) {
  642                return p atient.isS ubscribed;
  643           }) .map(funct ion(patien t) {
  644                return p atient.ide ntifier;
  645           }) );
  646       } else  {
  647           lo g.debug('m ockHdr.uns ubscribePa tient: pat ient with  identifier  %s doesn\ 't exist a t site %s' , identifi er, site);
  648       }
  649       return  {
  650           'a piVersion' : '1.0',
  651           's ucess': tr ue
  652       };
  653   }
  654  
  655   function h andleUnsub scribeAll( req, res)  {
  656       log.de bug('mockH dr: unsubs cribe all  patients f rom all si tes');
  657       _.each (sites, fu nction(sit e) {
  658           _. each(site. patientsSu bscribed,  function(p atient) {
  659                unsubscr ibePatient (site, pat ient.ident ifier);
  660           }) ;
  661       });
  662  
  663       res.se nd('All pa tients uns ubscribed. ');
  664   }
  665  
  666   function v alidateUns olicitedUp date(req,  res, next)  {
  667       var da ta = req.b ody;
  668       if (!d ata) {
  669           re turn res.s tatus(400) .send('Inv alid or em pty JSON d ata reciev ed in POST  message b ody');
  670       } else  if (!data .uid) {
  671           re turn res.s tatus(400) .send('Mis sing uid i n POST mes sage body' );
  672       } else  if(!isVal idUid(data .uid)){
  673           re turn res.s tatus(400) .send('inv alid uid i n POST mes sage body:  ' + data. uid);
  674       }
  675  
  676       var pi d = extrac tPidFromUi d(data.uid );
  677       var si teHash = e xtractSite HashFromPi d(pid);
  678       var si te = sites [siteHash] ;
  679       if (!s ite) {
  680           re turn res.s tatus(400) .send('pid  does not  correspond  to any co nfigured m ock HDR si te');
  681       }
  682  
  683       var pa tientsSubs cribed = s ite.patien tsSubscrib ed;
  684       var re solvedIden tifier = _ .findKey(p atientsSub scribed, f unction(pa tient) {
  685           re turn patie nt.pid ===  pid;
  686       });
  687  
  688       var pa tient = pa tientsSubs cribed[res olvedIdent ifier];
  689  
  690       if (!r esolvedIde ntifier ||  !patient. isSubscrib ed) {
  691           re turn res.s tatus(400) .send('pat ient with  pid ' + pi d + ' has  not been s ubscribed' );
  692       }
  693  
  694       var do main = ext ractDomain FromUid(da ta.uid);
  695       if (!_ .contains( domains, d omain)) {
  696           re turn res.s tatus(400) .send('dom ain ' + do main + ' i s not pres ent in the  list of c onfigured  HDR domain s');
  697       }
  698  
  699       req.si te = site;
  700       req.pa tient = pa tient;
  701       req.da taDomain =  domain;
  702  
  703       next() ;
  704   }
  705  
  706   function e xtractDoma inFromUid( uid) {
  707       var do main = uid .split(':' )[2];
  708       return  domain;
  709   }
  710  
  711   function e xtractPidF romUid(uid ){
  712       var ui dParts = u id.split(' :');
  713       return  uidParts[ 3] + ';' +  uidParts[ 4];
  714   }
  715  
  716   function i sValidUid( uid){
  717       return  /^urn:va: \w*:([0-9] |[A-F]){4} :[0-9]*:[\ s\S]+/.tes t(uid);
  718   }
  719  
  720   function h andleUnsol icitedUpda te(req, re s) {
  721       var da ta = req.b ody;
  722       var ne wLastUpdat eTime = mo ment().for mat('YYYYM MDDHHmmss' );
  723       data.l astUpdateT ime = newL astUpdateT ime;
  724  
  725       var pa tient = re q.patient;
  726       var si teId = req .site.site Id;
  727       var do main = req .dataDomai n;
  728  
  729       var me taStamp =  generateMe taStamp(ne wLastUpdat eTime, pat ient, site Id, domain , data);
  730       var co llectionWr apper = ge tCollectio nWrapper(d omain, pat ient, site Id, 1, 1);
  731       collec tionWrappe r.object =  data;
  732       var sy ncStart =  generateSy ncStartTem plate(pati ent, siteI d);
  733       syncSt art.metaSt amp = meta Stamp;
  734       var sy ncStatus =  generateS yncStatusT emplate(pa tient, sit eId, domai n);
  735  
  736       req.si te.waiting PollData.p ush(syncSt art);
  737       req.si te.waiting PollData.p ush(collec tionWrappe r);
  738       req.si te.waiting PollData.p ush(syncSt atus);
  739  
  740       res.st atus(201). send();
  741   }
  742  
  743   function g etCollecti onWrapper( domain, pa tient, sit eId, seq,  total) {
  744       return  {
  745           co llection:  domain,
  746           pi d: patient .pid,
  747           sy stemId: si teId,
  748           lo calId: pat ient.local Id,
  749           se q: seq,
  750           to tal: total ,
  751           ob ject: {}
  752       };
  753   }
  754  
  755   function g enerateMet aStamp(sta mpTime, pa tient, sit eId, domai n, data) {
  756       var me taStamp =  {
  757           ic n: null,
  758           st ampTime: s tampTime,
  759           so urceMetaSt amp: {}
  760       };
  761  
  762       metaSt amp.source MetaStamp[ siteId] =  getSourceM etaStamp(s tampTime,  patient, d omain, dat a);
  763       return  metaStamp ;
  764   }
  765  
  766   //Variadic  function:  domain an d data are  optional  parameters .
  767   //                     Include t hem when t he sourceM etaStamp i s only for  1 patient  data obje ct, as in  an unsolic ited updat e.
  768   //                     otherwise , domainMe taStamp ne eds to be  filled in  seperately  for each  domain
  769   function g etSourceMe taStamp(st ampTime, p atient, do main, data ) {
  770       var so urceMetaSt amp = {
  771           pi d: patient .pid,
  772           lo calId: pat ient.local Id,
  773           st ampTime: s tampTime,
  774           do mainMetaSt amp: {}
  775       };
  776  
  777       if(dom ain && dat a){
  778           so urceMetaSt amp.domain MetaStamp[ domain] =  getDomainM etaStamp(s tampTime,  domain, da ta);
  779       }
  780  
  781       return  sourceMet aStamp;
  782   }
  783  
  784   function g etDomainMe taStamp(st ampTime, d omain, dat a) {
  785       return  {
  786           do main: doma in,
  787           st ampTime: s tampTime,
  788           ev entMetaSta mp: data ?  getEventM etaStamp(d ata) : {}
  789       };
  790   }
  791  
  792   function g etEventMet aStamp(dat aObject) {
  793       var ev entMetaSta mp = {};
  794       eventM etaStamp[d ataObject. uid] = {
  795           st ampTime: d ataObject. lastUpdate Time.toStr ing()
  796       };
  797       return  eventMeta Stamp;
  798   }
  799  
  800   //Note: th is returns  an incomp lete sync  start obje ct; The 'm etaStamp'  and 'objec t' attribu tes need t o be set s eperately.
  801   function g enerateSyn cStartTemp late(patie nt, siteId , jobId) {
  802       return  {
  803           co llection:  'syncStart ',
  804           pi d: patient .pid,
  805           sy stemId: si teId,
  806           lo calId: pat ient.local Id,
  807           ic n: null,
  808           ro otJobId: p atient.roo tJobId,
  809           jo bId: jobId  || patien t.jobId,
  810           se q: 1,
  811           to tal: 1
  812       };
  813   }
  814  
  815   //Variadic  function:  domain is  an option al paramet er;
  816   //                     include w hen the sy ncStatus i s only int ended for  1 patient  data objec t, as in a n unsolici ted update
  817   //                     otherwise  domainTot als will n eed to be  seperately  filled in  for each  domain
  818   function g enerateSyn cStatusTem plate(pati ent, siteI d, domain)  {
  819       var ob ject = {
  820           do mainTotals : {},
  821           in itialized:  true,
  822           ui d: 'urn:va :syncStatu s:' + pati ent.pid.re place(/;/,  ':') + ': H4680'
  823       };
  824  
  825       if(dom ain){
  826           ob ject.domai nTotals[do main] = 1;
  827       }
  828  
  829       return  {
  830           co llection:  'syncStatu s',
  831           pi d: patient .pid,
  832           sy stemId: si teId,
  833           lo calId: pat ient.local Id,
  834           // icn: patie nt.icn,
  835           se q: 1,
  836           to tal: 1,
  837           ob ject: obje ct
  838       };
  839   }