Elsewhere

Francois Marier: Upgrading Lenovo ThinkPad BIOS under Linux

Planet Debian - Sun, 01/02/2015 - 04:30

The Lenovo support site offers downloadable BIOS updates that can be run either from Windows or from a bootable CD.

Here's how to convert the bootable CD ISO images under Linux in order to update the BIOS from a USB stick.

Checking the BIOS version

Before upgrading your BIOS, you may want to look up which version of the BIOS you are currently running. To do this, install the dmidecode package:

apt-get install dmidecode

then run:

dmidecode

or alternatively, look at the following file:

cat /sys/devices/virtual/dmi/id/bios_version Updating the BIOS using a USB stick

To update without using a bootable CD, install the genisoimage package:

apt-get install genisoimage

then use geteltorito to convert the ISO you got from Lenovo:

geteltorito -o bios.img gluj19us.iso

Insert a USB stick you're willing to erase entirely and then copy the image onto it (replacing sdX with the correct device name, not partition name, for the USB stick):

dd if=bios.img of=/dev/sdX

then restart and boot from the USB stick by pressing Enter, then F12 when you see the Lenovo logo.

Categories: Elsewhere

Drupal Association News: Nominations Open for Drupal Association At Large Director

Planet Drupal - Sun, 01/02/2015 - 01:00

It’s a great time to be part of the Drupal Association. We’ve done some amazing work in the last few years, and we’re in a great position to work with the community to continue to improve and grow fully into our mission. As a Drupal Association At-Large Director, you’d be in the center of the action. The At-large Director position is specifically designed to ensure community representation on the Drupal Association board and we strongly encourage anyone with an interest to nominate themselves today.

Nominate Yourself Today

The Board of Directors of the Drupal Association are responsible for financial oversight and setting the strategic direction of the Drupal Association. New board members will contribute to the strategic direction of the Drupal Association. Board members are advised of, but not responsible for matters related to the day to day operations of the Drupal Association, including program execution, staffing, etc. You can learn more about what’s expected of a board member in this post and presentation.

Directors are expected to contribute around five hours per month and attend three in-person meetings per year (financial assistance is available if required). All board members agree to meet the minimum requirements documented in the board member agreement.

Today we are opening the self-nomination form that allows you to throw your hat in the ring. We're looking to elect one candidate this year to serve a two-year term.

Log in first and...

To nominate yourself, you should be prepared to answer a few questions:

  • About Me: Tell us about yourself! Your background, how you got into Drupal, etc.
  • Motivation: Why are you applying for a board position? What initiatives do you hope to help drive, or what perspectives are you going to try and represent?
  • Experience: What Drupal community contributions have you taken part in (code, camps, etc.)? Do you have experience in financial oversight, developing business strategies, or organization governance?
  • Availability: I am able to travel to three in-person board meetings per year (either self-funded, or with financial sponsorship)
  • IRC Handle
  • Twitter Handle

We will also need to know that you are available for the next step in the process, meet the candidate sessions. We are hosting 2 sessions: 

Session One
  • Tuesday, 24 February 2015 at:
  • 8 AM PST in the US and Canada
  • 11 AM EST in the US and Canada
  • 1 PM in Sao Paulo Brasil
  • 4 PM in London
  • 12 AM Wednesday, 25 February in Beijing
  • 3 AM Wednesday, 25 February Sydney Australia
Session Two
  • Wednesday 25 February 2015 at:
  • 4 PM PST in the US and Canada
  • 7 PM EST in the US and Canada
  • 9 PM in Sao Paulo Brasil
  • 1 AM Thursday, 26 February in London
  • 8 AM Thursday, 26 February in Beijing
  • 10 AM Thursday, 26 February in Sydney Australia
Session Three
  • Thursday 26 February 2015 at:
  • 12:30 PM PST in the US and Canada
  • 3:30 PM EST in the US and Canada
  • 5:30 PM in Sao Paulo Brasil
  • 8:30 AM Friday, 27 February in London
  • 4:30 AM Friday, 27 February in Beijing
  • 7:30 AM Friday, 27 February in Sydney Australia

The nomination form will be open February 1, 2015 through February 20, 2015 at midnight UTC. For a thorough review of the process, please see our announcement blog post.

If you have any questions, please contact Holly Ross, Drupal Association Executive Director.

Flickr photo: Kodak Views

Categories: Elsewhere

Drupal Association News: Nominations Open for Drupal Association At Large Director

Planet Drupal - Sun, 01/02/2015 - 01:00

It’s a great time to be part of the Drupal Association. We’ve done some amazing work in the last few years, and we’re in a great position to work with the community to continue to improve and grow fully into our mission. As a Drupal Association At-Large Director, you’d be in the center of the action. The At-large Director position is specifically designed to ensure community representation on the Drupal Association board and we strongly encourage anyone with an interest to nominate themselves today.

Nominate Yourself Today

The Board of Directors of the Drupal Association are responsible for financial oversight and setting the strategic direction of the Drupal Association. New board members will contribute to the strategic direction of the Drupal Association. Board members are advised of, but not responsible for matters related to the day to day operations of the Drupal Association, including program execution, staffing, etc. You can learn more about what’s expected of a board member in this post and presentation.

Directors are expected to contribute around five hours per month and attend three in-person meetings per year (financial assistance is available if required). All board members agree to meet the minimum requirements documented in the board member agreement.

Today we are opening the self-nomination form that allows you to throw your hat in the ring. We're looking to elect one candidate this year to serve a two-year term.

Log in first and...

To nominate yourself, you should be prepared to answer a few questions:

  • About Me: Tell us about yourself! Your background, how you got into Drupal, etc.
  • Motivation: Why are you applying for a board position? What initiatives do you hope to help drive, or what perspectives are you going to try and represent?
  • Experience: What Drupal community contributions have you taken part in (code, camps, etc.)? Do you have experience in financial oversight, developing business strategies, or organization governance?
  • Availability: I am able to travel to three in-person board meetings per year (either self-funded, or with financial sponsorship)
  • IRC Handle
  • Twitter Handle

We will also need to know that you are available for the next step in the process, meet the candidate sessions. We are hosting 2 sessions: 

Session One
  • Tuesday, 24 February 2015 at:
  • 8 AM PST in the US and Canada
  • 11 AM EST in the US and Canada
  • 1 PM in Sao Paulo Brasil
  • 4 PM in London
  • 12 AM Wednesday, 25 February in Beijing
  • 3 AM Wednesday, 25 February Sydney Australia
Session Two
  • Wednesday 25 February 2015 at:
  • 4 PM PST in the US and Canada
  • 7 PM EST in the US and Canada
  • 9 PM in Sao Paulo Brasil
  • 1 AM Thursday, 26 February in London
  • 8 AM Thursday, 26 February in Beijing
  • 10 AM Thursday, 26 February in Sydney Australia
Session Three
  • Thursday 26 February 2015 at:
  • 12:30 PM PST in the US and Canada
  • 3:30 PM EST in the US and Canada
  • 5:30 PM in Sao Paulo Brasil
  • 8:30 AM Friday, 27 February in London
  • 4:30 AM Friday, 27 February in Beijing
  • 7:30 AM Friday, 27 February in Sydney Australia

The nomination form will be open February 1, 2015 through February 20, 2015 at midnight UTC. For a thorough review of the process, please see our announcement blog post.

If you have any questions, please contact Holly Ross, Drupal Association Executive Director.

Flickr photo: Kodak Views

Categories: Elsewhere

Gizra.com: (Automatic) QA

Planet Drupal - Sat, 31/01/2015 - 23:00

Here is a known fact - it's really easy to break the sites you are building. One wrong line of code, and a page is returning a 503 error.

Here is a known secret - (almost) nobody is doing QA. Since I'm not into arguing about this, I'm willing to soften it a bit to "most companies, don't do proper QA".

The reasons are pretty clear - not enough time and not enough budget. This post isn't going to be about the importance of QA - that point is clear to everybody, but rather give realistic tips and tools that will allow you to start improving the quality of your projects, and actually even save you some time and money.

Continue reading…

Categories: Elsewhere

John Goerzen: Home Automation, part 2: Z-Wave and ISY programming

Planet Debian - Sat, 31/01/2015 - 21:32

In my part 1 post yesterday, I wrote about the start of the home automation project. I mentioned that I was using Insteon switches, and they mostly were working well (I forgot to mention an annoyance: you can dim, but not totally shut off, their LED status light.) Anyhow, the Insteon battery-operated sensors seem to not be as good as their Z-Wave competition.

Setting up Z-Wave

Z-Wave devices get joined to the Z-Wave network in much the same way Bluetooth devices get paired with each other. The first time you use a Z-Wave device, you join it to the controller. The controller assigns it an ID on your network, and both devices discover the best route to communicate with each other.

I discovered that the Z-Wave module on the ISY-994i has particularly poor reception. Combined with the generally short range of battery-operated Z-wave devices, this meant that my sensors didn’t work reliably. As with Insteon, AC-powered Z-wave devices tend to be repeaters, but I didn’t have any AC-powered Z-wave devices. I went looking for Z-wave repeaters, and found some. But then I discovered that a Z-wave relay-based appliance switch was actually $5 cheaper, acted as a repeater, and could be used as a switch down the road if needed. A couple of those solved my communications issues. You join them to the network as usual, but then either re-join the battery-powered sensors (so they see the new route) or do a “network heal” (every device on the network re-learns about its neighbors and routes to the other devices) so they see the new route.

Z-Wave Motion / Occupancy Sensors

If you have been in new buildings, chances are you have seen light switches with built-in occupancy sensors. My doctor’s office has these. They are typically the same size as a regular light switch, but with a passive infrared (PIR) motion sensor used to automatically turn the lights off after a timeout (or even on, when someone walks into the room.) These work fine for small rooms, but if you’ve ever been in a bathroom with a PIR lightswitch that goes off while you’re still in the room, you are aware of their faults for larger rooms!

Most of the time, when you read about “occupancy sensors”, it’s really a PIR sensor, and the term is used interchangeably with “motion detector.” Motion detectors in home automation systems are commonly used for a number of purposes: detecting occuption of rooms for automatic control of lighting or HVAC systems, triggering alerts, or even locking or unlocking doors.

My friend told me he had poor luck with the Insteon PIR sensors, so I tried two different Z-Wave models: the $48 Aeon/Aeotec multi-sensor and the $30 Ecolink PIRZWAVE2-ECO. The Aeon device is clearly the more capable; it can be used indoors or out, and has a lot of options that can be configured by Z-Wave configuration parameters. It also has a ball/socket mount, so it can be easily aimed in different directions. It can draw power from 4 AAA batteries, or a mini USB cable (cable, but not power supply, included). The Aeon multi-sensor also has a temperature, humidity, and illumination (lux) sensor – but, as you’ll see, they have some drawbacks.

The Ecolink device is more basic; it has a few settings that can be altered via jumpers, but none that can be altered via Z-Wave configuration commands. That makes it a bit of a hassle, since you have to open it up to change, and when you do, it triggers a “tamper alarm” that is both undocumented and never seems to go away. It is powered by a single CR123A 3V Lithium battery, which are about $2 each on Amazon.

Both units have a default PIR timeout of 4 minutes. That means that after sensing motion, they will transmit the “on” signal (meaning motion detected) and then transmit no further signals for at least 4 minutes. This is because operating the radio consumes far more battery power than simply monitoring the PIR sensor, and it cuts down on repeated on/off transmissions. In this configuration, both units should have battery life of 6 months to a year, I figure, with an edge for the Ecolink, perhaps.

Both can also be configured to transmit more frequently; the Ecolink has a jumper that can change its timeout to 10 seconds, whereas the Aeon can be configured over Z-Wave for any timeout between 10 seconds and 65535 seconds (values above 4 minutes are rounded to the nearest minute, for some reason.)

Both also have adjustable sensitivity; on the Aeon this is via an adjustment knob, and on the Ecolink it’s via jumpers. And both can report their battery level to enable software alerts when it’s getting low.

The Aeon ships with its temperature, humidity, battery, and lux sensors disabled. This appears to be the cause of much confusion online, as they send one transmission and then no more. Sadly, one has to resort to the hard-to-find but very helpful MultiSensor engineering spec document to figure out the way to enable those sensors and set their interval. (It must be said, however, that I doubt most consumers will understand how to set bitfields, and this is either not covered or covered incorrectly in their other manuals.) This can be a real power drain, so I just set it to report battery level every 6 hours (so I can alert myself if it gets low) and leave it at that.

The Ecolink manual claims a detection radius of 39 feet and a total angle of 90deg (45deg left or right from center) and a 3-year battery life (I’m skeptical). It also is rated for indoor use only. Aeotec claims a detection radius of 16 feet and a total angle of 120 deg. Be skeptical of all these figures.

Once set up with good reception, both devices have been working fine.

Programming the controller

The ISY-994i-Zw Pro controller I mentioned in Part 1 has its own sort of programming language. It’s a lot better than the sort of GUI clicky mess that is found in most of these things, but it still has a sort of annoying Java-based editor where you select keywords from a menu and such. Although you can backup and restore the device, and import and export the programs, the file formats are XML and not really suitable for hand-editing. Sigh.

The language is limited, but gets the job done. Here is a simple program that turns off the fan in a bathroom 30 minutes after the light was turned off:

If Status '1st Floor / Bathroom + Laundry / Main Bath Fan' is On And Status '1st Floor / Bathroom + Laundry / Main Bath Light' is Off Then Wait 30 minutes Set '1st Floor / Bathroom + Laundry / Main Bath Fan' Off Else - No Actions - (To add one, press 'Action')

The if/then/else clauses should probably be more properly called when/do/finally. The “if” clauses are evaluated whenever a relevant event occurs. If the If evaluates to true, if executes the Then section. The program in “Then” is uninterruptible except for “wait” and “repeat” statements. So in this case, the program begins, and if the light stays off and the fan stays on, 30 minutes later it turns off the fan. But if the light comes back on, the program aborts (since there is nothing in “else”). Similarly, if the fan goes off, the program aborts.

A more complicated example: motion-activated lamp

There is a table lamp in our living room controlled by Insteon. By adding a motion sensor in that room, it can be automatically turned on by someone walking through the room. Now, to be useful, I don’t want it to turn on during the day. I also don’t want it to turn on or adjust itself if other lights are on in the room, or if I turned it on myself; that could cause it to go on and off while I’m watching TV, for instance. It’s just to be helpful at night. Because the ISY-994i is pretty limited, having almost no control flow operations, this — as with many tasks — requires several “programs”.

First, here’s my “main”:

If Status '1st Floor / Living + Dining Room / LR Table Lamp' is Off And $LR_Lamp_Lockout is 0 And Status '1st Floor / Living + Dining Room / ZW 005 Binary Sensor' is On And From Sunset To Sunrise (next day) And $LR_Lamp_Motion_Working is not 0 And Status '1st Floor / Living + Dining Room / LR Floor Lamp' is Off And Status '1st Floor / Living + Dining Room / Dining Light' is Off And Status '1st Floor / Living + Dining Room / LR Light' is Off Then Set '1st Floor / Living + Dining Room / LR Table Lamp' 22% Set '1st Floor / Living + Dining Room / LR S Remote (Table Lamp)' 22% Else - No Actions - (To add one, press 'Action')

So, let’s look at the conditions. This program triggers if the lamp is off, the sensor is on, the time is between sunset and sunrise, and three other lights are off. (I will explain the lockout and motion_working variables later). If this is the case, it sets the lamp to 22% (and also informs the wall switch for it that the lamp is at 22%). I pick this precise value because it is unlikely I would manually set it via the wall switch, and therefore “lamp is 22% bright” doubles as a “lamp was turned on by this program” flag.

So this is the turning the lamp on bit. Let’s look at the program that turns it back off later:

If Status '1st Floor / Living + Dining Room / LR Table Lamp' is 22% And ( Status '1st Floor / Living + Dining Room / ZW 005 Binary Sensor' is Off Or $LR_Lamp_Motion_Working is 0 Or Status '1st Floor / Living + Dining Room / LR Light' is not Off Or Status '1st Floor / Living + Dining Room / LR Floor Lamp' is not Off Or Status '1st Floor / Living + Dining Room / Dining Light' is not Off ) Then Wait 15 seconds Set '1st Floor / Living + Dining Room / LR S Remote (Table Lamp)' Off Set '1st Floor / Living + Dining Room / LR Table Lamp' Off Else - No Actions - (To add one, press 'Action')

This is using a sensor with a 4-minute timeout, so the lamp will always be on for at least 4 minutes and 15 seconds. This program runs if the lamp is still at the program-set level (so if, for instance, I turned the lamp full on, the program does nothing to override my setting.) Then, it looks for a condition to trigger turning the lamp off, which could be any of the sensor indicating no more motion, another program detecting it’s lost communication with the sensor, or somebody turning on one of the bigger lights in the room. Then it simply sets the light (and the wall switch controlling it) to off.

There are a couple more bits to this puzzle. What if the system turned the lamp on, but I really want it off? If I walked up to the wall switch and pushed “off”, the lamp would go off. And then, a couple seconds later, come back on, since the state of the system met the conditions for the lamp-on program. So we need a lockout that prevents this from happening. Here’s my “trigger lockout” program:

If Control '1st Floor / Living + Dining Room / LR Table Lamp' is switched Off Or Control '1st Floor / Living + Dining Room / LR Table Lamp' is switched Fast Off Or Control '1st Floor / Living + Dining Room / LR S Remote (Table Lamp)' is switched Fast Off Or Control '1st Floor / Living + Dining Room / LR S Remote (Table Lamp)' is switched Off Then $LR_Lamp_Lockout += 1 Run Program 'LR Lamp Clear Lockout' (If) Else - No Actions - (To add one, press 'Action')

So if someone pushes the “off” button at the lamp switch box at the outlet it’s plugged into (unlikely), or at the wall switch, it increments the lockout variable and runs another program. This other program is unique in that it is flagged “disabled”, meaning it is never run automatically by the system, only when called by another program. Here’s the clear lockout program:

If $LR_Lamp_Lockout > 0 Then Wait 5 minutes $LR_Lamp_Lockout = 0 Else - No Actions - (To add one, press 'Action')

Thus by pushing the “off” button on the switch, the motion-triggered program won’t turn the lamp back on for at least 5 minutes.

Before I had reliable Z-Wave communication to the device, I had some times where it would simply drop off the Z-Wave network until a reboot. This was particularly annoying if it occured after having detected motion, since the state of the sensor in the ISY controller is simply whatever state it last received. Therefore, I wrote this program to check if it believes the motion sensor is working:

If Status '1st Floor / Living + Dining Room / ZW 005 Binary Sensor' is On Then $LR_Lamp_Motion_Working = 1 Wait 1 hour $LR_Lamp_Motion_Working = 0 Else $LR_Lamp_Motion_Working = 1

We don’t really care if the motion sensor is broken when the status is off; all that happens then is no lamp turns on. So this program activates when the status is set to on. It flips the working flag to true, then waits for an hour. If the sensor shows no motion within that hour, the program skips to the else (keeping the flag true). But if it is still on after an hour, it decides “it must not be working” and sets the working flag to false. You can see that flag used in the other programs’ logic. But because of the Else, which is run whenever the conditions that caused the Then clause to run become false, as soon as the system receives “no motion”, it will flag the sensor as working again.

The final piece to this puzzle is a program flagged to run at boot time of the controller:

If - No Conditions - (To add one, press 'Schedule' or 'Condition') Then $LR_Lamp_Motion_Working = 1 Else - No Actions - (To add one, press 'Action')

This simply initializes the motion working variable to a known state.

Keypads

The Insteon KeypadLinc is a nice device. It can control a single load directly, but all 8 buttons are fully responsive in the Insteon system. They each also have individually-addressible LED backlights. They are commonly used to do things like “ALL OFF”, “TV” (to set lights for watching TV), “AWAY” (to set the system for everyone being out of the house for awhile), etc. They are the size of a regular Decora switch, and I have installed one already, but haven’t programmed much of it yet.

REST API

The ISY has an extensive REST API, which I’ve used to integrate it a bit with my Debian systems. More on that another time.

Mobile app

Mobile apps are a common thing people look for in these systems. You can’t use the Insteon app with the ISY, but they recommend Mobilinc Pro. It does the job. Mobilinc tries to sell a $10/mo connection service, which is totally unnecessary if you can figure out SSL, and has on-screen buttons to bypass, but judging by the Google Play reviews, a lot of people thought they had to pay for that and uninstalled it afterwards.

Future directions

Many people put in electronic door locks. I don’t plan to do that. I do plan to have the house systems be aware of the general state of things (is the house empty? is everyone asleep?) and do appropriate things with lighting and HVAC. I don’t really expect the savings in power for lighting control to pay for the system anytime soon. However, if it can achieve some savings in heating and cooling, it may well be able to pay for itself in a few years. So my big next step is thermostats that can integrate with all this.

I have had a water mess in my basement before, and water leak sensors are a very common item people deploy in these setups. I certainly plan to add a few of them.

Door-open sensors are also useful; they trigger more instantly and reliably than motion detectors and can be used in some nice ways (is it after dark and the door is opening when the house is vacant? If so, turn on the light nearby in case their hands are full.)

Issues

Some issues I ran into so far are already discussed above. One other major one involves SSL on the ISY-994i Pro. The method for adding SSL keys is cumbersome, but the processor on the device — which appears to run some sort of Java — is just not up to working with SSL. Apparently they only recently got it fast enough to work with 2048-bit keys. This is rather undocumented, though, so I obtained a cert for a 4096-bit key, my usual. Attempting to connect to the box with SSL appeared to hang not just that but confuse a lot of other things on it as well. Turned out it wasn’t hung; it just too a minute and 45 seconds to complete the SSL handshake. Moral of the story: use 2048-bit keys, or stunnel4 or some such to re-wrap the SSL communications with a stronger key.

The KeypadLinc backlights can be completely shut off, and both their on and off levels can be customized. I have it set to shut off the backlight during the day and turn it on at night. The wall switches, however, can’t have their brightness status LED bar entirely shut off. They can be made dim, but don’t ever go away. That’s rather annoying.

Also annoying is that Insteon doesn’t make switches in the traditional toggle switch style in colors other than white. As our house had mostly black switches, I was forced into the Decora style.

Overall thoughts

This has been a great learning experience for me in a number of ways. I have only begun to tap what the system can do, and the real benefits will probably come once I get the heating and cooling into the mix. It’s quite a nice way for a geek to go, and the improvements in lighting have also been popular with everyone else in the house.

Categories: Elsewhere

Ryan Szrama: Why not combine shopping carts on user login?

Planet Drupal - Sat, 31/01/2015 - 20:06

When I first wrote Ubercart's Cart module, we knew we were going to support both anonymous and authenticated shopping carts and checkout. The decision came at a time when there wasn't consensus around the impact of forced login on conversions, but we knew we wanted it to be optional if at all possible. Additionally, for authenticated users, we wanted to preserve items in their shopping carts so they would see the same items when logging in from multiple devices or across multiple sessions.

This resulted in a small conflict that we had to figure out how to deal with: users could have items in their authenticated shopping carts but browse the site anonymously, create a new shopping cart, and then log in. What should happen to the items in their authenticated carts vs. the items in their anonymous carts?

There are three basic resolutions: combine the shopping carts together so the user still has a single shopping cart, remove the items from the previous session and leave it up to the customer to find them again if desired, or retain the old shopping cart but ignore it until the customer has completed checkout for the current cart. In Ubercart, I chose to combine the items, but in Drupal Commerce I changed course to retain the old cart but, from the customer's point of view, treat that anonymously created cart as the current cart after login.

We got some push back for this decision, but ultimately I didn't change the default functionality of Drupal Commerce. We just made sure there was an appropriate hook (hook_commerce_cart_order_convert()) so developers could alter this behavior on a site-by-site basis as need be.

From the merchant's standpoint, the thinking behind combining carts goes that you don't want customers to forget they intended to purchase those products in the past. However, from the customer's standpoint, suddenly having additional items in the cart after logging in during the checkout process is quite jarring.

In fact, I've been bitten by this behavior when shopping online at Barnes & Noble. Weeks prior to placing an order, I had put a Wheel of Time novel in my shopping cart but eventually bought the book in store. When I came back to the site to purchase a gift for my wife, I used a login button on the checkout form to quickly reuse my previous addresses and payment details. Unbeknownst to me, the website combined my old shopping cart with my current one such that my "quick checkout" experience made me accidentally order a book I already owned! I then had to spend 30 minutes with customer service canceling the order and placing it afresh just for the book I actually wanted.

That experience confirmed in my mind we made the correct decision not to combine carts automatically. As eCommerce framework developers, we have no clue where a developer might like to integrate login during the checkout process. Best to let them decide if it's safe to do something with those previous cart items instead of silently making the decision for them.

That said, I believe we can improve the experience. Right now, Drupal Commerce retains the old shopping cart order, and after the customer completes checkout they'll see the previous shopping cart as their current cart. This can be confusing as well! My ideal situation would likely be a user interface component on the shopping cart page where customers can see items they had added to their carts in previous sessions, giving them the option to add those products to their current carts. If they decide not to, I don't see any harm in then just deleting those historical carts and moving on.

There's always room for improvement.

Photo credit: alphageek

Categories: Elsewhere

Pages

Subscribe to jfhovinne aggregator - Elsewhere