Invision Community 4: SEO, prepare for v5 and dormant account notifications By Matt Monday at 02:04 PM
mat206 Posted December 23, 2010 Posted December 23, 2010 The results I got using Varnish have been nothing short of stellar.. while I'm sure some drawbacks will exist overall I'm extraordinarily pleased with the results. Hopefully a few more people can try this technique and publish their own results to help improve this solution. First of all, mileage may vary on this technique and it can certainly be a part of your overall acceleration strategy. For me, I have a lot of IP.Content stuff as well as a huge amount of bounce traffic from search engines (ie. view one page then leave). For these viewers logging on isn't going to happen.. So to be clear, Varnish is a caching software that I downloaded from http://www.varnish-cache.org/ . It's been used with great success by some extremely large sites on the net and you should be using it too. What it will do in this case is CACHE entire rendered pages in the form that would be viewed by a NON-LOGGED IN user. Once a user chooses to log in, Varnish will pass all requests directly to the web server and all pages will be dynamic. Here's my server specs - Note that they are pretty dismal because I know I can scale hardware vertically pretty easily, they are also very unclear because the server is a VPS server Hardware:1 CPU (1 physical core), 1.7 GB RAM, Linux - Ubuntu Server 9 I'm using PHP 5.2 with eAccelerator, mod_deflate for page compression (gzip turned off in ACP) The images directory is served through images.mydomain.com and MaxCDN is configured with an origin pull to grab images from my site and cache them. Public is served through public.mydomain.com and is configured the same. (Oh, and MaxCDN is running a $49.95 for 1TB bandwidth special, the the 1TB is not monthly.. it lasts for a year.. so go make your site faster with it) See this article I wrote: http://community.invisionpower.com/resources/articles.html/_/server-resource-management/using-maxcdn-as-a-cdn-for-more-performance-with-minimal-effort-r510 Notes: MySQL is running on the same server, but because this is primarily to test the varnish caching capabilities it will not be a major factor in this test. To establish a baseline I ran a stress test software that simulated user traffic on a subset of pages on the site WITHOUT VARNISH INVOLVED (forums and a few pages that contained roughly 8 IP.Content blocks with caching turned on). The test was a ramp-up test.. at 10 simulated users the site was pretty snappy, at 20 simulated users there was a little bit of slow-down. The "top" command revealed Apache CPU usage was pretty high though and the whole site slowed to a crawl at 30 simulated users with 12 second response times. At 40 simulated users the site crapped out. It was disappointing as typical page response times on a test that simulated requests from Stockholm to my Chicago server measured around 4-5 seconds each.. but the server isn't high end and there is plenty of room to scale out by just getting a faster server. AFTER VARNISH, a load test of 250 (!) simultaneous users resulted in an average page request delay of only 2.98 seconds. My server load average was 0.04 in top. Pages were being downloaded at a throughput of 150 Mbps. Unfortunately the stress test software has a limitation of 250 simulated users at the level I'm paying for so I don't know what the upper limit is.
mat206 Posted December 23, 2010 Author Posted December 23, 2010 How to Set Up Varnish I'm not going to get into every little detail but for Ubuntu I just did this from the command line: sudo curl http://repo.varnish-cache.org/debian/GPG-key.txt | apt-key add - sudo echo "deb http://repo.varnish-cache.org/debian/ $(lsb_release -s -c) varnish-2.1" >> /etc/apt/sources.list sudo apt-get update sudo apt-get install varnish apt-get install libapache2-mod-rpaf (because varnish is a proxy, this module will allow you to see the actual client IP in IPS rather than 127.0.0.1) Then I edited /etc/default/varnish and found the uncommented line that started with "DAEMON_OPTS" and changed *:6081 to *:80 so Varnish would listen on the default HTTP port Then I modified my /etc/apache2/apache2.conf file so that all virtual hosts would run on port 8080 instead of port 80. e.g. Find /etc/apache2/ports.conf and change NameVirtualHost *:80 Listen 80 to NameVirtualHost *:8080 Listen 8080 You may need to modify your individual domain configurations to change the port number to 8080 as well. Restart apache (/etc/init.d/apache restart) Then edit the /etc/varnish/default.vcl file and paste in the following: # #Default backend definition. Set this to point to your content #server. # backend default { .host = "127.0.0.1"; .port = "8080"; } sub vcl_fetch { ## Remove the X-Forwarded-For header if it exists. remove req.http.X-Forwarded-For; ## insert the client IP address as X-Forwarded-For. This is the normal IP address of the user. set req.http.X-Forwarded-For = req.http.rlnclientipaddr; set obj.ttl = 300s; set obj.grace = 30s; ## Deliver the content return(deliver); } ## Deliver sub vcl_deliver { ## We'll be hiding some headers added by Varnish. We want to make sure people are not seeing we're using Varnish. ## Since we're not caching (yet), why bother telling people we use it? remove resp.http.X-Varnish; remove resp.http.Via; remove resp.http.Age; remove resp.http.X-Powered-By; } sub vcl_recv { # If they are or were logged in, let them pass through to the web server if (req.http.cookie && req.http.cookie ~ "member_id") { pass; } else { # Clear out the cookies as if we were an unauthenticated user and hit the cache unset req.http.cookie; set req.grace = 15s; } } sub vcl_hash { if (req.http.cookie && req.http.cookie ~ "member_id") { set req.hash += "auth"; } set req.hash += req.url; hash; }
mat206 Posted December 23, 2010 Author Posted December 23, 2010 I wrote Matt with the hope that he will change one of the core source files.. Here is a change to that will enable page-level varnish cache control: Modify \admin\sources\classes\output\formats\html\htmlOutput.php: if ($this->settings['aux_headers']) { $auxhdr = $this->settings['aux_headers']; if (is_array($auxhdr)) { foreach ($auxhdr as $header => $value) { header ($header . ":" . $value); } } } Full Method: /** * Prints any header information for this output module * * @access public * @return void Prints header() information */ public function printHeader() { //----------------------------------------- // Start GZIP compression //----------------------------------------- if ( $this->settings['disable_gzip'] != 1 ) { $buffer = ""; if ( count( ob_list_handlers() ) ) { $buffer = ob_get_contents(); ob_end_clean(); } if ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) AND strstr( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') ) { @ob_start('ob_gzhandler'); } else { @ob_start(); } print $buffer; } if ( $this->settings['print_headers'] ) { if ( isset( $_SERVER['SERVER_PROTOCOL'] ) AND strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) ) { header("HTTP/1.0 " . $this->_headerCode . ' ' . $this->_headerStatus ); } else { header("HTTP/1.1 " . $this->_headerCode . ' ' . $this->_headerStatus ); } /* Forcing a download? */ if ( $this->_forceDownload ) { header( "Content-type: unknown/unknown" ); header( "Content-Disposition: attachment; filename=\"" . IPSText::alphanumericalClean( $this->registry->output->getTitle() ) . ".html\"" ); } else { header( "Content-type: text/html;charset=" . IPS_DOC_CHAR_SET ); } if ( $this->settings['nocache'] ) { $expires = ( $this->_headerExpire ) ? gmdate( "D, d M Y H:i:s", time() + $this->_headerExpire ) . " GMT" : gmdate( "D, d M Y H:i:s", time() - 86400 ) . " GMT"; $maxAge = $this->_headerExpire; $nocache = ( ! $this->_headerExpire ) ? 'no-cache,' : ''; header( "Cache-Control: ". $nocache . "must-revalidate, max-age=" . $maxAge ); header( "Expires: " . $expires ); if ( ! $this->_headerExpire ) { header( "Pragma: no-cache" ); } } // ============================== NEW CODE ====================================== if ($this->settings['aux_headers']) { $auxhdr = $this->settings['aux_headers']; if (is_array($auxhdr)) { foreach ($auxhdr as $header => $value) { header ($header . ":" . $value); } } } // ============================== END NEW CODE ====================================== } }
mat206 Posted December 23, 2010 Author Posted December 23, 2010 How the above code might be used. Add this to any template, database display template, etc. // Instruct Varnish to cache this page-level content for 600 seconds for non-logged in users <php>$this->settings['aux_headers'] = Array("Varnish-Control" => "600");</php> Then save this as your default.vcl varnish configuration and restart varnish: #Default backend definition. Set this to point to your content #server. # backend default { .host = "127.0.0.1"; .port = "8080"; } sub vcl_fetch { ## Remove the X-Forwarded-For header if it exists. remove req.http.X-Forwarded-For; unset obj.http.Server; set obj.http.Server = "IPS"; ## insert the client IP address as X-Forwarded-For. This is the normal IP address of the user. set req.http.X-Forwarded-For = req.http.rlnclientipaddr; if (obj.http.Varnish-Control) { C{ char *ttl; ttl = VRT_GetHdr(sp, HDR_OBJ, "\020Varnish-Control:"); VRT_l_obj_ttl(sp, atoi(ttl)); }C remove obj.http.Varnish-Control; } set obj.ttl = 300s; set obj.grace = 30s; ## Deliver the content return(deliver); } ## Deliver sub vcl_deliver { ## We'll be hiding some headers added by Varnish. We want to make sure people are not seeing we're using Varnish. ## Since we're not caching (yet), why bother telling people we use it? remove resp.http.X-Varnish; remove resp.http.Via; remove resp.http.Age; ## We'd like to hide the X-Powered-By headers. Nobody has to know we can run PHP and have version xyz of it. remove resp.http.X-Powered-By; } sub vcl_recv { if (req.http.cookie && req.http.cookie ~ "member_id") { pass; } else { unset req.http.cookie; set req.grace = 15s; } } sub vcl_hash { if (req.http.cookie && req.http.cookie ~ "member_id") { set req.hash += "auth"; } set req.hash += req.url; hash; }
cthree Posted December 23, 2010 Posted December 23, 2010 Am I looking at proprietary source code posted in a public forum?
mat206 Posted December 23, 2010 Author Posted December 23, 2010 Am I looking at proprietary source code posted in a public forum? This forum is only available to those logged in with a customer account and at least it was a public method (small joke). But yeah, you can't read that post without already having access to the source code. PM me or hit the moderator report button if you have issues in the future as I don't want to go off topic on this thread.
mat206 Posted December 25, 2010 Author Posted December 25, 2010 Here is an updated default.vcl, I noticed a problem with the IPS software setting a cookie to member_id=0 for guests automatically.. so checking just for member_id wasn't enough of an indicator that the person was logged on. In this case we want to treat guests as not special and they would view content as if they weren't logged in. backend default { .host = "127.0.0.1"; .port = "8080"; } sub vcl_fetch { ## Remove the X-Forwarded-For header if it exists. remove req.http.X-Forwarded-For; unset obj.http.Server; set obj.http.Server = "IPS"; ## insert the client IP address as X-Forwarded-For. This is the normal IP address of the user. set req.http.X-Forwarded-For = req.http.rlnclientipaddr; if (obj.http.Varnish-Control) { C{ char *ttl; ttl = VRT_GetHdr(sp, HDR_OBJ, "\020Varnish-Control:"); VRT_l_obj_ttl(sp, atoi(ttl)); }C remove obj.http.Varnish-Control; } else { set obj.ttl = 300s; } set obj.grace = 30s; ## Deliver the content return(deliver); } ## Deliver sub vcl_deliver { ## We'll be hiding some headers added by Varnish. We want to make sure people are not seeing we're using Varnish. ## Since we're not caching (yet), why bother telling people we use it? remove resp.http.X-Varnish; remove resp.http.Via; remove resp.http.Age; ## We'd like to hide the X-Powered-By headers. Nobody has to know we can run PHP and have version xyz of it. remove resp.http.X-Powered-By; if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } sub vcl_recv { if (req.http.cookie && (req.http.cookie ~ "member_id" && !(req.http.cookie ~ "member_id=0"))) { pass; } else { unset req.http.cookie; set req.grace = 15s; } } sub vcl_hash { if (req.http.cookie && req.http.cookie ~ "member_id") { set req.hash += "auth"; } set req.hash += req.url; hash; }
Fishfish0001 Posted December 25, 2010 Posted December 25, 2010 Nice tutorial. Ill be sure to bookmark it.
.Peter Posted December 25, 2010 Posted December 25, 2010 Agreed.. If I ever go anything bigger than a vps I'll be sure to check out Varnish. Right now all I have are two VPS's and several shared but the VPS's are so unreliable due to a horrible host that I don't have anything important on them so I'm not in a huge need for Varnish.. but with the goals I have in mind for my site I"m thinking Varnish could be the way to go. Thanks Mat.
.Nuno. Posted December 25, 2010 Posted December 25, 2010 Hello, Thanks for this tutorial. Do you know if there is a way for topics view counter work?
Ambar Posted December 25, 2010 Posted December 25, 2010 Very cool, out of my league to even try ! But very cool :)
Zhana Posted December 25, 2010 Posted December 25, 2010 Cool, I asked about varnish cache a few days ago.
mat206 Posted December 26, 2010 Author Posted December 26, 2010 I know this is getting a little crazy here, but I'm in the process of trying a few things. One thing I want to attempt is to work out the ability to do Varnish caching using ESI for IP.Content pages where you use parse database tags. Otherwise, I'm trying to figure out a good way to do subpage caching using varnish. This may be possible.. and if so it may greatly accelerate the site. I feel like in order to truly scale this software more, a second MySQL driver with read/write splitting should be created, that full page caching should be written into IP.Content for database parsed pages.. there is a lot with this software that is in no way customized to the user, but it's impossible for IPS to know what parts of the site you are going to customize to the end user. To that end it would be pretty awesome do be able to see things like <esi:include src="/forums/index"/> embedded in the page and have varnish maintain a cache of the forum index even for logged in users. Although I don't know how truly practical this is. However, this would allow you to accelerate this software to potentially accommodate a thousand simultaneous users without breaking a sweat (at least that would be nice). Losing some functionality in exchange for performance is always a tradeoff when scaling. THIS NEW VCL configuration will cache static content regardless of whether the user is logged in (js, css, jpg, gif, png files) #Default backend definition. Set this to point to your content #server. # backend default { .host = "127.0.0.1"; .port = "8080"; } sub vcl_fetch { ## Remove the X-Forwarded-For header if it exists. remove req.http.X-Forwarded-For; unset obj.http.Server; set obj.http.Server = "IPS"; ## insert the client IP address as X-Forwarded-For. This is the normal IP address of the user. set req.http.X-Forwarded-For = req.http.rlnclientipaddr; if (obj.http.Varnish-Control) { C{ char *ttl; ttl = VRT_GetHdr(sp, HDR_OBJ, "\020Varnish-Control:"); VRT_l_obj_ttl(sp, atoi(ttl)); }C remove obj.http.Varnish-Control; } else { set obj.ttl = 300s; } set obj.grace = 30s; if (req.url ~ "\.(png|gif|jpg|swf|css|js)$") { unset obj.http.set-cookie; } ## Deliver the content return(deliver); } ## Deliver sub vcl_deliver { ## We'll be hiding some headers added by Varnish. We want to make sure people are not seeing we're using Varnish. ## Since we're not caching (yet), why bother telling people we use it? remove resp.http.X-Varnish; remove resp.http.Via; remove resp.http.Age; ## We'd like to hide the X-Powered-By headers. Nobody has to know we can run PHP and have version xyz of it. remove resp.http.X-Powered-By; if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } set resp.http.X-Rick-Would-Never = "Let you down"; # You can probably remove this ;) } sub vcl_recv { if (req.http.cookie && (req.http.cookie ~ "member_id" && !(req.http.cookie ~ "member_id=0"))) { if (req.url ~ "\.(png|gif|jpg|swf|css|js)$") { lookup; } else { pass; } } else { unset req.http.cookie; set req.grace = 15s; } } sub vcl_hash { if (req.http.cookie && req.http.cookie ~ "member_id") { set req.hash += "auth"; } set req.hash += req.url; hash; }
Connor T Posted January 6, 2011 Posted January 6, 2011 kk. I'm giving this a shot tonight. Will be installing, and will post my results. Thanks Mat
mat206 Posted January 6, 2011 Author Posted January 6, 2011 kk. I'm giving this a shot tonight. Will be installing, and will post my results. Thanks Mat Awesome. Looking forward to it.
Alexia Smith Posted January 6, 2011 Posted January 6, 2011 If you want to avoid modifying the IPS code you can control how long Varnish caches within the VCL as well. Here are tests you can use in the VCL to check for a pass condition. req.url ~ "(section=markasread|section=login|register)" You should also include in here any iframe/ESI scripts used for managing Varnish caching. req.http.Cookie ~ "member_id=" && req.http.Cookie !~ "member_id=(0|-1)" We have ran up to 8,000+ concurrent users at one time with Varnish in play on a quad core 2.2ghz machine. We also retain full functionality for logged in and out users by way of a custom script included either in an iframe or ESI, which also handles guest count and topic view counts.
.Nuno. Posted January 6, 2011 Posted January 6, 2011 We also retain full functionality for logged in and out users by way of a custom script included either in an iframe or ESI, which also handles guest count and topic view counts. Hello, That's great to ear, Would you be kind to share your vcl? Thanks
Alexia Smith Posted January 7, 2011 Posted January 7, 2011 Hello, That's great to ear, Would you be kind to share your vcl? Thanks I am not allowed to share scripts developed on company time, sorry! I can say that the example script above is very similar at the base level and would work much better with the checks I provided above.
.Nuno. Posted January 7, 2011 Posted January 7, 2011 Hello, I was looking for a way to use varnish without loosing the counters and you have done it. Thanks ... I understand.
.Nuno. Posted January 22, 2011 Posted January 22, 2011 Hello, Just want to share my custom setup to handle topics and forums for now. This setup uses ESI to update topics views of cached content. I don't have a big board and this is only for playing around, but with this setup I can serve topics in 1/2 time a was serving before, with an hit rate of 50%. A short notice ... my current setup is: nginx -> varnish -> apache2+mod_phpbackend default { .host = "127.0.0.1"; .port = "8080"; } sub vcl_recv { if ((req.http.Cookie ~ "member_id=" && req.http.Cookie !~ "member_id=(0|-1)") || req.http.Cookie ~ "guestSkinChoice=") { return(pass); } else { if (req.url ~ "^/forum" || req.url ~ "^/topic" || req.url ~ "^/public") { unset req.http.cookie; set req.grace = 15s; } } } sub vcl_fetch { if ((req.http.Cookie ~ "member_id=" && req.http.Cookie !~ "member_id=(0|-1)") || req.http.Cookie ~ "guestSkinChoice=") { return(pass); } else { if (req.url ~ "^/public") { unset beresp.http.set-cookie; set beresp.ttl = 3600s; set beresp.grace = 30s; } if (req.url ~ "^/forum") { unset beresp.http.set-cookie; set beresp.ttl = 300s; set beresp.grace = 30s; } if (req.url ~ "^/topic") { esi; unset beresp.http.set-cookie; set beresp.ttl = 600s; set beresp.grace = 30s; } } } sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } php file to update topic views (update_topicviews.php): <? require_once( './conf_global.php' ); $link = mysql_connect($INFO['sql_host'], $INFO['sql_user'], $INFO['sql_pass']); @mysql_select_db($INFO['sql_database'], $link); @mysql_query("INSERT INTO topic_views (views_tid) VALUES ('" . $_GET['tid'] . "')"); mysql_close($link); ?> add this to the beginning of topicViewTemplate: <if test="!$this->memberData['member_id']"> <esi:include src="/update_topicviews.php?tid={$topic['tid']}" /> </if> I would like to have some comments from you.
mat206 Posted January 26, 2011 Author Posted January 26, 2011 Here is my most up-to-date config.. some things to watch out for are if guests can use either a default skin or a mobile skin. For the previous config, this is addressed by just not caching pages if they choose an alternate skin. But I'm not 100% that the skin cookie will be set for mobile browsers by default. We didn't figure this out until stumbling upon a cached mobile version of our home page showing up in our pc browser. We also added custom error pages to handle some errors if we decided to take down apache in /var/www/errors/###.html (where ### is an error code, 503). We also had a problem with varnish actually caching redirects.. so some people who were not logged in would get caught in an infinite redirect for a particular URI because Varnish cached the redirect. backend default { .host = "127.0.0.1"; .port = "8081"; } sub vcl_fetch { // Dont cache 302 redirects and anything else other than what should be cached if (obj.status != 200 && obj.status != 404) { set obj.ttl = 0s; return (deliver); } ## Remove the X-Forwarded-For header if it exists. remove req.http.X-Forwarded-For; unset obj.http.Server; set obj.http.Server = "IPS"; ## insert the client IP address as X-Forwarded-For. This is the normal IP address of the user. set req.http.X-Forwarded-For = req.http.rlnclientipaddr; if (req.url ~ "\.(png|gif|jpg|swf|css|js)$") { unset obj.http.set-cookie; } ## Deliver the content return(deliver); } ## Deliver sub vcl_deliver { ## We'll be hiding some headers added by Varnish. We want to make sure people are not seeing we're using Varnish. ## Since we're not caching (yet), why bother telling people we use it? remove resp.http.X-Varnish; remove resp.http.Via; remove resp.http.Age; ## We'd like to hide the X-Powered-By headers. Nobody has to know we can run PHP and have version xyz of it. remove resp.http.X-Powered-By; if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } sub vcl_recv { set req.http.X-Device = "pc"; if (req.http.User-Agent ~ "iPad" || req.http.User-Agent ~ "iP(hone|od)" || req.http.User-Agent ~ "Android" || req.http.User-Agent ~ "SymbianOS" || req.http.User-Agent ~ "^BlackBerry" || req.http.User-Agent ~ "^SonyEricsson" || req.http.User-Agent ~ "^Nokia" || req.http.User-Agent ~ "^SAMSUNG" || req.http.User-Agent ~ "^LG") { set req.http.X-Device = "mobile"; } if (req.request == "POST") { pass; } if (req.url ~ "(section=markasread|section=login|register)") { pass; } else { if (req.http.cookie && (req.http.cookie ~ "member_id" && req.http.cookie !~ "member_id=(0|-1)")) { if (req.url ~ "\.(png|gif|jpg|swf|css|js)$") { lookup; } else { pass; } } else { unset req.http.cookie; set req.grace = 15s; } } } sub vcl_hash { if (req.http.cookie && req.http.cookie ~ "member_id") { set req.hash += "auth"; } set req.hash += req.url; set req.hash += req.http.X-Device; hash; } sub vcl_error { set obj.http.Content-Type = "text/html; charset=utf-8"; if ( obj.status >= 500 && obj.status <= 505) { C{ #include <stdio.h> #include <string.h> FILE * pFile; char content [100]; char page [10240]; char fname [50]; page[0] = '\0'; sprintf(fname, "/var/www/errors/%d.html", VRT_r_obj_status(sp)); pFile = fopen(fname, "r"); while (fgets(content, 100, pFile)) { strcat(page, content); } fclose(pFile); VRT_synth_page(sp, 0, page, "<!-- XID: ", VRT_r_req_xid(sp), " -->", vrt_magic_string_end); }C } else { synthetic {" <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>"} obj.status " " obj.response {"</title> </head> <body> <h1>Error "} obj.status " " obj.response {"</h1> <p>"} obj.response {"</p> <h3>Guru Meditation:</h3> <p>XID: "} req.xid {"</p> <address> <a href="http://www.varnish-cache.org/">Varnish</a> </address> </body> </html> "}; } return (deliver); }
ASTRAPI Posted January 29, 2011 Posted January 29, 2011 Let's hope that you will fix all problems and give us the best possible from Varnish to use it on Invision :) Thank you
Gary. Posted January 30, 2011 Posted January 30, 2011 Let's hope that you will fix all problems and give us the best possible from Varnish to use it on Invision :) Thank you Your WHM panel based, So why do you not use the WHM plugin which is Globally rather than per account ?http://www.unixy.net/varnish/ Only makes sense. :whistle:
Zhana Posted January 31, 2011 Posted January 31, 2011 Hi Shamil, Can you please shed some light on litespeed + internal caching? Thank you.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.