311. EPMO Open Source Coordination Office Redaction File Detail Report

Produced by Araxis Merge on 12/5/2017 12:06:46 PM Central Standard 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.

311.1 Files compared

# Location File Last Modified
1 IV-eHMP_CIF.zip\IMAG_Source\VISA\Java\ImagingVistaRealm\main\src\java\gov\va\med\imaging\tomcat\vistarealm VistaCertificateRealm.java Mon Dec 4 21:35:12 2017 UTC
2 IV-eHMP_CIF.zip\IMAG_Source\VISA\Java\ImagingVistaRealm\main\src\java\gov\va\med\imaging\tomcat\vistarealm VistaCertificateRealm.java Mon Dec 4 22:03:47 2017 UTC

311.2 Comparison summary

Description Between
Files 1 and 2
Text Blocks Lines
Unchanged 2 1020
Changed 1 2
Inserted 0 0
Removed 0 0

311.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

311.4 Active regular expressions

No regular expressions were active.

311.5 Comparison detail

  1   package go v.va.med.i maging.tom cat.vistar ealm;
  2  
  3   import jav a.lang.man agement.Ma nagementFa ctory;
  4   import jav a.security .Principal ;
  5   import jav a.security .cert.Cert ificateExp iredExcept ion;
  6   import jav a.security .cert.Cert ificateNot YetValidEx ception;
  7   import jav a.security .cert.X509 Certificat e;
  8   import jav a.util.Arr ayList;
  9   import jav a.util.Lis t;
  10  
  11   import jav ax.managem ent.Instan ceAlreadyE xistsExcep tion;
  12   import jav ax.managem ent.Instan ceNotFound Exception;
  13   import jav ax.managem ent.MBeanR egistratio nException ;
  14   import jav ax.managem ent.MBeanS erver;
  15   import jav ax.managem ent.NotCom pliantMBea nException ;
  16   import jav ax.managem ent.Object Instance;
  17   import jav ax.managem ent.Object Name;
  18  
  19   import org .apache.ca talina.Lif ecycleStat e;
  20   import org .apache.ca talina.Cre dentialHan dler;
  21   import org .apache.ca talina.Con tainer;
  22   import org .apache.ca talina.Rea lm;
  23   import org .apache.lo gging.log4 j.LogManag er;
  24   import org .apache.lo gging.log4 j.Logger;
  25   import org .ietf.jgss .GSSContex t;
  26  
  27   /**
  28    * This cl ass implem ents a Tom cat Realm  that accep ts only X. 509 certif icates.
  29    * Otherwi se it is s imilar to  the VistaR ealm in th at the cre ated Princ ipal 
  30    * instanc es are Vis taRealmPri ncipal and  compatibl e with the  Transacti onContext
  31    * mechani sm in VIX.  
  32    *  
  33    * This Re alm will N OT delegat e authenti cation to  its contai ner parent  realm lik e
  34    * VistaRe alm does.
  35    * 
  36    * Portion s of this  code and t he comment s are copi ed verbati m from
  37    * Tomcat/ Catalina s ource.
  38    * 
  39    * A quick  discussio n of Realm  calling s equence in  Tomcat (o r at least  how I
  40    * think t hey work).  -startup-  1.) const ructor() 2 .) setCont ainer() 3. )
  41    * MBeanRe gistration .preRegist er() 4.) M BeanRegist ration.pos tRegister( ) 5.)
  42    * Lifecyc le.start()  6.) backg roundProce ss() runs  periodical ly from he re to
  43    * Lifecyc le.stop()
  44    * 
  45    * -on cli ent call-  1.) findSe curityCons traints()  - determin es if the  web.xml
  46    * file ha s defined  security-c onstraint  elements f or the res ource shou ld return
  47    * an arra y of appli cable cons traints (i n descendi ng order o f specific ity) 2.)
  48    * hasUser DataPermis sion() - t o check th e web.xml  specified  requiremen ts for
  49    * data in tegrity an d security  in transm ission 3.)  authentic ate() - de pending on
  50    * the pre sented cre dentials,  may call o ne of the  four authe nticate me thods if
  51    * the use r exists,  should ret urn a Prin cipal real ization 4. )
  52    * hasReso urcePermis sion() - d etermines  if the aut henticated  user has  permission
  53    * to the  specific r esource na med - on s erver stop  - 1.) Lif ecycle.sto p()
  54    * 
  55    * Initial ization Se quence:
  56    * 
  57    * ======= ========== ========== ========== ========== ========== ========== ======
  58    * server. xml Realm  element ex ample with  just requ ired prope rties spec ified
  59    * <Realm
  60    * classNa me="gov.va .med.imagi ng.tomcat. vistarealm .VistaReal m"
  61    * siteNum ber = "660 "
  62    * siteAbb reviation  = "SLC"
  63    * siteNam e = "Salt  Lake City,  UT"
  64    * />
  65    * 
  66    * ======= ========== ========== ========== ========== ========== ========== ======
  67    * server. xml Realm  element ex ample with  all prope rties spec ified
  68    * <Realm
  69    * classNa me="gov.va .med.imagi ng.tomcat. vistarealm .VistaReal m"
  70    * siteNum ber="660"
  71    * siteAbb reviation= "SLC"
  72    * siteNam e="Salt La ke City, U T"
  73    * usingPr incipalCac he="true"
  74    * princip alCacheLif espan="600 00"
  75    * refresh PrincipalC acheEntryO nUse="true "
  76    * vistaCo nnectDelay Kludge="10 00"
  77    * />
  78    * 
  79    * @author         
BECKEC
  80    * 
  81    */
  82   public cla ss VistaCe rtificateR ealm
  83   extends Ab stractVist aRealmImpl
  84   implements  Realm, or g.apache.c atalina.Li fecycle, A bstractVis taRealm, V istaCertif icateRealm MBean
  85   {
  86           //  Known Rol es are now  defined i n the Vist aRealmRole s Enum in  the
  87           //  VistaReal mClient pr oject.
  88           //  Partially  this was  for a code  cleanup,  and partia lly to mak e them
  89           //  available
  90           //  outside o f the real m itself.
  91  
  92           pr ivate Logg er logger  = LogManag er.getLogg er(this.ge tClass());
  93           
  94           pr ivate Cont ainer pare ntContaine r;
  95           pr ivate Real m parentCo ntainerRea lm;
  96  
  97           /* *
  98            *  
  99            * /
  100           pu blic Vista Certificat eRealm()
  101           {
  102                    logg er.info(Vi staCertifi cateRealm. class.getC anonicalNa me() + " c tor()");
  103           }
  104           
  105           pu blic synch ronized Co ntainer ge tParentCon tainer()
  106           {
  107                    if(p arentConta iner == nu ll)
  108                             parent Container  = getConta iner() ==  null ? nul l : getCon tainer().g etParent() ;
  109                    
  110                    retu rn parentC ontainer;
  111           }
  112           
  113           pu blic synch ronized Re alm getPar entContain erRealm()
  114           {
  115                    if(p arentConta inerRealm  == null)
  116                    {
  117                             Contai ner parent Container  = getParen tContainer ();
  118                             parent ContainerR ealm = par entContain er == null  ? null :  parentCont ainer.getR ealm();
  119                    }
  120                    
  121                    retu rn parentC ontainerRe alm;
  122           }        
  123           
  124  
  125           /*  (non-Java doc)
  126            *  @see gov. va.med.ima ging.tomca t.vistarea lm.Abstrac tVistaReal mImpl#getS iteAbbrevi ation()
  127            * /
  128           @O verride
  129           pu blic Strin g getSiteA bbreviatio n() 
  130           {
  131                    // i f the site  abbreviat ion has no t been set , attempt  to get it  from the p arent Vist aAccessVer ifyRealm 
  132                    if(s uper.getSi teAbbrevia tion() ==  null)
  133                    {
  134                             logger .debug("Re alm site a bbreviatio n is null,  attemptin g to set f rom parent ");
  135                             Realm  parentReal m = getPar entContain erRealm();
  136                             if(par entRealm i nstanceof  gov.va.med .imaging.t omcat.vist arealm.Vis taAccessVe rifyRealm)
  137                             {                                  
  138                                      gov.va.m ed.imaging .tomcat.vi starealm.V istaAccess VerifyReal m accessVe rifyRealm  = (gov.va. med.imagin g.tomcat.v istarealm. VistaAcces sVerifyRea lm)parentR ealm;
  139                                      logger.d ebug("Sett ing site a bbreviatio n from par ent VistaA ccessVerif yRealm to  [" + acces sVerifyRea lm.getSite Abbreviati on() + "]" );
  140                                      this.set SiteAbbrev iation(acc essVerifyR ealm.getSi teAbbrevia tion());
  141                             }
  142                    }
  143                    retu rn super.g etSiteAbbr eviation() ;
  144           }
  145  
  146           /*  (non-Java doc)
  147            *  @see gov. va.med.ima ging.tomca t.vistarea lm.Abstrac tVistaReal mImpl#getS iteName()
  148            * /
  149           @O verride
  150           pu blic Strin g getSiteN ame() 
  151           {
  152                    // i f the site  name has  not been s et, attemp t to get i t from the  parent Vi staAccessV erifyRealm
  153                    if(s uper.getSi teName() = = null)
  154                    {
  155                             logger .debug("Re alm site n ame is nul l, attempt ing to set  from pare nt");
  156                             Realm  parentReal m = getPar entContain erRealm();
  157                             if(par entRealm i nstanceof  gov.va.med .imaging.t omcat.vist arealm.Vis taAccessVe rifyRealm)
  158                             {                                  
  159                                      gov.va.m ed.imaging .tomcat.vi starealm.V istaAccess VerifyReal m accessVe rifyRealm  = (gov.va. med.imagin g.tomcat.v istarealm. VistaAcces sVerifyRea lm)parentR ealm;
  160                                      logger.d ebug("Sett ing site n ame from p arent Vist aAccessVer ifyRealm t o [" + acc essVerifyR ealm.getSi teName() +  "]");
  161                                      this.set SiteName(a ccessVerif yRealm.get SiteName() );
  162                             }
  163                    }
  164                    retu rn super.g etSiteName ();
  165           }
  166  
  167           /*  (non-Java doc)
  168            *  @see gov. va.med.ima ging.tomca t.vistarea lm.Abstrac tVistaReal mImpl#getS iteNumber( )
  169            * /
  170           @O verride
  171           pu blic Strin g getSiteN umber() 
  172           {
  173                    // i f the site  number ha s not been  set, atte mpt to get  it from t he parent  VistaAcces sVerifyRea lm
  174                    if(s uper.getSi teNumber()  == null)
  175                    {
  176                             logger .debug("Re alm site n umber is n ull, attem pting to s et from pa rent");
  177                             Realm  parentReal m = getPar entContain erRealm();
  178                             if(par entRealm i nstanceof  gov.va.med .imaging.t omcat.vist arealm.Vis taAccessVe rifyRealm)
  179                             {                                  
  180                                      gov.va.m ed.imaging .tomcat.vi starealm.V istaAccess VerifyReal m accessVe rifyRealm  = (gov.va. med.imagin g.tomcat.v istarealm. VistaAcces sVerifyRea lm)parentR ealm;
  181                                      logger.d ebug("Sett ing site n umber from  parent Vi staAccessV erifyRealm  to [" + a ccessVerif yRealm.get SiteNumber () + "]");
  182                                      this.set SiteNumber (accessVer ifyRealm.g etSiteNumb er());
  183                             }
  184                    }
  185                    retu rn super.g etSiteNumb er();
  186           }
  187  
  188           /*  (non-Java doc)
  189            *  @see org. apache.cat alina.Real m#isAvaila ble()
  190           */
  191           // @Override
  192           // public boo lean isAva ilable()
  193           // {
  194           //       retu rn false;
  195           // }
  196           
  197           @O verride
  198       protec ted Logger  getLogger ()
  199       {
  200                return l ogger;
  201       }
  202  
  203           
  204           /*  (non-Java doc)
  205            *  @see org. apache.cat alina.Real m#getRoles (java.secu rity.Princ ipal)
  206            * /
  207           // @Override
  208           // public Str ing[] getR oles(Princ ipal princ ipal)
  209           // {
  210           //       retu rn null; / /getParent ContainerR ealm() ==  null ? nul l : getPar entContain erRealm(). getRoles(p rincipal);
  211           // }
  212  
  213           
  214           /*  (non-Java doc)
  215            *  @see org. apache.cat alina.Life cycle#getS tateName()
  216           */
  217           @O verride
  218           pu blic Strin g getState Name()
  219           {
  220                    retu rn null; / /getParent ContainerR ealm() ==  null ? nul l : getPar entContain erRealm(). getStateNa me();
  221           }
  222  
  223           /*  (non-Java doc)
  224            *  @see org. apache.cat alina.Life cycle#getS tate()
  225           */
  226           @O verride
  227           pu blic Lifec ycleState  getState()
  228           {
  229                    retu rn null; / /getParent ContainerR ealm() ==  null ? nul l : getPar entContain erRealm(). getState() ;
  230           }
  231           
  232           /*  (non-Java doc)
  233            *  @see org. apache.Lif ecycle.des troy()
  234           */
  235           @O verride
  236           pu blic void  destroy()
  237           {
  238           }
  239           
  240           /*  (non-Java doc)
  241            *  @see org. apache.Lif ecycle.ini t()
  242           */
  243           @O verride
  244           pu blic void  init()
  245           {
  246           }
  247  
  248           
  249           /* *
  250            *  Is the re alm initia lized (i.e . capable  of authent icating/au thorizing 
  251            *  users).
  252            *  
  253            *  @return
  254            * /
  255           pu blic boole an isIniti alized()
  256           {
  257                    bool ean result  = true;
  258                    Cont ainer cont ainer = th is.getCont ainer();
  259                    Stri ng contain erName = c ontainer = = null ? n ull : cont ainer.getN ame();
  260                    
  261                    if ( getSiteAbb reviation( ) == null)
  262                    {
  263                             logger .warn("Vis taRealm["  + containe rName + "]  - site ab breviation  is not se t and must  be before  authentic ation will  succeed." );
  264                             result  = false;
  265                    }
  266                    if ( getSiteNam e() == nul l)
  267                    {
  268                             logger .warn("Vis taRealm["  + containe rName + "]  - site na me is not  set and mu st be befo re authent ication wi ll succeed .");
  269                             result  = false;
  270                    }
  271                    if ( getSiteNum ber() == n ull)
  272                    {
  273                             logger .warn("Vis taRealm["  + containe rName + "]  - site nu mber is no t set and  must be be fore authe ntication  will succe ed.");
  274                             result  = false;
  275                    }
  276                    
  277                    retu rn result;
  278           }
  279  
  280           /*
  281           /*
  282            *  ========= ========== ========== ========== ========== ========== ========== ========== =======
  283            *  Authentic ation Meth ods
  284            *  ========= ========== ========== ========== ========== ========== ========== ========== =======
  285            * /
  286  
  287           /* *
  288            *  Return th e Principa l associat ed with th e specifie d username  and
  289            *  credentia ls, if the re is one;  otherwise  return <c ode>null</ code>.
  290            *  
  291            *  @param us ername
  292            *              Username  of the Pr incipal to  look up,  A valid Vi staImaging
  293            *              access c ode
  294            *  @param cr edentials
  295            *              Password  or other  credential s to use i n authenti cating thi s
  296            *              username , The veri fy code ma tching the  given acc ess code
  297            * /
  298           pu blic Princ ipal authe nticate(St ring usern ame, Strin g password )
  299           {
  300                    logg er.info("a uthenticat e (" + use rname + ",  password) ");
  301                    retu rn null;
  302           }
  303           
  304           /* *
  305            *  Return th e Principa l associat ed with th e specifie d username  and
  306            *  credentia ls, if the re is one;  otherwise  return <c ode>null</ code>.
  307            *  
  308            *  @param us ername
  309            *              Username  of the Pr incipal to  look up
  310            *  @param cr edentials
  311            *              Password  or other  credential s to use i n authenti cating thi s
  312            *              username
  313            * /
  314           pu blic Princ ipal authe nticate(St ring usern ame, byte[ ] credenti als)
  315           {
  316                    logg er.info("a uthenticat e (" + use rname + ",  byte[])") ;
  317                    retu rn null;
  318           }
  319           
  320           /*  (non-Java doc)
  321            *  @see org. apache.cat alina.Real m#authenti cate(org.i etf.jgss.G SSContext; , java.lan g.String)
  322            * /
  323           pu blic Princ ipal authe nticate(GS SContext g ssContext,  boolean s toreCreds)
  324           {
  325                    retu rn null;
  326           }
  327  
  328           /*  (non-Java doc)
  329            *  @see org. apache.cat alina.Real m#authenti cate(java. lang.Strin g)
  330            * /
  331           pu blic Princ ipal authe nticate(St ring uid)
  332           {
  333                    retu rn null;
  334           }
  335  
  336  
  337           /* *
  338            *  Return th e Principa l associat ed with th e specifie d username , which
  339            *  matches t he digest  calculated  using the  given par ameters us ing the me thod
  340            *  described  in RFC 20 69; otherw ise return  <code>nul l</code>.
  341            *  
  342            *  @param us ername
  343            *              Username  of the Pr incipal to  look up
  344            *  @param di gest
  345            *              Digest w hich has b een submit ted by the  client
  346            *  @param no nce
  347            *              Unique ( or suppose dly unique ) token wh ich has be en used fo r
  348            *              this req uest
  349            *  @param re alm
  350            *              Realm na me
  351            *  @param md 5a2
  352            *              Second M D5 digest  used to ca lculate th e digest :  MD5(Metho d +
  353            *              ":" + ur i)
  354            * /
  355           pu blic Princ ipal authe nticate(St ring usern ame, Strin g clientDi gest, Stri ng nOnce,  String nc,  String cn once, Stri ng qop, St ring realm ,
  356                    Stri ng md5a2)
  357           {
  358                    logg er.info("a uthenticat e (" + use rname + ",  digest)") ;
  359                    retu rn null;
  360           }
  361  
  362           /* *
  363            *  Return th e Principa l associat ed with th e specifie d chain of  X509 clie nt
  364            *  certifica tes. If th ere is non e, return  <code>null </code>.
  365            *  
  366            *  For this  method to  be called  the client  must have  presented  an X509
  367            *  certifica te, which  has been s igned by a  trusted C ertificate  Authority . At
  368            *  this poin t, all we  need to do  is get th e user nam e from the  certifica te
  369            *  and assig n the role .
  370            *  
  371            *  @param ce rts
  372            *              Array of  client ce rtificates , with the  first one  in the ar ray
  373            *              being th e certific ate of the  client it self.
  374            * /
  375           pu blic Princ ipal authe nticate(X5 09Certific ate certs[ ])
  376           {
  377                    logg er.debug(" Authentica ting using  X509 cert ificate.") ;
  378                    Vist aRealmPrin cipal prin cipal = nu ll;
  379                    List <java.secu rity.cert. X509Certif icate> cer tsList = n ew ArrayLi st<java.se curity.cer t.X509Cert ificate>() ;
  380                    bool ean posses sesTrusted Certificat e = false;
  381                    Stri ng name =  null;
  382  
  383                    // c heck all o f the cert ificates,  if one is  valid then  that beco mes the
  384                    // s ource for  the Princi pal inform ation
  385                    for  (X509Certi ficate cer t : certs)
  386                    {
  387                             logger .debug("X5 09Certific ate subjec t '" + cer t.getSubje ctDN().get Name() + " .");
  388                             certsL ist.add(ce rt); // bu ild the li st that wi ll populat e the
  389                             // Pri ncipal
  390                             // we  may not us e this lis t but buil ding it no w
  391                             // avo ids a seco nd iterato r
  392                             try
  393                             {
  394                                      // the v alidity ch eck will t hrow an ex ception if  it is inv alid
  395                                      cert.che ckValidity ();
  396                                      name = ( name == nu ll ? cert. getSubject DN().getNa me() : nam e);
  397                                      possesse sTrustedCe rtificate  = true;
  398                                      logger.d ebug("X509 Certificat e is valid .");
  399                             } 
  400                             catch  (Certifica teExpiredE xception e )
  401                             {
  402                                      logger.w arn("Authe ntication  by certifi cate of "  + cert.get SubjectX50 0Principal ().getName () + " fai led due to  "
  403                                               + e.getMes sage());
  404                             } 
  405                             catch  (Certifica teNotYetVa lidExcepti on e)
  406                             {
  407                                      logger.w arn("Authe ntication  by certifi cate of "  + cert.get SubjectX50 0Principal ().getName () + " fai led due to  "
  408                                               + e.getMes sage());
  409                             }
  410                    }
  411  
  412                    // p ossessesTr ustedCerti ficate wil l be false  unless at  least one  certifica te is vali d
  413                    if ( possessesT rustedCert ificate)
  414                    {
  415                             logger .debug("Us er '" + na me + "' ha s been aut henticated  by X509Ce rtificate. ");
  416                             List<S tring> rol es = new A rrayList<S tring>();
  417                             roles. add(VistaR ealmRoles. PeerVixsRo le.getRole Name());
  418                             princi pal = new  VistaRealm Principal( getRealmNa me(), name , certsLis t, roles,  null);
  419                             princi pal.setPre emptiveAut horization (this);
  420                             VistaR ealmSecuri tyContext. set(princi pal);
  421                    }
  422  
  423                    retu rn princip al;
  424           }
  425           
  426           /*  (non-Java doc)
  427            *  @see org. apache.cat alina.Real m#setCrede ntialHandl er(org.apa che.catali na.Credent ialHandler )
  428           */
  429           @O verride
  430           pu blic void  setCredent ialHandler (Credentia lHandler c redentialH andler)
  431           {
  432                    if ( getParentC ontainerRe alm() != n ull)
  433                             getPar entContain erRealm(). setCredent ialHandler (credentia lHandler);
  434           }
  435           
  436           /*  (non-Java doc)
  437            *  @see org. apache.cat alina.Real m#getCrede ntialHandl er()
  438           */
  439           @O verride
  440           pu blic Crede ntialHandl er getCred entialHand ler()
  441           {
  442                    retu rn getPare ntContaine rRealm() = = null ? n ull : getP arentConta inerRealm( ).getCrede ntialHandl er();
  443           }
  444  
  445  
  446  
  447           /* *
  448           //  ========= ========== ========== ========== ========== ========== ========== ========== =========
  449           //  MBean Reg istration  Stuff
  450           //  ========= ========== ========== ========== ========== ========== ========== ========== =========
  451           /* *
  452            *  Self-regi ster with  the MBeanS erver. Onc e this met hod runs o nce, it wi ll
  453            *  not re-re gister, ju st return  immediatel y.
  454            *  
  455            * /
  456           
  457           /*
  458           pr ivate Obje ctName reg isteredIns tanceName  = null;
  459  
  460           pr otected vo id mBeanRe gistration ()
  461           {
  462                    // i f we're al ready regi stered the n just ret urn
  463                    if ( registered InstanceNa me != null )
  464                             return ;
  465  
  466                    // r egister th e manageme nt interfa ce if the  MBeanServe r exists
  467                    // n ote that t he regions  are creat ed by the  FileSystem Cache, whi ch is
  468                    // r eponsible
  469                    // f or registe ring their  managemen t MBeans
  470                    MBea nServer mb s = Manage mentFactor y.getPlatf ormMBeanSe rver();
  471                    if ( mbs != nul l)
  472                    {
  473                             try
  474                             {
  475                                      ObjectIn stance oi  = mbs.regi sterMBean( this, null );
  476                                      register edInstance Name = oi. getObjectN ame();
  477                             } catc h (Instanc eAlreadyEx istsExcept ion e)
  478                             {
  479                                      logger.e rror(e);
  480                             } catc h (MBeanRe gistration Exception  e)
  481                             {
  482                                      logger.e rror(e);
  483                             } catc h (NotComp liantMBean Exception  e)
  484                             {
  485                                      logger.e rror(e);
  486                             }
  487                    }
  488           }
  489  
  490           pr otected vo id mBeanUn Registrati on()
  491           {
  492                    MBea nServer mb s = Manage mentFactor y.getPlatf ormMBeanSe rver();
  493                    if ( mbs != nul l && regis teredInsta nceName !=  null)
  494                    {
  495                             try
  496                             {
  497                                      mbs.unre gisterMBea n(register edInstance Name);
  498                                      register edInstance Name = nul l;
  499                             } catc h (Instanc eNotFoundE xception x )
  500                             {
  501                                      logger.e rror(x);
  502                             } catc h (MBeanRe gistration Exception  x)
  503                             {
  504                                      logger.e rror(x);
  505                             }
  506                    }
  507           }
  508           */
  509   }
  510  
  511