Stefan's profileStefan Prodan's spacePhotosBlogLists Tools Help

Blog


    My New Intel PC Power Consumption Estimation

    These days I am building a new pc for home use. It’s so difficult for me to chose the rite parts as I want to have a high end PC suitable for programming, design (photo & video editing) and gamming that can run smoothly Vista 64bit. The full configuration without a case (my old Thermaltake Soprano is in excellent shape) must not exceed 1000 Euro. This week I’ve been reading tones of hardware reviews, forums and blogs; finally I’ve managed to make a list of components I want for my new pc. Today I was wandering what kind of power supply should I buy considering the low amount of money I got left from my 1000 Euro budget. So first I’ve tried to figure out my pc’s configuration power consumption.

    First of all I was tying to find a free windows software that will calculate the power consumption of my actual pc… but no luck. After intense “googling” I’ve found a great web application made by Thermaltake named Power Consumption Calculator. I highly recommend this calculator for anyone who is tying to build a PC on his own from components.

    Here it is the estimation I got for my configuration:

    System Type: Single Processor
    Motherboard: High End – Desktop
    CPU: Intel Core 2 Duo E8500 3166 MHz Wolfdale
    CPU Utilization (TDP): 85% TDP
    RAM: 4 Sticks DDR2 SDRAM
    Video Card: NVIDIA GeForce 9800 GTX+
    Video Type: Single Card
    IDE HDD 7200 rpm: 4 HDDs
    DVD-RW/DVD+RW Drive: 1 Drive
    Sound Blaster - All Models: Yes
    PCI IDE Card: Yes
    Additional PCI Card (avg): 1 Card
    Fan Controller: Yes
    Front Bay Card Reader: Yes
    Fans Regular: 1 Fan 140mm;  2 Fans 250mm;
    Keyboard & Mouse (included): Yes
    System Load: 90 %

    Recommended PSU Wattage: 390 Watts

    Now having this value I thought that buying a 420 power supply will do just fine, but the watts specified on the power supplies products can be deceptive. If you buy for example a 400Watts that doesn’t really mean you have all that power, on a 400 you might have 300 or even less and I am not talking about a “no name” low-cost product here.

    My conclusion is that for a 390 watts consumption, to be sure, I have to buy a power supply at 550 watts minimum. Finally I can now make a decision based on my budget and desired quality, my choice is Antec NeoPower 550EC.

    Hardmusic.ro Hardcore Mix Vol.1 by Creep



    Promotional hardcore techno mix by Creep for www.hardmusic.ro

    Playlist:
    1. Mike NRG - Lost in Dreams (Weapon X Remix)
    2. Evil Activities – Evilution
    3. Weapon X - Planet Rocker
    4. Evil Activities – No Place To Hide
    5. Nitrogenetics – Pledge Of Resistance
    6. The Stunned Guys And Art Of Fighters - Eternal
    7. Art of Fighters - Artwork(Tha Playah Remix)
    8. Masters of Ceremony - Dirt
    9. Prankster – Hustlers & Killers
    10.Na-Goyah - Going Down
    11.Source Code - I'm Not A Number (Headbanger Remix)
    12.DJ D Vs DJ Piwi - Always Naked
    13.Unexist - Spank Yer Ass

    Download

    Hardmusic.ro up and running!

     

    Hardmusic.ro it’s a project intended to promote the hard styles of electronic music in Romania.

    Hardmusic.ro a luat nastere in decembrie 2008 si este un site ce promoveaza muzica electronica in formele ei dure ("hard styles"). Scopul echipei hardmusic este sa largeasca spectrul de genuri de muzica electronica ascultate si promovate in Romania, in primul rand hardmusic.ro se vrea un site de culturalizare a genurilor inexistente pe scena romana, genuri consacrate in europa cum ar fi hardstyle, mainstream hardcore, uk hardcore, hard house, uplift si multe altele.

    Esti pasionat de muzica electronica? Vrei sa promovezi un eveniment sau ai un artist favorit si vrei sa scrii despre el?
    Devino membru al echipei hardmusic inscrie-te pe forum si contacteaza-ne sau da-ne un mail: contact email

    My Smartphone Wallet on Softpedia

    I am proud to announce that Softpedia.com has publish My Smartphone Wallet v1.0 Beta in the handheld section.

    Now you can download the application from them:

    http://handheld.softpedia.com/get/Security/Password-Managers/My-Smartphone-Wallet-68356.shtml

    My Smartphone Wallet Beta v1.0

    My Smartphone Wallet is a freeware mobile application designed to store in a secure way your credit card information, very simple and easy to use. This application is compatible with Windows Mobile Version 5 and 6 for Smartphone QVGA and needs .NET Compact Framework 2.0 installed on the device. The current version 1.0.0.0 Beta was tested on HTC S710 device and should work fine on any Windows Mobile 6 Standard Edition without the need of .NET Compact Framework updates.

    MySpWallet Beta v1.0

    Why this software? Well there is no freeware wallet application for Smartphone that I could find on the web and as any software developer will say "If you can make your own why buying from others ?! " :)  Before I was storing in my notes the credit card information as allot of people do... so if anyone finds your lost phone or steals it there is a big chance that you'll lose the money from the cards as well, with this app no such thing is possible, just put a strong password and you are safe. Only someone that can reverse SHA1 can hack the password, so I wouldn't mind about that. (For geeks: I know about MD5 and SHA1 reverse lookup databases but with a strong password all the effort to crack are in vain).

    Features

    • Password protected access to credit cards information
    • Encrypts all credit cards entries using 128-bit Hash and 40-bit Symmetric
    • Stores all the information needed for online transactions
    • Warns about expire dates
    • Data file backup (restore is done by copy/paste to app dir)
    • No phone dependencies, the data can be accessed on any WM5 or WM6 device with the rite password
    • Small memory footprint (internal memory can be monitored using the "Memory info" function)

    In version 1.0.0.0 the credit card fields that are stored are:

    1. Credit Type (Visa, MasterCard, etc)
    2. Owner (the person name that owns the card)
    3. Bank name
    4. Card number
    5. Card CVV/CVC/CID Code (Security code on the back of the card, not all types has it)
    6. Expiration date
    7. Card PIN (Used for money redraw at the ATM)
    8. Lost phone number (any card has it)
    9. Notes (extra data that you can add like currency and such)

    Thing to do (final version)

    • Test the application on different devices (help needed)
    • Add a strong password evaluator
    • Restore function
    • Optimize the code that deals with save & load of the wallet data file
    • Maybe add more fields to the credit card entry (suggestion are welcomed)

    Safety concerns?
    This software is made using VS.NET and WM6 SDK, the code is not protected in any way so you can easily decompile it and see the C# code for yourself, there is no trick in it, no secret backdoor access or any bad intentions. I intend to make this project open source if anyone shows interest in it. The encryption code uses Microsoft Base Cryptographic Provider v1.0 so if there is any vulnerability blame the Windows Mobile Kernel or RSA :)

    License
    I hereby state that My Smartphone Wallet is Freeware, and therefore can be used in an unlimited fashion for any purpose by individuals, corporations, educational, government, military departments, and any other entity. It is prohibited to sell My Smartphone Wallet standalone as part of another software, to distribute in any form without permission from Stefan Prodan, or to claim any rights regarding My Smartphone Wallet.
    The software is provided "AS IS" and the author and contributors disclaim all warranties with regard to this software including all implied warranties of merchantability and fitness. In no event shall author and contributors be liable for any special, direct, indirect, or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software.

    Download Beta 1.0 (Copy the .cab file to your mobile phone and run it)

    If you use this app and have
    any thoughts post a comment or
    contact me any time at:
    hotmail

    Digg!

    HTC VOX S710 Smartphone Review

    Technorati Tags: ,,

    This month I decided to acquire a Windows Mobile 6 device to play with, the Vodafone offered me  a discount on HTC Vox so being my first Smartphone experience I wanted something cheep. I've played allot with it these days so here comes my review.

    htc_s710

    Hardware Specs

    Processor: TI's OMAP 850, 201 MHz
    Platform: Microsoft Windows Mobile 6 Standard
    Memory: ROM 128MB, RAM 64MB
    Expansion: microSD (up to 8GB)
    Network: GSM/GPRS/EDGE
    Connectivity: Bluetooth, Wi-Fi, USB
    Camera: 2 mega-pixel CMOS
    Display: TFT 240 x 320 pixels
    Dimension: 101.5 mm(L) x 50 mm(W) x 18.6 mm(T)
    Weight: 140 g
    Full specs on gsmarena

    Out of the box software

    • Office Mobile 2003 (Outlook, Word, Excel, PowerPoint, Voice Notes)
    • Adobe Reader LE 2.0
    • Windows Media Player 10 Mobile
    • Windows Live Mobile
    • Java MIDP 2.0
    • HTC Quick Notes
    • HTC Audio Manager
    • HTC Task Manager

    You should know that Outlook is at the core of this phone, mail, tasks, calendar, SMS, MMS are managed using Outlook, the best part about this is that with ActiveSync version 4.5 you can synchronize most of the data, only SMS, MMS are not imported on the PC, but there are 3ed parties software that can do this. Word, Excel and PowerPoint lack the function to create new files, the workaround is to put on your SD empty documents and edit those then "save as". Windows Live is well integrated, you have access to all the features like mail, messenger, contacts and search (IE Mobile default search). With Adobe Reader LE you can open even large PDF file but lacks the usability I was expecting from Adobe, try to read a PDF book that is not made for mobile and you'll see what I mean. With Media Player you'll not be able to view AVI file (DivX, Xvid, etc) and if you want to play movies they should be converted priory at a lower frame rate. Java MIDP it's great, I've tested allot of games and applications made for Symbian and J2ME and most of them, if they are made for 240 X 320 resolution perform ok. The HTC applications are very well made and without them using this phone would get really hard, first of all WM6 doesn't have a Task Manager, HTC Task Manager is a tool that you should put on speed dial because the system will eat up most of the RAM so you'll have around 20MB free memory for all the applications that are running, with the Task Manager you can monitor the RAM usage and close applications to make room for others. The memory problem I think is generated by the fact that windows applications like Media Player, IE, Contacts, Outlook, etc doesn't have a close button, so if you access the calendar there is no way to close it. HTC Task Manager has another great feature "Go To", it acts like Alt-Tab, it's the only way to bring to front running applications. HTC Audio Manager is an MP3 player like Winamp, Media Player is not suitable for music playback so this software comes to the rescue.

     Recommended software

    • Office Mobile 2007 Update (adds Office 2007 file types compatibility and Zip Mobile 6.1)
    • Office OneNote Mobile (requires that you have on your PC OneNote 2007 installed, it will detect your device and deploy the mobile kit, then you can synchronize notes using ActiveSync)
    • BeyondPod (freeware RSS Reader with podcast support)
    • Palringo (freeware All in One Instant Messenger, you can even push pictures taken with your phone)
    • Schedy Mobile (freeware alarm app, Windows alarm is useless you'll need a configurable alarm app for sure)
    • Mobipocket Mobile Reader (freeware eBook reader, you'll need the windows apps as well because you'll be able to export DOC, PDF, HTML and RTF documents to Mobipocket format, Adobe Reader LE is a jock compared to this)
    • Avot mV (freeware video streaming player, you can search on youtube.com and tones of other sites, youtube doesn't perform well I don't know if it's Avot fault or the OMAP 850 CPU, other videos like CNN news are ok)
    • Resco Explorer (commercial product, it's a great file explorer has all the functions that the default WM6 explorer lacks, like copy to, move to, archive, unzip, unrar and more; I like it so much because it comes with two great add-ons: FTP client and Registry manager, for me as a developer the Registry add-on is a must, with it I can make backups and switch between multiple configurations)

    The Good :)

    • Great value for money
    • QWERTY keyboard is great for instant messengers, mails and sms
    • Strong signal and good voice / playback quality (better then most phones with mp3 player)
    • Audio playback with the display on can last up to 7 hours (tested)
    • Tones of application and games on the web: freeware, shareware and commercial
    • It's more then a multimedia gadget, due to the Compact Framework and Java environment it can be used for business purpose (ERP client, report viewer, Exchange client and much more)
    • Wi-Fi works great in secure environments like VPN, HTTPS
    • Can be used as a synchronization device between multiple PC's (home and office for example)
    • With a large SD Card (4GB-8GB) you don't need to carry any extra devices like a USB Stick or Mobile HDD

    The Bad :(

    • No 3G, the GPRS is too slow for today Internet needs
    • Pictures quality are bad, no blitz or zoom (there are phones with 2MP and better photo quality)
    • No Adobe Flash Player (there is a workaround that can be done but involves buying Opera and some registry hacks but still will not work 100%)
    • No hardware support for call recordings (that means that no software will work doesn't matter how good is it)
    • The 200Mhz CPU is slow on multithreading (you have to close background applications as often as possible otherwise the phone will run very slow)
    • The loudspeaker is awful
    • Even if the device has mini USB it works only with the HTC cable and there is no audio jack entry so if you want better headphones you have to  buy a 3 in 1 adaptor from HTC
    • Windows Update is not working, I've search about this and the HTC wiki suggests it's HTC fault, they should host the update server and they didn't...

    PS: I am working on a mobile application right now called My Smartphone Wallet, it's an app that is designed to store credit card data in a secure way on your mobile. It's going to be be released as freeware, more info soon.

    Session provider for .NET Remoting and WCF

    Project objectives
    Create a session provider mechanism that mimics the ASP.NET Session. The provider target are distributed applications developed with VS.NET 2008 and .NET Framework 3.5. The Session object should be compatible with .NET Remoting and WCF technologies and must perform well in a multithreading environment. The Session provider should be customize by external components without recompilation.

    Project background
    The project was first developed on .NET Framework 2.0 and was used by a distributed application made with C# 2.0 and .NET Remoting. Now the application is run by over 2000 clients with good feedback, no bugs have been reported regarding the features that depend on the Session component. The reason behind the C# 3.0 upgraded version of the Session component is the fact that due to the multithreading environment the C# 2.0 version was using the ReaderWriterLock class. ReaderWriterLock has a lot of problems in environments with heavy load, .NET Framework 3.5 brings a new class named ReaderWriterLockSlim that improves speed and reduces the deadlock occurrence possibilities. You can find out more about the reasons why Microsoft decided to implement the ReaderWriterLockSlim from the Joe Duffy's Blog in this post and you can see a performance comparison of ReaderWriterLockSlim with ReaderWriterLock on Pedram Razaei's blog in this post. The older version of the Session project has allot of hard coded members, members that were application specific, the new version has to provide a way to add dynamic objects to the Session, objects that are not implemented inside the Session class.

    Building interfaces
    To reach one of the main objective(extensibility) I've created an interface for the objects that can register in the session instance. All objects that can register must implement the ISessionEntry. By this interface the Session provider can control the entries and in the same time the developer can create his own class that suits his needs without changing the Session class code.
    ISessionEntry

    Another interface used in the project is ISession. If you want to have your own implementation of the Session provider you can do it by inheriting ISession. Note that T is type of ISessionEntry and must have a default empty constructor.

    public interface ISession<T> where T : ISessionEntry, new()

    ISession

    Building Session class
    The full code of the Session class can be found here, but let me explain a little what's going on. The Session class is ensuring the thread safety of it's members using a ReaderWriterLockSlim instance called slimLoack. There are 3 collections inside that holds the objects managed by the class: activEntries, expiredEntries and data. The activEntries collection is most important one, to modify this List there 2 public methods (Register and Unregister) and one private method named ClearExpired that's called by the cleaner thread every minute. The expiredEntries is a private collection used by the cleaner thread inside ClearExpired and helps delete entries from the active collection.

    public Session(int sessionTimeoutInMinutes)
    {
    slimLock = new ReaderWriterLockSlim();
    cleaner = new Thread(new ParameterizedThreadStart(ClearExpired));
    cleaner.IsBackground = true;
    cleaner.Start(sessionTimeoutInMinutes);
    }

    As you can see in the constructor it can be set the timeout, there is no default value like in ASP.NET (20 minutes) because I think that any .NET Remoting server or WCF has it's own specific timeout, for example in the distributed application I mentioned the timeout is like 1h but if your application has per user licence then the timeout should be very short. In a per user licence case you should make on the client a KeepAlive Thread that every minute updates the LastAccessTime value on the server using the public method UpdateLastAccessTime. If the client shuts down without calling the Unregister method then after 1 minute he can login again because the cleaner thread has deleted the user entry from the active session.
    The data collection is of type Dictionary<long, Hashtable> and mimics the ASP.NET way of storing and retrieving custom objects from the session. There is a Set and a Get method, in order to perform them the objects stored must be marked as serializable, if you'll use binary serialization in Remoting or netTcpBinding in WCF most of the objects will be suitable for session storage.
    There is a method named PrepareForDispose, it's not a common method for a .NET class but I wanted to make sure that the cleaner thread will exist gracefully, calling Abort on a thread is very nasty way to exit because it will throw a ThreadAbortException. So my PrepareForDispose method wakes up the thread if it's in sleep mode and waits for it to finish processing like this:

    //set volatile flag
    running = false;
    //wake up cleaner if (cleaner.ThreadState == ThreadState.WaitSleepJoin)
    {
    cleaner.Interrupt();
    }
    //wait for the thread to stop for (int i = 0; i < 100; i++)
    {
    if (cleaner == null || cleaner.ThreadState == ThreadState.Stopped)
    {
    System.Diagnostics.Debug.WriteLine(
    "Cleaner has stopped after " + i * 100 + " milliseconds");
    break;
    }
    Thread.Sleep(100);
    }

    Using the Session provider
    Before using the the Session provider we have to create a class suitable for a session entry, the most common usage is the User class.

    [Serializable]
    public sealed class User : ISessionEntry
    {
    #region ISessionEntry Members
    public long SessionId
    { get; set; }

    public DateTime LastAccessTime
    { get; set; }
    #endregion public string Username
    { get; set; }
    public string Password
    { get; set; }
    }

    The following example is a console application and it shows how the methods of Session class can be used:

    class Program
    {
    static void Main(string[] args)
    {
    //Session object creation Session<User> sessionManager = new Session<User>(1);
    //Register timeout event sessionManager.OnEntryTimeout += new SessionEntryTimeoutDelegate<User>(sessionManager_OnEntryTimeout);
    //New user User user = new User() { Username = "Stefan", Password = "Prodan" };
    //Login sessionManager.Register(ref user);
    //Call Session specific methods Console.WriteLine("User {0} session id is {1}",
    sessionManager[user.SessionId].Username, user.SessionId);
    //Store on the session a user's object sessionManager.SetData("MyData", "UserObject", user.SessionId);
    Console.WriteLine("{0} session data is {1}",
    user.Username, sessionManager.GetData("MyData", user.SessionId));
    //Wait for the user session to expire Console.WriteLine("Wait until the session expires (1 minute)");
    Console.ReadKey();
    //Free resources used by the session sessionManager.PrepareForDispose(); Console.ReadKey(); } static void sessionManager_OnEntryTimeout(User user)
    {
    Console.WriteLine("Session expired for user id {0}", user.SessionId);

    }
    }

    In the future I will post real examples of how to use Session provider in production with .NET Remoting and WCF. Full source code of the examples will be uploaded to my SkyDrive public folder so anyone can get them. In the meanwhile I am expecting comments and ideas about improving the session provider.

    Digg!

    kick it on DotNetKicks.com

    Session related interfaces

    public interface ISessionEntry
    {
        long SessionId { get; set; }
        DateTime LastAccessTime { get; set; }
    }
    
    public interface ISession<T> where T : ISessionEntry, new()
    {
        System.Collections.Generic.List<T> Entries();
        object GetData(string key, long id);
        bool IsOnline(long sessionId);
        event SessionEntryTimeoutDelegate<T> OnEntryTimeout;
        void PrepareForDispose();
        void Register(ref T newEntry);
        void SetData(string key, object val, long id);
        T this[long index] { get; }
        bool Unregister(long sessionId);
        bool UpdateLastAccessTime(long sessionId);
    }

    Session Class

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    using System.Threading;
    
    namespace Aleph.Framework.Remoting
    {
        public delegate void SessionEntryTimeoutDelegate<T>(T entry);
    
        public class Session<T> : ISession<T> where T : ISessionEntry, new() 
        {
            //timeout event
            public event SessionEntryTimeoutDelegate<T> OnEntryTimeout;
    
            //storage colections
            List<T> activEntries = new List<T>();
            List<T> expiredEntries = new List<T>();
            Dictionary<long, Hashtable> data = new Dictionary<long, Hashtable>();
    
            //threading
            Thread cleaner;
            ReaderWriterLockSlim slimLock;
            volatile bool running = true;
    
            public T this[long index]
            {
                get
                {
                    slimLock.EnterReadLock();
                    T outputEntry = new T();
                    try
                    {
                        foreach (T entry in this.activEntries)
                        {
                            if (entry.SessionId == index)
                            {
                                outputEntry = entry;
                                break;
                            }
                        }
                    }
                    finally
                    {
                        slimLock.ExitReadLock();
                    }
    
                    if (outputEntry.SessionId == 0)
                    {
                        throw new SessionException("Session expired");
                    }
    
                    return outputEntry;
                }
            }
    
            public Session(int sessionTimeoutInMinutes)
            {
                slimLock = new ReaderWriterLockSlim();
                cleaner = new Thread(new ParameterizedThreadStart(ClearExpired));
                cleaner.IsBackground = true;
                cleaner.Start(sessionTimeoutInMinutes);
            }
    
            public void Register(ref T newEntry)
            {
                slimLock.EnterWriteLock();
                try
                {
                    newEntry.LastAccessTime = DateTime.Now;
                    newEntry.SessionId = newEntry.LastAccessTime.ToBinary();
    
                    this.activEntries.Add(newEntry);
                }
                finally
                {
                    slimLock.ExitWriteLock();
                }
            }
    
            public bool Unregister(long sessionId)
            {
                slimLock.EnterWriteLock();
                try
                {
                    bool ok = false;
                    int y = -1;
    
                    for (int i = 0; i < this.activEntries.Count; i++)
                    {
                        if (this.activEntries[i].SessionId == sessionId)
                        {
                            y = i;
                            ok = true;
                            //remove data from colection
                            data.Remove(sessionId);
                            break;
                        }
                    }
                    if (y > -1)
                    {
                        //remove entry from colection
                        this.activEntries.RemoveAt(y);
                    }
                    return ok;
                }
                finally
                {
                    slimLock.ExitWriteLock();
                }
            }
    
            public bool UpdateLastAccessTime(long sessionId)
            {
                slimLock.EnterWriteLock();
                try
                {
                    bool ok = false;
                    int y = -1;
                    //search for entry
                    for (int i = 0; i < this.activEntries.Count; i++)
                    {
                        if (activEntries[i].SessionId == sessionId)
                        {
                            y = i;
                            ok = true;
                            break;
                        }
                    }
                    if (y > -1)
                    {
                        this.activEntries[y].LastAccessTime = DateTime.Now;
                    }
                    return ok;
                }
                finally
                {
                    slimLock.ExitWriteLock();
                }
            }
    
            public bool IsOnline(long sessionId)
            {
                bool ok = false;
                slimLock.EnterReadLock();
                try
                {
                    //search for session ID
                    foreach (T entry in this.activEntries)
                    {
                        if (entry.SessionId == sessionId)
                        {
                            ok = true;
                            break;
                        }
                    }
                }
                finally
                {
                    slimLock.ExitReadLock();
                }
    
                return ok;
            }
    
            public List<T> Entries()
            {
                slimLock.EnterReadLock();
                try
                {
                    return this.activEntries;
                }
                finally
                {
                    slimLock.ExitReadLock();
                }
            }
    
            public void SetData(string key, object val, long id)
            {
                slimLock.EnterWriteLock();
                try
                {
                    Hashtable ht = new Hashtable();
                    if (data.ContainsKey(id))
                    {
                        ht = data[id];
                        //overwite value if key exists
                        //acts like the ASP.NET session
                        if (ht.ContainsKey(key))
                        {
                            ht[key] = val;
                        }
                        else
                        {
                            ht.Add(key, val);
                        }
                        data[id] = ht;
                    }
                    else
                    {
                        ht.Add(key, val);
                        data.Add(id, ht);
                    }
                }
                finally
                {
                    slimLock.ExitWriteLock();
                }
            }
    
            public object GetData(string key, long id)
            {
                slimLock.EnterReadLock();
                object val = null;
                try
                {
                    if (data.ContainsKey(id))
                    {
                        if (data[id].ContainsKey(key))
                        {
                            val = data[id][key];
                        }
                    }
                }
                finally
                {
                    slimLock.ExitReadLock();
                }
                return val;
            }
    
            public void PrepareForDispose()
            {
                //set flag
                running = false;
                //wake up cleaner
                if (cleaner.ThreadState == ThreadState.WaitSleepJoin)
                {
                    cleaner.Interrupt();
                }
                //wait for the thread to stop
                for (int i = 0; i < 100; i++)
                {
                    if (cleaner == null || cleaner.ThreadState == ThreadState.Stopped)
                    {
                        System.Diagnostics.Debug.WriteLine(
                            "Cleaner has stopped after " + i * 100 + " milliseconds");
                        break;
                    }
                    Thread.Sleep(100);
                }
                //prepare objects for GC
                activEntries.Clear();
                activEntries = null;
                expiredEntries.Clear();
                expiredEntries = null;
                data.Clear();
                data = null;
            }
    
            void ClearExpired(object timeout)
            {
                int sessionTimeout = (int)timeout;
    
                while (running)
                {
                    slimLock.EnterUpgradeableReadLock();
    
                    try
                    {
                        //process all active entries
                        for (int i = 0; i < this.activEntries.Count; i++)
                        {
                            TimeSpan span = 
                                DateTime.Now - this.activEntries[i].LastAccessTime;
                            if (span.TotalMinutes >= sessionTimeout)
                            {
                                this.expiredEntries.Add(this.activEntries[i]);
                            }
                        }
    
                        //remove timeout entries
                        if (this.expiredEntries.Count > 0)
                        {
                            slimLock.EnterWriteLock();
                            try
                            {
                                foreach (T entry in this.expiredEntries)
                                {
                                    System.Diagnostics.Debug.WriteLine(
                                        "Session expired for id = " + entry.SessionId);
    
                                    if (OnEntryTimeout != null)
                                    {
                                        //will slow down the thread
                                        OnEntryTimeout(entry);
                                    }
    
                                    data.Remove(entry.SessionId);
                                    this.activEntries.Remove(entry);
                                }
    
                                this.expiredEntries.Clear();
                            }
                            finally
                            {
                                slimLock.ExitWriteLock();
                            }
                        }
                    }
                    finally
                    {
                        slimLock.ExitUpgradeableReadLock();
                    }
    
                    //sleep for 1 minute(larger values will speed up the session)
                    Thread.Sleep(TimeSpan.FromMinutes(1).Milliseconds);
                }
    
            }
        }
    }