Whether it's Chapter 7 or 13, bankruptcy is a tough spot to be in, but there is a road out, and you can drive it.
Despite an economy on the upturn, many Americans are finding bankruptcy to be the only answer when financial circumstances overwhelm them or a job loss or illness turns a rosy future into a disaster. Bankruptcy gives some time and breathing room to pay off debts, or it may expunge those debts altogether. But bankruptcy is not a financial Get out of Jail Free card. It has consequences, and one consequence is that it will make it more difficult—and more expensive—to get a new loan for a big-ticket item such as a car. Happily, you can recover from bankruptcy, rebuild your credit, and rejoin the economic mainstream. So how does buying a car figure into the equation?
Buying a vehicle makes sense after bankruptcy if you treat it as a tool to improve your financial situation. Buying a car or truck after bankruptcy makes no sense at all if it causes you to overextend your finances by putting you in a situation where making your loan payments is a struggle—or worse. Buying a vehicle that is too expensive or buying one too soon after bankruptcy won't help you, and it could send you hurtling back over the financial abyss. But by very carefully obtaining an auto loan with terms you can handle, you can begin to re-establish your creditworthiness. "If someone [after bankruptcy] can be approved for a car loan and makes the payments on time every month, the loan will help them re-establish credit," Sarah Teets, a senior client advocate at credit-counseling firm GreenPath Financial Wellness, told C/D.
There are two types of personal bankruptcy in the United States, and each type has ramifications for a potential vehicle purchase. In a Chapter 7 bankruptcy, the court liquidates your assets and distributes them to your creditors, and your debts are essentially expunged. Quite often, certain assets are exempted from the liquidation up to a certain value. A vehicle can be one of those assets, because bankruptcy courts generally recognize that one needs a car to get and keep a job. The entire Chapter 7 process is relatively short, typically less than six months. After receiving your Notice of Discharge, you will be debt free, but you will also have a bankruptcy on your credit report, where it will stay for 10 years, Teets said. This will typically drop you into the riskiest and most expensive end of the car-loan pool: subprime.
Chapter 13 bankruptcy is substantively different than Chapter 7. In a Chapter 13 bankruptcy, debt is restructured, not discharged. The good news is that you save your assets rather than seeing the vast majority of what you own liquidated to pay off debt. The bad news is that it is a lengthy process that can take up to five years. During that multiyear period, taking on substantial additional debt isn't your decision alone; it also requires the permission of the bankruptcy court. "One thing the bankruptcy trustee will consider is whether a [new] car should be regarded as a necessity or a luxury," Teets said.
Permission to take on a car loan to buy a modest vehicle often is granted by the court. But just as is the case for the person who has filed Chapter 7, the Chapter 13 bankruptcy will be a black mark that will stay with you, typically for seven years. It also will label you a subprime loan prospect.
Subprime buyers are getting car loans and purchasing new cars every day of the week. The important question isn't whether you can buy a vehicle; it is whether you should buy one. If you take on a subprime loan, the odds are that you will be charged an interest rate three to four times higher than that charged to those with the best credit scores. While car-loan interest rates for the least risky buyers currently hover around 4.0 percent, the Associated Press recently reported the rate for subprime borrowers has ballooned to 16.8 percent.
Still, accepting a loan at a high rate can be beneficial if you buy an affordable, reliable vehicle that will help your employment situation. Purchase a modest, used "transportation car" that won't cost you more than 15 percent of your total take-home pay. Save the purchase of the brand-new car until you have put your financial house in order and bankruptcy is long behind you.
Sadly, though, many consumers emerging from bankruptcy can't resist that brand-new, flashy set of wheels. And some car dealers take advantage of those people by offering them financing, often at exorbitant interest rates, knowing full well they are likely to default on the loan. If they do, the vehicle will be repossessed, and the money the car buyer has paid on the loan will be forfeited. The car buyer ends up with no car and no money, a financial double whammy.
Chapter 7 bankruptcy should discharge your debts, but you should check your credit reports to make certain this has occurred. If some of the accounts that should have been closed by the bankruptcy are not closed, that will wreak additional havoc on your credit score. If you see issues, get them fixed.
If you have outstanding loans that have survived the bankruptcy, be certain you are meticulously making the payments on time. Get a secured credit card that requires a cash deposit and is commonly used to rebuild credit. If you make on-time minimum payments and maintain the account balance below the credit limit on the secured card, you will improve your credit rating. Proceed in this manner for at least a year before seeking to buy a car on credit.
Prospective buyers with a bankruptcy on their credit history will often be confronted with extremely high interest rates, but those interest rates can vary widely. If you have a good relationship with your bank or credit union, start your search for a car loan there.
Because of your bankruptcy history, you will be facing higher than average interest rates, so it is a poor financial decision to make the purchase even more expensive by considering a high-priced new car. As you rebuild your credit, your emphasis should be on modest transportation.
Once you have purchased a vehicle, be certain you make your payments on time. Don't give the dealer and/or the financial institution a reason to consider repossessing your vehicle. That would leave you without transportation and in worse financial straits than you were before the purchase.


Whether you about to travel to Vietnam for your adoption or returning to Vietnam - the Vietnam Travel section provides valuable travel advice and information. Packing, sightseeing, touring, author interviews, answers to common questions and so much more.
An introduction to the country, and links to the important sites in northern, central and southern Vietnam.
Author and scholar Dana Sachs provides advice for traveling to Vietnam, and the way adoption is viewed in Vietnam (Interview Allison Martin).
Award winning journalist David Lamb discusses the surprises he encountered in his return to Vietnam after so many year (Interview Allison Martin).
Author Dana Sachs describes her attraction for Vietnam and her favorite Vietnamese places (Interview Allison Martin).
Photojournalist Jim Gensheimer discusses the aftermath of pain of the war and the transformation of the Vietnamese people (Interview Allison Martin).
Enjoy these remarkable personal stories about Vietnam adoption trips.
Wow! Time to begin final preparations for your trip to Vietnam. But what to bring? Prepare yourself with these articles on packing for Vietnam travel.
From medical tips to jet leg, health articles for your travel to and within Vietnam.


Charles Baskerville is the latest victim of a centuries-old curse! Now, Henry Baskerville needs Sherlock Holmes' help to break the curse, before another murder occurs! Travel to legendary Baskerville Hall, and figure out exactly what is going on, and what the mysterious Hound of the Baskervilles is after. Crack the case in this incredible Hidden Object Puzzle Adventure game, Sherlock Holmes – Hound of the Baskervilles! This is a special Collector's Edition release full of exclusive extras you won't find in the standard version. As a bonus, Collector's Edition purchases count toward three stamps on your Monthly Game Club Punch Card!
Proposed to download game Sherlock Holmes and the Hound of the Baskervilles Collector's Edition scanned with anti-viruses and have no ads, no adware, no spyware inside. The "Play Hidden Objects" project thankful for your choice and wish to download Sherlock Holmes and the Hound of the Baskervilles Collector's Edition free from our server.


text:
//  LocalyticsSession.m
//  Copyright (C) 2012 Char Software Inc., DBA Localytics
//
//  This code is provided under the Localytics Modified BSD License.
//  A copy of this license has been distributed in a file called LICENSE
//  with this source code.
//
// Please visit www.localytics.com for more information.

#import "LocalyticsSession.h"
#import "WebserviceConstants.h"
#import "LocalyticsUploader.h"
#import "LocalyticsDatabase.h"

#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/mach.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <CommonCrypto/CommonDigest.h>

#pragma mark Constants
#define PREFERENCES_KEY             @"_localytics_install_id" // The randomly generated ID for each install of the app
#define CLIENT_VERSION              @"iOS_2.14"      // The version of this library
#define LOCALYTICS_DIR              @".localytics"	// The directory in which the Localytics database is stored
#define IFT_ETHER                   0x6             // Ethernet CSMACD
#define PATH_TO_APT                 @"/private/var/lib/apt/"

#define DEFAULT_BACKGROUND_SESSION_TIMEOUT 15   // Default value for how many seconds a session persists when App shifts to the background.

// The singleton session object.
static LocalyticsSession *_sharedLocalyticsSession = nil;

@interface LocalyticsSession()

@property (nonatomic, retain) NSString *sessionUUID;
@property (nonatomic, retain) NSString *applicationKey;
@property (nonatomic, assign) NSTimeInterval lastSessionStartTimestamp;
@property (nonatomic, retain) NSDate *sessionResumeTime;
@property (nonatomic, retain) NSDate *sessionCloseTime;
@property (nonatomic, retain) NSMutableString *unstagedFlowEvents;
@property (nonatomic, retain) NSMutableString *stagedFlowEvents;
@property (nonatomic, retain) NSMutableString *screens;
@property (nonatomic, assign) NSTimeInterval sessionActiveDuration;
@property (nonatomic, assign) BOOL sessionHasBeenOpen;
@property (nonatomic, assign) NSInteger sessionNumber;

// Private methods.
- (void)ll_open;
- (void)reopenPreviousSession;
- (void)addFlowEventWithName:(NSString *)name type:(NSString *)eventType;
- (void)addScreenWithName:(NSString *)name;
- (NSString *)blobHeaderStringWithSequenceNumber:(int)nextSequenceNumber;
- (BOOL)ll_isOptedIn;
- (BOOL)createOptEvent:(BOOL)optState;
- (BOOL)saveApplicationFlowAndRemoveOnResume:(BOOL)removeOnResume;
- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue;
- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue first:(BOOL)firstAttribute;
-(void) uploadCallback:(NSDictionary*)info;

// Datapoint methods.
- (NSString *)customDimensions;
- (NSString *)locationDimensions;
- (NSString *)hashString:(NSString *)input;
- (NSString *)randomUUID;
- (NSString *)escapeString:(NSString *)input;
- (NSString *)installationId;
- (NSString *)appVersion;
- (NSTimeInterval)currentTimestamp;
- (BOOL)isDeviceJailbroken;
- (NSString *)deviceModel;
- (NSString *)modelSizeString;
- (double)availableMemory;
- (NSString *)advertisingIdentifier;
- (NSString *)uniqueDeviceIdentifier;

@end

@implementation LocalyticsSession

@synthesize queue                       = _queue;
@synthesize criticalGroup               = _criticalGroup;
@synthesize sessionUUID                 = _sessionUUID;
@synthesize applicationKey              = _applicationKey;
@synthesize lastSessionStartTimestamp   = _lastSessionStartTimestamp;
@synthesize sessionResumeTime           = _sessionResumeTime;
@synthesize sessionCloseTime            = _sessionCloseTime;
@synthesize isSessionOpen               = _isSessionOpen;
@synthesize hasInitialized              = _hasInitialized;
@synthesize backgroundSessionTimeout    = _backgroundSessionTimeout;
@synthesize unstagedFlowEvents          = _unstagedFlowEvents;
@synthesize stagedFlowEvents            = _stagedFlowEvents;
@synthesize screens                     = _screens;
@synthesize sessionActiveDuration       = _sessionActiveDuration;
@synthesize sessionHasBeenOpen          = _sessionHasBeenOpen;
@synthesize sessionNumber               = _sessionNumber;
@synthesize enableHTTPS                 = _enableHTTPS;

// Stores the last location passed in to the app.
CLLocationCoordinate2D lastDeviceLocation = {0};

#pragma mark Singleton

+ (LocalyticsSession *)sharedLocalyticsSession {
	@synchronized(self) {
		if (_sharedLocalyticsSession == nil) {
			_sharedLocalyticsSession = [[self alloc] init];
		}
	}
	return _sharedLocalyticsSession;
}

- (LocalyticsSession *)init {
	if((self = [super init])) {
        _isSessionOpen  = NO;
        _hasInitialized = NO;
        _backgroundSessionTimeout = DEFAULT_BACKGROUND_SESSION_TIMEOUT;
        _sessionHasBeenOpen = NO;
        _queue = dispatch_queue_create("com.Localytics.operations", DISPATCH_QUEUE_SERIAL);
        _criticalGroup = dispatch_group_create();
        _enableHTTPS = NO;

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];

        [LocalyticsDatabase sharedLocalyticsDatabase];
    }

    return self;
}

#pragma mark Public Methods

- (void)LocalyticsSession:(NSString *)appKey {
	// If the session has already initialized, don't bother doing it again.
	if(self.hasInitialized)
	{
		[self logMessage:@"Object has already been initialized."];
		return;
	}

	@try {

        if(appKey == (id)[NSNull null] || appKey.length == 0) {
            [self logMessage:@"App key is null or empty."];
            self.hasInitialized = NO;
            return;
        }

        // App key should only be alphanumeric chars and dashes.
        NSString *trimmedAppKey = [appKey stringByReplacingOccurrencesOfString:@"-" withString:@""];
        if([[trimmedAppKey stringByTrimmingCharactersInSet:[NSCharacterSet alphanumericCharacterSet]] isEqualToString:@""] == false) {
            [self logMessage:@"App key may only contain dashes and alphanumeric characters."];
            self.hasInitialized = NO;
            return;
        }

        if ([LocalyticsDatabase sharedLocalyticsDatabase]) {
            // Check if the app key has changed.
            NSString *lastAppKey = [[LocalyticsDatabase sharedLocalyticsDatabase] appKey];
            if (![lastAppKey isEqualToString:appKey]) {
                if (lastAppKey) {
                    // Clear previous events and dimensions to guarantee that new data isn't associated with the old app key.
                    [[LocalyticsDatabase sharedLocalyticsDatabase] resetAnalyticsData];

                    // Vacuum to improve the odds of opening a new session following bulk delete.
                    [[LocalyticsDatabase sharedLocalyticsDatabase] vacuumIfRequired];
                }
                // Record the key for future checks.
                [[LocalyticsDatabase sharedLocalyticsDatabase] updateAppKey:appKey];
            }

            self.applicationKey = appKey;
            self.hasInitialized = YES;
            [self logMessage:[@"Object Initialized.  Application's key is: " stringByAppendingString:self.applicationKey]];
        }
	}
	@catch (NSException * e) {}
}

- (void)startSession:(NSString *)appKey {
  //check app key
  NSPredicate *matchPred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"[A-Fa-f0-9-]+"];
	BOOL matches = [matchPred evaluateWithObject:appKey];
  if (matches == NO) {
    //generate exception
    NSException *exception = [NSException exceptionWithName:@"Invalid Localytics App Key" reason:@"Application key is not valid. Please look at the iOS integration guidlines at http://www.localytics.com/docs/iphone-integration/" userInfo:nil];
    [exception raise];
  }

	[self LocalyticsSession:appKey];
	[self open];
	[self upload];
}

// Public interface to ll_open.
- (void)open {
    dispatch_async(_queue, ^{
        [self ll_open];
    });
}

- (BOOL)resume {

	// Do nothing if session is already open
	if(self.isSessionOpen == YES)
		return YES;

	BOOL ret = NO;
	// conditions for resuming previous session
	if(self.sessionHasBeenOpen &&
		 (!self.sessionCloseTime ||
			[self.sessionCloseTime timeIntervalSinceNow]*-1 <= self.backgroundSessionTimeout)) {
			 // Note that we allow the session to be resumed even if the database size exceeds the
			 // maximum. This is because we don't want to create incomplete sessions. If the DB was large
			 // enough that the previous session could not be opened, there will be nothing to resume. But
			 // if this session caused it to go over it is better to let it complete and stop the next one
			 // from being created.
			 ret = YES;
			 dispatch_async(_queue, ^{
				 @try {
					 if([self ll_isOptedIn] == false) {
						 [self logMessage:@"Can't resume session because user is opted out."];
					 } else {
						 [self logMessage:@"Resume called - Resuming previous session."];
						 [self reopenPreviousSession];
					 }
				 }
				 @catch (NSException * e) {}
			 });

		 } else {
			 ret = NO;
			 dispatch_async(_queue, ^{
				 @try {
					 if([self ll_isOptedIn] == false) {
						 [self logMessage:@"Can't resume session because user is opted out."];
					 } else {
						 // otherwise open new session and upload
						 [self logMessage:@"Resume called - Opening a new session."];
						 [self ll_open];
					 }
				 }
				 @catch (NSException * e) {}
			 });

		 }
	self.sessionCloseTime = nil;
	return ret;
}

- (void)close {
    dispatch_group_async(_criticalGroup, _queue, ^{
        // Do nothing if the session is not open
        if (self.isSessionOpen == NO) {
            [self logMessage:@"Unable to close session"];
            return;
        }

        // Save time of close
        self.sessionCloseTime = [NSDate date];

        // Update active session duration.
        self.sessionActiveDuration += [self.sessionCloseTime timeIntervalSinceDate:self.sessionResumeTime];

        int sessionLength = (int)[[NSDate date] timeIntervalSince1970] - self.lastSessionStartTimestamp;

        @try {
            // Create the JSON representing the close blob
            NSMutableString *closeEventString = [NSMutableString string];
            [closeEventString appendString:@"{"];
            [closeEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE         value:@"c"                      first:YES]];
            [closeEventString appendString:[self formatAttributeWithName:PARAM_SESSION_UUID      value:self.sessionUUID]];
            [closeEventString appendString:[self formatAttributeWithName:PARAM_UUID              value:[self randomUUID] ]];
            [closeEventString appendFormat:@",\"%@\":%ld", PARAM_SESSION_START, (long)self.lastSessionStartTimestamp];
            [closeEventString appendFormat:@",\"%@\":%ld", PARAM_SESSION_ACTIVE, (long)self.sessionActiveDuration];
            [closeEventString appendFormat:@",\"%@\":%ld", PARAM_CLIENT_TIME, (long)[self currentTimestamp]];

            // Avoid recording session lengths of users with unreasonable client times (usually caused by developers testing clock change attacks)
            if(sessionLength > 0 && sessionLength < 400000) {
                [closeEventString appendFormat:@",\"%@\":%d", PARAM_SESSION_TOTAL, sessionLength];
            }

            // Open second level - screen flow
            [closeEventString appendFormat:@",\"%@\":[", PARAM_SESSION_SCREENFLOW];
            [closeEventString appendString:self.screens];

            // Close second level - screen flow
            [closeEventString appendString:@"]"];

            // Append the custom dimensions
            [closeEventString appendString:[self customDimensions]];

            // Append the location
            [closeEventString appendString:[self locationDimensions]];

            // Close first level - close blob
            [closeEventString appendString:@"}\n"];

            BOOL success = [[LocalyticsDatabase sharedLocalyticsDatabase] queueCloseEventWithBlobString:[[closeEventString copy] autorelease]];

            self.isSessionOpen = NO;  // Session is no longer open.

            if (success) {
                [self logMessage:@"Session succesfully closed."];
            } else {
                [self logMessage:@"Failed to record session close."];
            }
        }
        @catch (NSException * e) {}
    });
}

- (void)setOptIn:(BOOL)optedIn {
    dispatch_async(_queue, ^{
        @try {
            LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
            NSString *t = @"set_opt";
            BOOL success = [db beginTransaction:t];

            // Write out opt event.
            if (success) {
                success =  [self createOptEvent:optedIn];
            }

            // Update database with the option (stored internally as an opt-out).
            if (success) {
                [db setOptedOut:optedIn == NO];
            }

            if (success && optedIn == NO) {
                // Disable all further Localytics calls for this and future sessions
                // This should not be flipped when the session is opted back in because that
                // would create an incomplete session.
                self.isSessionOpen = NO;
            }

            if (success) {
                [db releaseTransaction:t];
                [self logMessage:[NSString stringWithFormat:@"Application opted %@", optedIn ? @"in" : @"out"]];
            } else {
                [db rollbackTransaction:t];
                [self logMessage:@"Failed to update opt state."];
            }
        }
        @catch (NSException * e) {}
    });
}

// Public interface to ll_isOptedIn.
- (BOOL)isOptedIn {
    __block BOOL optedIn = YES;
    dispatch_sync(_queue, ^{
        optedIn = [self ll_isOptedIn];
    });
    return optedIn;
}

// A convenience function for users who don't wish to add attributes.
- (void)tagEvent:(NSString *)event {
	[self tagEvent:event attributes:nil reportAttributes:nil];
}

// Most users should use this tagEvent call.
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes {
	[self tagEvent:event attributes:attributes reportAttributes:nil];
}

- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes reportAttributes:(NSDictionary *)reportAttributes {
    dispatch_async(_queue, ^{
        @try {
            // Do nothing if the session is not open.
            if (self.isSessionOpen == NO)
            {
                [self logMessage:@"Cannot tag an event because the session is not open."];
                return;
            }

            if(event == (id)[NSNull null] || event.length == 0)
            {
                [self logMessage:@"Event tagged without a name. Skipping."];
                return;
            }

            // Create the JSON for the event
            NSMutableString *eventString = [[[NSMutableString alloc] init] autorelease];
            [eventString appendString:@"{"];
            [eventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE     value:@"e" first:YES] ];
            [eventString appendString:[self formatAttributeWithName:PARAM_UUID          value:[self randomUUID] ]];
            [eventString appendString:[self formatAttributeWithName:PARAM_APP_KEY       value:self.applicationKey ]];
            [eventString appendString:[self formatAttributeWithName:PARAM_SESSION_UUID  value:self.sessionUUID ]];
            [eventString appendString:[self formatAttributeWithName:PARAM_EVENT_NAME    value:[self escapeString:event] ]];
            [eventString appendFormat:@",\"%@\":%ld", PARAM_CLIENT_TIME, (long)[self currentTimestamp]];

            // Append the custom dimensions
            [eventString appendString:[self customDimensions]];

            // Append the location
            [eventString appendString:[self locationDimensions]];

            // If there are any attributes for this event, add them as a hash
            int attrIndex = 0;
            if(attributes != nil)
            {
                // Open second level - attributes
                [eventString appendString:[NSString stringWithFormat:@",\"%@\":{", PARAM_ATTRIBUTES]];
                for (id key in [attributes allKeys])
                {
                    // Have to escape paramName and paramValue because they user-defined.
                    [eventString appendString:
                     [self formatAttributeWithName:[self escapeString:[key description]]
                                             value:[self escapeString:[[attributes valueForKey:key] description]]
                                             first:(attrIndex == 0)]];
                    attrIndex++;
                }

                // Close second level - attributes
                [eventString appendString:@"}"];
            }

            // If there are any report attributes for this event, add them as above
            attrIndex = 0;
            if(reportAttributes != nil)
            {
                [eventString appendString:[NSString stringWithFormat:@",\"%@\":{", PARAM_REPORT_ATTRIBUTES]];
                for(id key in [reportAttributes allKeys]) {
                    [eventString appendString:
                     [self formatAttributeWithName:[self escapeString:[key description]]
                                             value:[self escapeString:[[reportAttributes valueForKey:key] description]]
                                             first:(attrIndex == 0)]];
                    attrIndex++;
                }
                [eventString appendString:@"}"];
            }

            // Close first level - Event information
            [eventString appendString:@"}\n"];

            BOOL success = [[LocalyticsDatabase sharedLocalyticsDatabase] addEventWithBlobString:[[eventString copy] autorelease]];
            if (success) {
                // User-originated events should be tracked as application flow.
                [self addFlowEventWithName:event type:@"e"]; // "e" for Event.

                [self ampTrigger:event];

                [self logMessage:[@"Tagged event: " stringByAppendingString:event]];
            } else {
                [self logMessage:@"Failed to tag event."];
            }
        }
        @catch (NSException * e) {}
    });
}

- (void)tagScreen:(NSString *)screen {
    dispatch_async(_queue, ^{
        // Do nothing if the session is not open.
        if (self.isSessionOpen == NO)
        {
            [self logMessage:@"Cannot tag a screen because the session is not open."];
            return;
        }

        // Tag screen with description to enforce string type and avoid retaining objects passed by clients in lieu of a
        // screen name.
        NSString *screenName = [screen description];
        [self addFlowEventWithName:screenName type:@"s"]; // "s" for Screen.

        // Maintain a parallel list of only screen names. This is submitted in the session close event.
        // This may be removed in a future version of the client library.
        [self addScreenWithName:screenName];

        [self logMessage:[@"Tagged screen: " stringByAppendingString:screenName]];
    });
}

- (void)setLocation:(CLLocationCoordinate2D)deviceLocation {
    lastDeviceLocation = deviceLocation;
    [self logMessage:@"Setting Location"];
}

- (void)setCustomDimension:(int)dimension value:(NSString *)value {
    dispatch_async(_queue, ^{
        if(dimension < 0 || dimension > 3) {
            [self logMessage:@"Only valid dimensions are 0 - 3"];
            return;
        }

        if(false == [[LocalyticsDatabase sharedLocalyticsDatabase] setCustomDimension:dimension value:value]) {
            [self logMessage:@"Unable to set custom dimensions."];
        }
    });
}

- (void)upload {
    dispatch_group_async(_criticalGroup, _queue, ^{
        @try {
            if ([[LocalyticsUploader sharedLocalyticsUploader] isUploading]) {
                [self logMessage:@"An upload is already in progress. Aborting."];
                return;
            }

            NSString *t = @"stage_upload";
            LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
            BOOL success = [db beginTransaction:t];

            // - The event list for the current session is not modified
            // New flow events are only transitioned to the "old" list if the upload is staged successfully. The queue
            // ensures that the list of events are not modified while a call to upload is in progress.
            if (success) {
                // Write flow blob to database. This is for a session in progress and should not be removed upon resume.
                success = [self saveApplicationFlowAndRemoveOnResume:NO];
            }

            if (success && [db unstagedEventCount] > 0) {
                // Increment upload sequence number.
                int sequenceNumber = 0;
                success = [db incrementLastUploadNumber:&sequenceNumber];

                // Write out header to database.
                sqlite3_int64 headerRowId = 0;
                if (success) {
                    NSString *headerBlob = [self blobHeaderStringWithSequenceNumber:sequenceNumber];
                    success = [db addHeaderWithSequenceNumber:sequenceNumber blobString:headerBlob rowId:&headerRowId];
                }

                // Associate unstaged events.
                if (success) {
                    success = [db stageEventsForUpload:headerRowId];
                }
            }

            if (success) {
                // Complete transaction
                [db releaseTransaction:t];

                // Move new flow events to the old flow event array.
                if (self.unstagedFlowEvents.length) {
                    if (self.stagedFlowEvents.length) {
                        [self.stagedFlowEvents appendFormat:@",%@", self.unstagedFlowEvents];
                    } else {
                        self.stagedFlowEvents = [[self.unstagedFlowEvents mutableCopy] autorelease];
                    }
                    self.unstagedFlowEvents = [NSMutableString string];
                }

                // Begin upload.
               [[LocalyticsUploader sharedLocalyticsUploader] uploaderWithApplicationKey:self.applicationKey useHTTPS:[self enableHTTPS] installId:[self installationId] resultTarget:self callback:@selector(uploadCallback:)];
            } else {
                [db rollbackTransaction:t];
                [self logMessage:@"Failed to start upload."];
            }
        }
        @catch (NSException * e) { }
    });
}

#pragma mark Private Methods

-(NSString*)libraryVersion {
	return CLIENT_VERSION;
}

-(void) uploadCallback:(NSDictionary*)info{
}

- (void)dequeueCloseEventBlobString
{
   LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
   NSString *closeEventString = [db dequeueCloseEventBlobString];
   if (closeEventString) {
      BOOL success = [db addCloseEventWithBlobString:closeEventString];
      if (!success) {
         // Re-queue the close event.
         [db queueCloseEventWithBlobString:closeEventString];
      }
   }
}

- (void)ll_open {
    // There are a number of conditions in which nothing should be done:
    if (self.hasInitialized == NO ||  // the session object has not yet initialized
        self.isSessionOpen == YES)  // session has already been opened
    {
        [self logMessage:@"Unable to open session."];
        return;
    }

    if([self ll_isOptedIn] == false) {
        [self logMessage:@"Can't open session because user is opted out."];
        return;
    }

    @try {
        // If there is too much data on the disk, don't bother collecting any more.
        LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
        if([db databaseSize] > MAX_DATABASE_SIZE) {
            [self logMessage:@"Database has exceeded the maximum size. Session not opened."];
            self.isSessionOpen = NO;
            return;
        }

        [self dequeueCloseEventBlobString];

        self.sessionActiveDuration = 0;
        self.sessionResumeTime = [NSDate date];
        self.unstagedFlowEvents = [NSMutableString string];
        self.stagedFlowEvents = [NSMutableString string];
        self.screens = [NSMutableString string];

        // Begin transaction for session open.
        NSString *t = @"open_session";
        BOOL success = [db beginTransaction:t];

        // lastSessionStartTimestamp isn't really the last session start time.
        // It's the sessionResumeTime which is [NSDate date] or now. Therefore,
        // save the current lastSessionTimestamp value from the database so it
        // can be used to calculate the elapsed time between session start times.
        NSTimeInterval previousSessionStartTimeInterval = [db lastSessionStartTimestamp];

        // Save session start time.
        self.lastSessionStartTimestamp = [self.sessionResumeTime timeIntervalSince1970];
        if (success) {
            success = [db setLastsessionStartTimestamp:self.lastSessionStartTimestamp];
        }

        // Retrieve next session number.
        int sessionNumber = 0;
        if (success) {
            success = [db incrementLastSessionNumber:&sessionNumber];
        }
       [self setSessionNumber:sessionNumber];

        if (success) {
            // Prepare session open event.
            self.sessionUUID = [self randomUUID];

            // Store event.
            NSMutableString *openEventString = [NSMutableString string];
            [openEventString appendString:@"{"];
            [openEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE              value:@"s"              first:YES]];
            [openEventString appendString:[self formatAttributeWithName:PARAM_NEW_SESSION_UUID           value:self.sessionUUID]];
            [openEventString appendFormat:@",\"%@\":%ld", PARAM_CLIENT_TIME, (long)self.lastSessionStartTimestamp];
            [openEventString appendFormat:@",\"%@\":%d", PARAM_SESSION_NUMBER, sessionNumber];

            double elapsedTime = 0.0;
            if (previousSessionStartTimeInterval > 0) {
               elapsedTime = [self lastSessionStartTimestamp] - previousSessionStartTimeInterval;
            }
            NSString *elapsedTimeString = [NSString stringWithFormat:@"%.0f", elapsedTime];
            [openEventString appendString:[self formatAttributeWithName:PARAM_SESSION_ELAPSE_TIME value:elapsedTimeString]];

            [openEventString appendString:[self customDimensions]];
            [openEventString appendString:[self locationDimensions]];

            [openEventString appendString:@"}\n"];

            [self customDimensions];

            success = [db addEventWithBlobString:[[openEventString copy] autorelease]];
        }

        if (success) {
            [db releaseTransaction:t];
            self.isSessionOpen = YES;
            self.sessionHasBeenOpen = YES;
            [self logMessage:[@"Succesfully opened session. UUID is: " stringByAppendingString:self.sessionUUID]];
        } else {
            [db rollbackTransaction:t];
            self.isSessionOpen = NO;
            [self logMessage:@"Failed to open session."];
        }
    }
    @catch (NSException * e) {}
}

/*!
 @method reopenPreviousSession
 @abstract Reopens the previous session, using previous session variables. If there was no previous session, do nothing.
*/
- (void)reopenPreviousSession {
    if(self.sessionHasBeenOpen == NO){
        [self logMessage:@"Unable to reopen previous session, because a previous session was never opened."];
    return;
    }

    // Record session resume time.
    self.sessionResumeTime = [NSDate date];

    //Remove close and flow events if they exist.
    [[LocalyticsDatabase sharedLocalyticsDatabase] removeLastCloseAndFlowEvents];

    self.isSessionOpen = YES;
}

/*!
 @method addFlowEventWithName:type:
 @abstract Adds a simple key-value pair to the list of events tagged during this session.
 @param name The name of the tagged event.
 @param eventType A key representing the type of the tagged event. Either "s" for Screen or "e" for Event.
 */
- (void)addFlowEventWithName:(NSString *)name type:(NSString *)eventType {
    if (!name || !eventType)
        return;

    // Format new event as simple key-value dictionary.
    NSString *eventString = [self formatAttributeWithName:eventType value:[self escapeString:name] first:YES];

    // Flow events are uploaded as a sequence of key-value pairs. Wrap the above in braces and append to the list.
    BOOL previousFlowEvents = self.unstagedFlowEvents.length > 0;
    if (previousFlowEvents) {
        [self.unstagedFlowEvents appendString:@","];
    }
    [self.unstagedFlowEvents appendFormat:@"{%@}", eventString];
}

/*!
 @method addScreenWithName:
 @abstract Adds a name to list of screens encountered during this session.
 @discussion The complete list of names is sent with the session close event. Screen names are stored in parallel to the
 screen flow events list and may be removed in future versions of this library.
 @param name The name of the tagged screen.
 */
- (void)addScreenWithName:(NSString *)name {
    if (self.screens.length > 0) {
        [self.screens appendString:@","];
    }
    [self.screens appendFormat:@"\"%@\"", [self escapeString:name]];
}

/*!
 @method blobHeaderStringWithSequenceNumber:
 @abstract Creates the JSON string for the upload blob header, substituting in the given upload sequence number.
 @param  nextSequenceNumber The sequence number for the current upload attempt.
 @return The upload header JSON blob.
 */
- (NSString *)blobHeaderStringWithSequenceNumber:(int)nextSequenceNumber {

    NSMutableString *headerString = [[[NSMutableString alloc] init] autorelease];

    // Common header information.
	UIDevice *thisDevice = [UIDevice currentDevice];
	NSLocale *locale = [NSLocale currentLocale];
	NSLocale *english = [[[NSLocale alloc] initWithLocaleIdentifier: @"en_US"] autorelease];
	NSLocale *device_locale = [[NSLocale preferredLanguages] objectAtIndex:0];
    NSString *device_language = [english displayNameForKey:NSLocaleIdentifier value:device_locale];
	NSString *locale_country = [english displayNameForKey:NSLocaleCountryCode value:[locale objectForKey:NSLocaleCountryCode]];
    NSString *uuid = [self randomUUID];
	NSString *device_uuid = [self uniqueDeviceIdentifier];
  NSString *device_adid = [self advertisingIdentifier];

    // Open first level - blob information
    [headerString appendString:@"{"];
    [headerString appendFormat:@"\"%@\":%d", PARAM_SEQUENCE_NUMBER, nextSequenceNumber];
    [headerString appendFormat:@",\"%@\":%ld", PARAM_PERSISTED_AT, (long)[[LocalyticsDatabase sharedLocalyticsDatabase] createdTimestamp]];
    [headerString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE    value:@"h" ]];
    [headerString appendString:[self formatAttributeWithName:PARAM_UUID         value:uuid ]];

    // Open second level - blob header attributes
    [headerString appendString:[NSString stringWithFormat:@",\"%@\":{", PARAM_ATTRIBUTES]];
    [headerString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE    value:@"a"  first:YES]];

	// >>  Application and session information
    [headerString appendString:[self formatAttributeWithName:PARAM_INSTALL_ID       value:[self installationId] ]];
	[headerString appendString:[self formatAttributeWithName:PARAM_APP_KEY          value:self.applicationKey ]];
	[headerString appendString:[self formatAttributeWithName:PARAM_APP_VERSION      value:[self appVersion]  ]];
	[headerString appendString:[self formatAttributeWithName:PARAM_LIBRARY_VERSION  value:[self libraryVersion]        ]];

    // >>  Device Information
	if (device_uuid) {
		[headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_UUID_HASHED   value:[self hashString:device_uuid] ]];
	}
  if (device_adid) {
    [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_ADID value:device_adid]];
  }
	[headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_PLATFORM      value:[thisDevice model]            ]];
	[headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_OS_VERSION    value:[thisDevice systemVersion]    ]];
	[headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_MODEL         value:[self deviceModel]         ]];

// MAC Address collection. Uncomment the following line to add Mac address to the mix of collected identifiers
//    [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_MAC value:[self hashString:[self macAddress]]     ]];
	[headerString appendString:[NSString stringWithFormat:@",\"%@\":%ld", PARAM_DEVICE_MEMORY, (long)[self availableMemory]  ]];
	[headerString appendString:[self formatAttributeWithName:PARAM_LOCALE_LANGUAGE   value:device_language]];
	[headerString appendString:[self formatAttributeWithName:PARAM_LOCALE_COUNTRY    value:locale_country]];
	[headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_COUNTRY    value:[locale objectForKey:NSLocaleCountryCode]]];
	[headerString appendString:[NSString stringWithFormat:@",\"%@\":%@", PARAM_JAILBROKEN, [self isDeviceJailbroken] ? @"true" : @"false"]];

    //  Close second level - attributes
    [headerString appendString:@"}"];

    // Close first level - blob information
    [headerString appendString:@"}\n"];

	return [[headerString copy] autorelease];
}

- (BOOL)ll_isOptedIn {
    return [[LocalyticsDatabase sharedLocalyticsDatabase] isOptedOut] == NO;
}

/*!
 @method createOptEvent:
 @abstract Generates the JSON for an opt event (user opting in or out) and writes it to the database.
 @return YES if the event was written to the database, NO otherwise
 */
- (BOOL)createOptEvent:(BOOL)optState {
	NSMutableString *optEventString = [NSMutableString string];
    [optEventString appendString:@"{"];
    [optEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE  value:@"o"                  first:YES]];
	[optEventString appendString:[self formatAttributeWithName:PARAM_UUID         value:[self randomUUID] first:NO ]];
	[optEventString appendString:[NSString stringWithFormat:@",\"%@\":%@", PARAM_OPT_VALUE, (optState ? @"false" : @"true") ]];	//this actually transmits the opposite of the opt state. The JSON contains whether the user is opted out, not whether the user is opted in.
    [optEventString appendFormat:@",\"%@\":%ld", PARAM_CLIENT_TIME, (long)[self currentTimestamp]];
	[optEventString appendString:@"}\n"];

    BOOL success = [[LocalyticsDatabase sharedLocalyticsDatabase] addEventWithBlobString:[[optEventString copy] autorelease]];
    return success;
}

/*
 @method saveApplicationFlowAndRemoveOnResume:
 @abstract Constructs an application flow blob string and writes it to the database, optionally flagging it for deletion
 if the session is resumed.
 @param removeOnResume YES if the application flow blob should be deleted if the session is resumed.
 @return YES if the application flow event was written to the database successfully.
 */
- (BOOL)saveApplicationFlowAndRemoveOnResume:(BOOL)removeOnResume {
    BOOL success = YES;

    // If there are no new events, then there is nothing additional to save.
    if (self.unstagedFlowEvents.length) {
        // Flows are uploaded as a distinct blob type containing arrays of new and previously-uploaded event and
        // screen names. Write a flow event to the database.
        NSMutableString *flowEventString = [[[NSMutableString alloc] init] autorelease];

        // Open first level - flow blob event
        [flowEventString appendString:@"{"];
        [flowEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"f"                  first:YES]];
        [flowEventString appendString:[self formatAttributeWithName:PARAM_UUID      value:[self randomUUID] ]];
        [flowEventString appendFormat:@",\"%@\":%ld", PARAM_SESSION_START, (long)self.lastSessionStartTimestamp];

        // Open second level - new flow events
        [flowEventString appendFormat:@",\"%@\":[", PARAM_NEW_FLOW_EVENTS];
        [flowEventString appendString:self.unstagedFlowEvents]; // Flow events are escaped in |-addFlowEventWithName:|
        // Close second level - new flow events
        [flowEventString appendString:@"]"];

        // Open second level - old flow events
        [flowEventString appendFormat:@",\"%@\":[", PARAM_OLD_FLOW_EVENTS];
        [flowEventString appendString:self.stagedFlowEvents];
        // Close second level - old flow events
        [flowEventString appendString:@"]"];

        // Close first level - flow blob event
        [flowEventString appendString:@"}\n"];

        success = [[LocalyticsDatabase sharedLocalyticsDatabase] addFlowEventWithBlobString:[[flowEventString copy] autorelease]];
    }
    return success;
}

// Convenience method for formatAttributeWithName which sets firstAttribute to NO since
// this is the most common way to call it.
- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue {
    return [self formatAttributeWithName:paramName value:paramValue first:NO];
}

/*!
 @method formatAttributeWithName:value:firstAttribute:
 @abstract Returns the given string key/value pair as a JSON string.
 @param paramName The name of the parameter
 @param paramValue The value of the parameter
 @param firstAttribute YES if this attribute is first in an attribute list
 @return a JSON string which can be dumped to the JSON file
 */
- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue first:(BOOL)firstAttribute {
	// The expected result is one of:
    //  "paramname":"paramvalue"
    //  "paramname":null
    NSMutableString *formattedString = [NSMutableString string];
    if (!firstAttribute) {
        [formattedString appendString:@","];
    }

    NSString *quotedString = @"\"%@\"";
    paramName = [NSString stringWithFormat:quotedString, paramName];
    paramValue = paramValue ? [NSString stringWithFormat:quotedString, paramValue] : @"null";
    [formattedString appendFormat:@"%@:%@", paramName, paramValue];
	return [[formattedString copy] autorelease];
}

/*!
 @method escapeString
 @abstract Formats the input string so it fits nicely in a JSON document.  This includes
 escaping double quote and slash characters.
 @return The escaped version of the input string
 */
- (NSString *)escapeString:(NSString *)input
{
	NSString *output = [input stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
	output = [output stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
	output = [output stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"];
  output = [output stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
  output = [output stringByReplacingOccurrencesOfString:@"\t" withString:@"\\t"];
  output = [output stringByReplacingOccurrencesOfString:@"\b" withString:@"\\b"];
  output = [output stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
  output = [output stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"];
  output = [output stringByReplacingOccurrencesOfString:@"\v" withString:@"\\v"];
   return output;
}

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
    [self logMessage:@"Application entered the background."];

    // Continue executing until critical blocks finish executing or background time runs out, whichever comes first.
    UIApplication *application = (UIApplication *)[notification object];
    __block UIBackgroundTaskIdentifier taskID = [application beginBackgroundTaskWithExpirationHandler:^{
        // Synchronize with the main queue in case the the tasks finish at the same time as the expiration handler.
        dispatch_async(dispatch_get_main_queue(), ^{
            if (taskID != UIBackgroundTaskInvalid) {
                [self logMessage:@"Failed to finish executing critical tasks. Cleaning up."];
                [application endBackgroundTask:taskID];
                taskID = UIBackgroundTaskInvalid;
            }
        });
    }];

    // Critical tasks have finished. Expire the background task.
    dispatch_group_notify(_criticalGroup, dispatch_get_main_queue(), ^{
        [self logMessage:@"Finished executing critical tasks."];
        if (taskID != UIBackgroundTaskInvalid) {
            [application endBackgroundTask:taskID];
            taskID = UIBackgroundTaskInvalid;
        }
    });
}

/*!
 @method logMessage
 @abstract Logs a message with (localytics) prepended to it.
 @param message The message to log
 */
- (void)logMessage:(NSString *)message
{
    if(DO_LOCALYTICS_LOGGING) {
        NSLog(@"(localytics) %s\n", [message UTF8String]);
    }
}

#pragma mark Datapoint Functions
/*!
 @method customDimensions
 @abstract Returns the json blob containing the custom dimensions. Assumes this will be appended
 to an existing blob and as a result prepends the results with a comma.
 */
- (NSString *)customDimensions
{
    NSMutableString *dimensions = [[[NSMutableString alloc] init] autorelease];

    for(int i=0; i <4; i++) {
        NSString *dimension = [[LocalyticsDatabase sharedLocalyticsDatabase] customDimension:i];
        if(dimension) {
            [dimensions appendFormat:@",\"c%i\":\"%@\"", i, dimension];
        }
    }

    return [[dimensions copy] autorelease];
}

/*!
 @method locationDimensions
 @abstract Returns the json blob containing the current location if available or nil if no location is available.
 */
- (NSString *)locationDimensions
{
    if(lastDeviceLocation.latitude == 0 || lastDeviceLocation.longitude == 0) {
        return @"";
    }

    return [NSString stringWithFormat:@",\"lat\":%f,\"lng\":%f",
            lastDeviceLocation.latitude,
            lastDeviceLocation.longitude];

    return [NSString stringWithFormat:@"%lf", lastDeviceLocation.latitude];
}

/*!
 @method macAddress
 @abstract Returns the macAddress of this device.
 */
- (NSString *)macAddress
{
    NSMutableString* result = [NSMutableString string];

    BOOL success;
    struct ifaddrs* addrs;
    const struct ifaddrs* cursor;
    const struct sockaddr_dl* dlAddr;
    const uint8_t * base;
    int i;

    success = (getifaddrs(&addrs) == 0);
    if(success)
    {
        cursor = addrs;
        while(cursor != NULL)
        {
            if((cursor->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl *) cursor->ifa_addr)->sdl_type == IFT_ETHER))
            {
                dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr;
                base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen];

                for(i=0; i<dlAddr->sdl_alen; i++)
                {
                    if(i != 0) {
                        [result appendString:@":"];
                    }
                    [result appendFormat:@"%02x", base[i]];
                }
                break;
            }
            cursor = cursor->ifa_next;
        }
        freeifaddrs(addrs);
    }

    return result;
}

/*!
 @method hashString
 @abstract SHA1 Hashes a string
 */
- (NSString *)hashString:(NSString *)input
{
    NSData *stringBytes = [input dataUsingEncoding: NSUTF8StringEncoding];
    unsigned char digest[CC_SHA1_DIGEST_LENGTH];

    if (CC_SHA1([stringBytes bytes], [stringBytes length], digest)) {
        NSMutableString* hashedUUID = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
        for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
            [hashedUUID appendFormat:@"%02x", digest[i]];
        }
        return hashedUUID;
    }

    return nil;
}

/*!
 @method randomUUID
 @abstract Generates a random UUID
 @return NSString containing the new UUID
 */
- (NSString *)randomUUID {
	CFUUIDRef theUUID = CFUUIDCreate(NULL);
	CFStringRef stringUUID = CFUUIDCreateString(NULL, theUUID);
	CFRelease(theUUID);
	return [(NSString *)stringUUID autorelease];
}

/*!
 @method installationId
 @abstract Looks in user preferences for an ID unique to this installation. If one is not
 found it checks if one happens to be in the database (carroyover from older version of the db)
 if not, it generates one.
 @return A string uniquely identifying this installation of this app
 */
- (NSString *) installationId {
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSString *installId = [prefs stringForKey:PREFERENCES_KEY];

    if(installId == nil)
    {
        [self logMessage:@"Install ID not found in preferences, checking DB"];
        installId = [[LocalyticsDatabase sharedLocalyticsDatabase] installId];
    }

    // If it hasn't been found yet, generate a new one.
    if(installId == nil)
    {
        [self logMessage:@"Install ID not find one in database, generating a new one."];
        installId = [self randomUUID];
    }

    // Store the newly generated installId
    [prefs setObject:installId forKey:PREFERENCES_KEY];
    [[NSUserDefaults standardUserDefaults] synchronize];

    return installId;
}

/*!
 @method uniqueDeviceIdentifier
 @abstract A unique device identifier is a hash value composed from various hardware identifiers such
 as the device's serial number. It is guaranteed to be unique for every device but cannot
 be tied to a user account. [UIDevice Class Reference]
 @return An 1-way hashed identifier unique to this device.
 */
- (NSString *)uniqueDeviceIdentifier {

	NSString *systemId = nil;
	// We collect it as long as it is available along with a randomly generated ID.
	// This way, when this becomes unavailable we can map existing users so the
	// new vs returning counts do not break.
	//only do this if the OS is less than 6.0
  if (([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0f)) {
		SEL udidSelector = NSSelectorFromString(@"uniqueIdentifier");
		if ([[UIDevice currentDevice] respondsToSelector:udidSelector]) {
			systemId = [[UIDevice currentDevice] performSelector:udidSelector];
		}
	}
	return systemId;
}

/*!
 @method advertisingIdentifier
 @abstract An alphanumeric string unique to each device, used for advertising only.
 From UIDevice documentation.

 @return An identifier unique to this device.
 */
- (NSString *)advertisingIdentifier {
  NSString *adId = nil;
	Class advertisingClass = NSClassFromString(@"ASIdentifierManager");
	if (advertisingClass) {
		SEL adidSelector = NSSelectorFromString(@"advertisingIdentifier");
    adId = [[[advertisingClass performSelector:NSSelectorFromString(@"sharedManager")] performSelector:adidSelector] performSelector:NSSelectorFromString(@"UUIDString")];
	}
	return adId;
}

/*!
 @method appVersion
 @abstract Gets the pretty string for this application's version.
 @return The application's version as a pretty string
 */
- (NSString *)appVersion {
	return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
}

/*!
 @method currentTimestamp
 @abstract Gets the current time as seconds since Unix epoch.
 @return an NSTimeInterval time.
 */
- (NSTimeInterval)currentTimestamp {
    return [[NSDate date] timeIntervalSince1970];
}

/*!
 @method isDeviceJailbroken
 @abstract checks for the existance of apt to determine whether the user is running any
 of the jailbroken app sources.
 @return whether or not the device is jailbroken.
 */
- (BOOL) isDeviceJailbroken {
	NSFileManager *sessionFileManager = [NSFileManager defaultManager];
	return [sessionFileManager fileExistsAtPath:PATH_TO_APT];
}

/*!
 @method deviceModel
 @abstract Gets the device model string.
 @return a platform string identifying the device
 */
- (NSString *)deviceModel {
	char *buffer[256] = { 0 };
	size_t size = sizeof(buffer);
    sysctlbyname("hw.machine", buffer, &size, NULL, 0);
    NSString *platform = [NSString stringWithCString:(const char*)buffer
											encoding:NSUTF8StringEncoding];
	return platform;
}

/*!
 @method modelSizeString
 @abstract Checks how much disk space is reported and uses that to determine the model
 @return A string identifying the model, e.g. 8GB, 16GB, etc
 */
- (NSString *) modelSizeString {

#if TARGET_IPHONE_SIMULATOR
	return @"simulator";
#endif

	// User partition
	NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSDictionary *stats = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[path lastObject] error:nil];
	uint64_t user = [[stats objectForKey:NSFileSystemSize] longLongValue];

	// System partition
	path = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSSystemDomainMask, YES);
    stats = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[path lastObject] error:nil];
	uint64_t system = [[stats objectForKey:NSFileSystemSize] longLongValue];

	// Add up and convert to gigabytes
	// TODO: seem to be missing a system partiton or two...
	NSInteger size = (user + system) >> 30;

	// Find nearest power of 2 (eg, 1,2,4,8,16,32,etc).  Over 64 and we return 0
	for (NSInteger gig = 1; gig < 257; gig = gig << 1) {
		if (size < gig)
			return [NSString stringWithFormat:@"%dGB", gig];
	}
	return nil;
}

/*!
 @method availableMemory
 @abstract Reports how much memory is available
 @return A double containing the available free memory
 */
- (double)availableMemory {
	double result = NSNotFound;
	vm_statistics_data_t stats;
	mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
	if (!host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&stats, &count))
		result = vm_page_size * stats.free_count;

	return result;
}

#pragma mark System Functions
+ (id)allocWithZone:(NSZone *)zone {
	@synchronized(self) {
		if (_sharedLocalyticsSession == nil) {
			_sharedLocalyticsSession = [super allocWithZone:zone];
			return _sharedLocalyticsSession;
		}
	}
	// returns nil on subsequent allocations
	return nil;
}

- (id)copyWithZone:(NSZone *)zone {
	return self;
}

- (id)retain {
	return self;
}

- (unsigned)retainCount {
	// maximum value of an unsigned int - prevents additional retains for the class
	return UINT_MAX;
}

- (oneway void)release {
	// ignore release commands
}

- (id)autorelease {
	return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];

    dispatch_release(_criticalGroup);
    dispatch_release(_queue);
	[_sessionUUID release];
	[_applicationKey release];
	[_sessionCloseTime release];
    [_unstagedFlowEvents release];
    [_stagedFlowEvents release];
    [_screens release];
	[_sharedLocalyticsSession release];

	[super dealloc];
}

#pragma mark - AMP stub
- (void)ampTrigger:(NSString *)event {
  //do nothing
}

@end

redpajama_set_name: RedPajamaGithub


Has anyone ever driven their smart car naked... hmm?
You know... it would be really cool to put an opt in announce list for people who want to be reminded of such things, but who forget (like me). LOLOr, you could bump this thread every three weeks or so ;-)Thank you.
I'm pretty Zen most of the time, but I find this really helps too. In fact, there are some books I only listen to while driving, so sometimes, if I'm at a particularly good part of a book I actually like it when traffic gets bad.By the way, I sent you a PM... LOL... I've taken long ways to a destination or STOPPED on a yellow light just so I could listen to a little more. I'm so glad I'm not alone. Thanks for the PM.MWAH!
Hi, Buddha!Ohhh, Lance Henricksen is awesome. Too bad he didn't read Neuromancer! Although that may still be an interesting listen. Thanks!
Welcome to our newest moderator, Duck!
Duck! Awesome job on organizing the How-To items in one post! You rock. Thanks.
LOL... the one genre I'm actually NOT "into" (exept in manga form, oddly -- see my blurb on Godchild/Count Cain above). I like science fiction (not so much fantasy), non fiction anthropology/history/culture as it relates to Japan, Russia, Egypt and Germany. I'm a bit of a sumbarine nut, as well as WWI flying aces. I love historical fiction as well -- England, Germany, Japan especially. The HBP is my first foray into audio books, so I've no idea if I can expect the same level of quality in other audio books.
I have all 6 books on CD also. I assume you are talking about the Jim Dale version. I have listened to them several times each as well as read the books.Yes, the Jim Dale version. He's quite excellent. I've discovered that listening to audio books completely relaxes me while driving -- in that I don't mind being "stuck" in traffic. I am still very much alert while driving, but remain adversely unaffected by poor traffic conditions (which seems non stop here in Vancouver at times).Once I'm finished the HBP, I'll have to find some other audio books to listen to ;-) Any suggestions?
Those are fantastic!!! What a great idea!!! Thanks so much for your hard work!Love them!
Those are fabulous! Keep 'em coming!Such happy loving members!!!
Hello, all!This is just a shout out to everyone. I'd like to create new "you've been spotted cards" -- you know, the ones we leave on the windshield's of fellow smarties' cars to tell them about the club.In discussions with DangerDan, we'd like to revisit the idea of displaying pictures of happy smart owners on the front of the card. So... if anyone has any high resolution images of happy smart owners and their cars, please comment here with those images (you can always post a low res image in message for reference and then attach the high res image).Thanks to all!!And a most prosperous 2007 to you all!!!


Good educational background with a sound Financial leverage to invest upto 10 lakhs.
In city with population more than 25 lakhs, you are required to have land not less than 1 acre with sufficient building. You must have an arrangement with other organization for providing health education and for conducting physical activities such as games in their grounds.
In other towns there must be a minimum 4500 sq. ft of build up are.
If the land has been possessed on lease, it is only acceptable if lease duration is not less than 30 years and made in favour society/school intending to start-on school.
Once, the site is approved by us, you may sign an MOU with us to block your territory paying 30% of the license fee.
Sign the Franchisee Agreement paying the balance of the license fees.


text:
Q: Legendary smith problems I have been playing Final Fantasy 3 (FF3) for about 33 hours now (I have played three times previously) but I am now having trouble with the legendary smith to get the ultima sword.
I have talked to the Princess, fixed her amulet and returned it. I have also exterminated the pest in the basement and received the ore. I have talked to Cid for the cut scene and completed up to the big light tower thingy as I have defeated everyone up to this point.
I have searched in all the smith's spawns including that dark knight village where I have seen other people go for this sword but it has not spawned.
What am I missing? What should I do to get the Ultima Sword?

A: Everything is explained on the FF3 Legendary Smith wikia page, especially:

Finding the Smith
Restore Princess Sara's Pendant
The party will receive a message from Princess Sara about her pendant (the player will have to check
  Mognet as Ingus), and the player must visit Castle Sasune: East Tower
  to Princess Sara's room and she will give the player the pendant. It
  has recently become broken, and needs repairing.
The party then needs to visit Takka to have it repaired and he will
  claim it is beyond his abilities. Regardless, in his mail (which the
  player will have to check Mognet as Refia) he informs them of the
  Legendary Smith whom they must find in North Western Saronia. She
  repairs the pendant and in return she asks the party to find her some
  Orichalcum. Return the pendant to Princess Sara in her tower.
Find Orichalcum
Check Mognet as Luneth to find a message from Cid titled "Something in the Basement...". Visit Cid in Canaan and
  talk to him to hear about the monster. Head down to Cid's basement and
  defeat the Aeon to collect an "Unknown Metal". Talk to Cid once more
  and he'll identify it as Orichalcum.
Now take the Orichalcum to the Legendary Smith, in Falgabard, after
  unlocking the door in Eureka. Upon giving her the metal, she will
  provide the Ultima Weapon, and wander the world.

A list of locations is also available, where you can find the Legendary Smith:

  - Ur - Inside the well.
  - Castle Sasune - The East Tower's third floor.
  - Healing Copse - The grove just before Tozus.
  - Village of the Ancients - The Inn.
  - Gysahl - Inside the Chocobo stable.
  - Replito - A northern house.
  - Dwarven Hollows - The entrance to the Subterranean Lake.
  - Saronia Castle - The basement.
  - Doga's Village - The central island.
  - Ancient Ruins - The Inn.
  - Saronia Castle - The hidden passageway in the left area where the two Black Mages are.

redpajama_set_name: RedPajamaStackExchange


text:
6 Best portable speakers for iphones
Step-by- step guide to pairing your Mpow Jaws Bluetooth Headphones
10 Best Guitars for Short Fingers
Red Diamond Audio is reader supported. When you buy through links on our site, We may earn an affiliate commision. Read AFFILIATE DISCLOSURE.
Best Portable Speakers for Iphones
We all are aware of the popularity of Bluetooth speakers. They are considered to be one of the best companions for listening to songs or tuning in to the top hits. As long as you have your iPhone and portable speaker with you, you are all ready to go. Sometimes, looking for the perfect set of Bluetooth speaker may be difficult. Therefore, in order to ease your work we have enlisted down a list of 6 best portable speakers for iphones. They are highly efficient in producing deep, intense sounds to satisfy your thirst for bass.
1) Ultimate Ears Boom 3 Portable Waterproof Bluetooth Speaker
2) Marshall Stannmore II Wireless Bluetooth Speaker
3) FUGOO Tough Bluetooth Wireless
4) Anker Soundcore Bluetooth Speaker
5) Bose Soundlink Revolve Wireless Portable Bluetooth Speaker
6) Sbode Bluetooth Portable Speaker
Factors to look for in your best portable speakers for iphones:
Battery life: This is one of the most important features to look for in your set of portable speaker. No one would prefer to charge his speaker again and again. Since these speakers are small and compact, they also tend to have smaller batteries which can get exhausted very quickly. Therefore, you must look for those speakers who come with amazing battery life. This ensures that you are hitched to your favourite songs all day long.
Quality of audio: Audio tends to get distorted while listening to them at high volumes. Also, the quality of audio tends to differ from speaker to speaker. Therefore, go for those speakers which claim to provide the lowest frequency in their frequency range. This will ensure that you get the desired bass every time you play a song.
Size: Since we are talking about portable speakers, the size also plays a vital role. Care must be taken that the speaker is not too big. This will increase its weight thereby, not making it fit for travelling. Go for those speakers which come compact in a small size and good style.
Bluetooth version: Always, check the version of Bluetooth that your desired version of speaker claims to provide. Be sure to buy the latest Bluetooth technology. This will ensure fast connectivity and better results.
Therefore, these are some of the tips which can be considered before you go shopping for the best portable speakers for iphones. Keeping in mind these tips, we have curated a list of portable speakers which can serve your purpose in every situation.
Now, taking your own set of Boom 3 to the next pool party won't be an issue anymore. Because this product has been intentionally made to be water-resistant. The product comes with an inbuilt high rating of water-resistance. This allows it to be submerged in 3 feet of water for a maximum period of 30 minutes. The product also comes with an effective protection against mud and dirt. In case it gets messy, one can easily wash the gadget with warm soapy water.
The sound of this speaker is phenomenal. The gadget delivers an immersive level of 360 degree sounds with the most accurate bass. The sounds ate deep and loud too. Also, one can easily balance the sounds according to taste. The power of this device is too good. The gadget remains in power for more than 15 hours while you play your favourite sets of songs. Also, it comes with a Power-Up charging feature. This enables one to charge the device wirelessly. This makes your speaker always ready for your next musical adventure. The speaker is 100% durable and super-portable.
As already mentioned, the device is 100% resistant to water and can sustain it for a good period of time. It comes with several magic buttons. One can easily skip, pause, play and control several lists of music. The device can produce a maximum sound level of 90 dBA with a frequency range of 90 hertz to 20 kilohertz. One can also party up with this device. You can easily connect a total of 2,3 or 4 speakers in order to enjoy the maximum level of sounds. The gadget works best with other generation of Boom speakers. The speaker also comes wrapped in an intense performance fabric. This makes it beautiful and tough enough to withstand unpredictable accidents.
The speaker has been engineered with an excellent water resistance technology.
One can easily party up with 150 speakers in total.
The gadget comes pre-equipped with a 15-hour of battery life.
The sound quality of the device is awesome.
It comes with a micro version of USB charging.
The vintage look of this speaker is the most appreciated feature. It almost looks like an old version of a tube amp guitar. Though the speaker is portable and diligent enough to perform a wide range of operations, it still lacks some features like it is not resistant to water or it isn't that amount of rugged as one might expect it to be. Yet, travelling can be fun with this device. The device can easily be customised as per one's needs.
There are knobs provided at the top of the speaker. This makes it easy to adjust the bass and treble according to the taste and liking. It also comes with a companion app which can get your phone a 5-band equaliser. It comes with a larger version of live sound. This makes it perfect to be used in any kind of space. Be it a large or a super-large room, the sounds produced by this device is no-doubted deep and intense. Apart from these, the gadget also excels in producing the most clean and precise audio. Even if one plays the music in the highest levels, he is sure to get the clearest audio from the speaker.
The gadget comes pre-equipped with Bluetooth 5.0 version. It also comes with a wireless connection. This technology assists to channelize lossless wireless sounds with efficiency. Connectivity can be made easily within a range of 30 feet. One can easily customise the sounds he wants to listen. For this, one can take the help of the analogue controls provided on the speakers or the app that comes along with this gadget. It comes with wired connectivity. One can also connect the Bluetooth by plugging into the RCA ports or into the 3.5 mm inputs.
This offers the best analogue learning experience. The gadget is multi-functional. It hosts several features which enable easy connectivity and switching between two or more Bluetooth devices with ease. It has an awesome iconic design. Also, the gadget comes pre-equipped with a frequency range of 50 hertz to 20,000 hertz. Other components like Stannmore II Bluetooth speaker, 80.0 output wattage, user manuals are also included in the whole unit. These features make it one of the best portable speakers for iphones.
It comes with a good companion app.
It is highly customisable.
It functions great at loud volumes.
It is a bit over the budget.
It comes with no water resistance feature.
If you are someone who loves to enjoy music all day long, then well Fugoo Bluetooth speakers can definitely be your choice. It comes with a staggering version of 40-hour long battery life. This will enable anyone to keep the party going. Also, the sounds produced by it are pretty good and amazing. Even at peak volumes, one can be able to enjoy the perfect audio. The gadget comes with six sets of drivers. These are spread out on every 4 side.
This ensures that you get well-balanced and clear 360 degree level of sounds. Its drivers tend to face every direction. They are tilted upward at a degree of 8 to enable better dispersion of sounds. It comes with a frequency range of 60 hertz to 20 kilohertz. The device comes with an awesome version of connectivity. It uses a Bluetooth 4.0 variant for enabling wireless connectivity.
This connectivity can also last for a maximum of 33 feet. Its audio/video remote control profile enables you to control the device efficiently. The gadget has been designed in such a way that it can be used for both indoor and outdoor purposes. Its sleek design portrays an elegant structure. The speaker tends to produce excellent treble tones with excellent bass.
The device produces a crisp and clear quality of sounds which is suitable for both outdoor and indoor. It can be also used as a speakerphone. It comes with an unidirectional microphone supported with echo cancellation. It can also be operated in full-duplex speakerphone mode. It incorporates the use of digital signal processors for reducing maximum levels of noise. Also, the speaker is 100% resistant to water. It has been designed to withstand the most rugged conditions with high efficiency.
It comes with a 40-hour battery life.
It also comes in a rugged design.
It also comes with IP67 water resistance.
It is quieter as compared to other speakers.
When it comes to inexpensive range of speakers, Anker always leads the pack. They also come in four sets of variably cheap speakers. Also, never ever confuse the concept of Cheap with junk. These products are so beautifully well-built that one can use them for daily use too. The speaker provides a 24-hour battery life with 12 watts of sound.
The size is perfect for the production of perfect bass. The quality of sounds produced by it is pretty amazing. It comprises of a 12W of pure audio power. This comes along with an enhanced version of bass thunders. Its superb quality of dual neodymium drivers is responsible for this. It also comes pre-equipped with an advanced version of digital signal processor. This ensures that the gadget produces a heart-pounding bass along with negligible distortion.
This gadget is also known to be one of the best value for money speaker. It comes pre-equipped with an intense form of bass. The patented spiral bass port boosts the low-end frequencies with efficiency. This makes the beats hit even harder. They are also considered to be one of the best portable speakers for iphones. It comes with an outstanding feature of outdoor proof. This ensures maximum protection against rain, spills, snow and dust.
This also enables one to produce the best and incredible quality sounds at home or anywhere you prefer. It comes well-equipped with a 24-hour sustainable, rechargeable battery. Its 5200 mAh li-ion battery is responsible for producing 24 hour-long sublimable sounds. Therefore, go and grab your own set of Bluetooth speaker for enjoying your favourite playlist of songs.
It is pretty inexpensive.
It comes with IPX5 water resistance.
It comes with a long-range of Bluetooth connectivity.
While playing at maximum volume, the audio tends to get distorted.
The brand Bose has always been popular in delivering the best quality speakers and headphones. Whether you listen to sounds via input jack or via your iPhone or via sending it wirelessly by Bluetooth, the quality of sounds produced by it is pretty amazing. It also comes with a convenient carrying handle. Its 2-pound weight is a lot easy to manage. Also, its tank structure makes it a lot sturdy. The gadget has been engineered to produce deep, immersive and loud levels of sounds. Its true 360 degree sounds are pretty consistent and have an uniform coverage.
Its seamless aluminium body is 100% durable and resistant to water. One can easily enjoy the 16-hours of playtime. Its rechargeable version of lithium-ion battery has been specifically designed for that. It also facilitates NFC pairing for the purpose of easy connectivity to every NFC paired device. The wireless Bluetooth pairing facility comes pre-equipped with taking calls and voice prompts too. Moreover, the gadget is also compatible with both Google Assistant and Siri. Also, one can also pair two different speakers for both playing in both party and stereo modes. It can also multi-connect to different devices for facilitating easy swapping.
The device enables easy management of Bluetooth connections. With the help of Bose app, one can easily unlock several features and access future updates easily. The customer care support is also pretty amazing. Its fabricated flexible handle makes it easy to grab whenever you're in haste. Its optional variant of charging cradle provides an elegant home base and helps to keep the speaker charged for quite a long time. You can easily attach the device to any tripod and boom! You are all set to go. You can also enlist them in your list of best portable speakers for iphones.
It produces fantastic quality of sounds.
It comes with an inbuilt microphone.
It provides an outstanding bass.
Though the century has moved on a lot, people still exist who love to listen to FM radio. And, yes! This version of Bluetooth speaker comes pre-equipped with an FM Tuner. This makes it easy to catch up with your favourite local music station. It is pretty inexpensive as compared to other speakers and has a 8-hour long battery life. The speaker sounds great for the price at which it is available.
Also, one can increase the sound output by pairing two or more devices, thereby creating a true version of wireless system. The gadget is known to produce crystal clear bass sounds. It is 100% multifunctional and comes as a variant of a wireless stereo speaker. It is 100% durable, waterproof and portable as well. It also facilitates hands-free calling and incorporates an inbuilt FM Radio. Its automatic features are pretty amazing thereby, making it one of the best portable speakers for iphones.
It comes with an FM Tuner.
It comes with a stereo pair along with two speakers.
It has a 8-hour long battery life.
Therefore, this is the list of some products which are considered to be one of the best portable speakers for iphones that are available online. So, get ready to avail them and tune your favourite songs in them.
FAQ Section:
1) How can one pair his portable speaker with his iPhone?
If it is Bluetooth enabled, then simply turn on the Bluetooth option of your iPhone. Search for new devices and pair your Bluetooth speaker as soon as its name flashes over the screen. For further details, you can go through the user manual of the speaker.
2) What factors must be looked upon before purchasing the portable speaker?
For this, care must be taken while checking the audio quality, size, Bluetooth version, waterproof quality, NFC, availability of wired inputs etc of the device.
3) How to switch on my portable speaker?
For this, kindly refer to the user manual of the speaker.
4) Is "Resistant to water" feature significant?
If you are someone who loves pool parties, then well this feature should be your prime importance. Also for other users, this feature may seem insignificant but it is better to opt for such feature rather than going for non-waterproof ones.
For more great reviews and product insights, make sure you visit us at Red Diamond Audio or connect with us on social media!
How to Connect Wireless Headphones to TV
How to turn off headphone mode on Android
How to Fix Sound Delay in Bluetooth Headphones
Fix HyperX Cloud Alpha Mic Not Working
How to connect a gaming headset to your PC
RED DIAMOND AUDIO IS A PARTICIPANT IN THE AMAZON SERVICES LLC ASSOCIATES PROGRAM, AN AFFILIATE ADVERTISING PROGRAM DESIGNED TO PROVIDE A MEANS FOR SITES TO EARN ADVERTISING FEES BY ADVERTISING AND LINKING TO AMAZON.COM.
Copyright © 2020 Red Diamond Audio. All Rights Reserved.

redpajama_set_name: RedPajamaCommonCrawl


text:
Subsidized broadband program speeds up, but Colorado customers must upgrade to keep discount
The federal Lifeline program provides $9.25 to low-income consumers for wireless or broadband service. But the FCC's upgrade on Dec. 1 may leave some CenturyLink or mobile customers behind -- and with higher bills.
Tamara Chuang / Colorado Sun
A national low-income broadband program will get a speed boost on Tuesday as new federal requirements go into effect for the Lifeline service.
But not all Lifeline customers will automatically see the upgrade to 25 megabits per second from 20 mbps for fixed broadband service, or an increase to 11.75 gigabytes of data for wireless customers.
Over at CenturyLink, customers must upgrade to the faster and likely more costly 25 mbps speed or otherwise lose their Lifeline discount. Failure to upgrade on time would result in a slower than 25 mbps service that Lifeline offers and no discount. CenturyLink, which rebranded this year and is now part of Lumen Technologies, is one of the largest telecoms offering internet and phone service in Colorado.
"Effective December 1, 2020, the Federal Communications Commission (FCC) qualification for Lifeline broadband speeds will change from 20M/3M to 25M/3M. Failure to contact CenturyLink, to upgrade your speed, will result in the removal of the Lifeline discount," notes the company's website.
Lumen officials won't say how many customers it has on Lifeline services. And it doesn't make it easy to see how much faster service costs. According to a Lumen price-check link, 100 mbps service to a home in Denver runs $49 to $65 a month, depending on the promotion. But in Estes Park, a 30 mbps connection is $49. In Montrose, $49 covers the cost of 10 mbps, which would make customers ineligible for the Lifeline discount.
According to the Federal Communications Commission, the federal program provides discounts of $9.25 a month to nearly 60,000 Coloradans. The subsidy can be used for telephone, mobile or broadband service.
To read the rest of the Colorado Sun article, click here.
Craig Dog Park receives a new, paved walkway
Dog owners will now have easier access to the Craig Dog Park thanks to grants from the Yampa Valley Community Foundation and Yampa Valley Electric Association's Operation Roundup.
Steamboat Springs School District
Multiple Positions at Steamboat Springs School District in STEAMBOAT SPRINGS
Join Steamboat Springs School District is seeking qualified candidates Principal - SSHS District Office Custodian LT Sub Paraprofessional (SSMS) Coaches…


The hotel is only 10 minutes away from the heart of Munich and the new convention center!
We know: A good start into the day , of course, also includes a full breakfast. The Amiga Hotel you can enjoy your breakfast.
The Amiga Hotel offers single to quadruple rooms and business rooms comfortable. Whether business trip or city break: With us, you are correct!
What 's going on in Munich and what is on offer? Would you like to visit the fair and get to know the heart of Munich?
WELCOME to the new Hotel Amiga!
The former Hotel Friedenspromenade is being refurbished for our guests and will be shining in a new outfit this August!


text:
Title: Mozilla Flooded With Requests After Apple Privacy Changes Hit Facebook
https://www.bleepingcomputer.com/news/security/mozilla-flooded-with-requests-after-apple-privacy-changes-hit-facebook/
Excerpt: "Mozilla volunteers have recently been flooded with online merchants and marketers' requests for their domains to be added to what's called a Public Suffix List (PSL). Public Suffix List (PSL) is an initiative of the Mozilla community volunteers to maintain a list of top-level domains (TLDs) and domains that should be treated as one to prevent the mixing of cookies between distinct domains."
https://www.darkreading.com/vulnerabilities—threats/new-malware-downloader-spotted-in-targeted-campaigns/d/d-id/1340640
Excerpt: "Researchers at Malwarebytes recently spotted the Saint Bot dropper, as they have named it, being used as part of the infection chain in targeted campaigns against government institutions in the country of Georgia. In each case, the attackers used Saint Bot to drop information stealers and other malware downloaders. According to the security vendor, it is likely that the new loader is being used by a few different threat actors, so there are likely other victims."
Title: LinkedIn Confirmed That It Was Not a Victim of a Data Breach
https://securityaffairs.co/wordpress/116689/data-breach/linkedin-not-data-breach.html
Excerpt: "The four leaked files contain information about the users whose data has been allegedly scraped by the threat actor, including their full names, email addresses, phone numbers, workplace information, and more. Users on the hacker forum can view the leaked samples for about $2 worth of forum credits, the threat actor was auctioning the much-larger 500 million user database for at least a 4-digit sum, worth of bitcoin or other cryptocurrencies."
Title: 6-Year-Old Moodle Flaw Exposed Millions to Account Takeover Attack
https://www.hackread.com/6-year-old-moodle-account-takeover-vulnerability/
Excerpt: "The vulnerability was discovered on 9th October 2020 however details of it were released last week. According to researchers, the platform was vulnerable for 6 years before being discovered and patched. Any university or school that used Moodle during that time with TeX filter enabled was at risk. TeX filter is mainly needed when sharing mathematical formulas so scientific or economics departments of universities will probably have TeX filter enabled."
Title: How Ransomware Gangs Are Connected, Sharing Resources and Tactics
https://blog.malwarebytes.com/ransomware/2021/04/how-ransomware-gangs-are-connected-and-sharing-resources-and-tactics/
Excerpt: "Many of us who read the news daily encounter a regular drum beat of ransomware stories that are both worrying and heartbreaking. And what many of us don't realize is that they are often interconnected. Some of the gangs behind the ransomware campaigns that we read about have established a relationship among each other that can be described as "being in league with each other", yet they lack certain elements that might cement their status as a true cartel in the digital underground world."
Title: Over 90% of Organizations Hit by a Mobile Malware Attack in 2020
https://www.infosecurity-magazine.com/news/over-90-of-organizations-mobile/
Excerpt: "Almost every global organization suffered at least one mobile malware attack in 2020, according to a new report from Check Point. The security vendor polled 1800 customers of its Harmony Mobile device threat protection product to compile its 2021 Mobile Security Report. Of the near-total number that faced a mobile attack last year, 93% of incidents originated in a device network, and were either phishing attempts (52%), C&C communication with malware already on the device (25%) or involved infected websites/URLs (23%)."
Title: FBI Arrests Man for Plan to Kill 70% Of Internet in AWS Bomb Attack
Date Published: April 9, 2021
https://www.bleepingcomputer.com/news/security/fbi-arrests-man-for-plan-to-kill-70-percent-of-internet-in-aws-bomb-attack/
Title: Facebook Removes 16k Groups for Trading Fake Reviews
https://www.infosecurity-magazine.com/news/facebook-groups-trading-fake/
Title: Hackers Hit 9 Countries, Expose 623,036 Payment Card Records
https://www.scmagazine.com/home/security-news/cybercrime/hackers-hit-nine-countries-expose-623036-payment-card-records/
Excerpt: "The leaked data also included the victims' nicknames, hashed passwords, contact details, history of activity, and current balance. The database also exposed all compromised data traded on the website: This included 623,036 payment card records issued by banks from the United States, Canada, the United Kingdom, China, Singapore, France, Brazil, Saudi Arabia, and Mexico. There were also 498 sets of online banking credentials and 69,592 sets of U.S. social security numbers and Canadian social insurance numbers."
Title: US Blacklists 7 Chinese Supercomputer Entities
https://www.bankinfosecurity.com/us-blacklists-7-chinese-supercomputer-entities-a-16371
Excerpt: "Citing national security concerns, the U.S. Department of Commerce this week placed seven Chinese supercomputer organizations on the Entity List, which effectively bars them from receiving supplies or components from American companies. Commerce Secretary Gina M. Raimondo notes that the high-performance computing technologies developed by these entities could be used in weapons of mass destruction programs."


What's better than curling up on the couch and enjoying some great tv! The biggest problem is, that there is often nothing to watch, welcome to TV done smarter than ever, welcome to Skyworth Binge TV.
Skyworth Binge TV makes it possible to watch TV via the Internet while also exploring all the advantages of the Android platform. The convenient remote control with voice search provides a user-friendly experience. Finally, you will enjoy watching TV at its best with 4K Ultra HD and HEVC. Enjoy tons of premium series and movies for you and the kids from Showmax or Live stream a selection of the best DStv channels including M-Net Movies and SuperSport(subscriptions not included).
- Remote control with voice search option.
- Compatible with Google Android TV remote control app.
Binge TV is the complete package, it comes ready to use straight out of the box and can be set up with the power of Google and your smartphone in under 60-seconds.


text:
Q: Intel x86 HAXM installation error Hae . I'm trying to install intel HAXM and is giving me this error..Intel Virtualization is not turned on.However,i have already turned it on .. what might be the problem

A: Make sure you have hypervison off
bcdedit /set hypervisorlaunchtype off
There's also the NX, XD bit setting. You can type
bcdedit /set nx AlwaysOn
Make sure you use the Haxm from the web site instead of using the one downloaded through Android Studio). https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager
If you're using Avast, disable "Enable hardware-assisted virtualization" under: Settings > Troubleshooting.

A: It's not an answer to your question, exactly, but I strongly recommend using Genymotion for your emulation. I can't believe I waited so long to get it running. Genymotion runs smoother on my cheap laptop with an AMD processor than the Android Studio emulator does on my Intel powered gaming rig with HAXM. It has dramatically improved my iteration loop.


text:
Q: Table causing crash on Apple Watch When I try to launch my apple watch app with the following code, it crashes after the log prints "produce" (there is nothing after that). When I remove the code, it does not crash. I cannot figure out what could be going wrong.
 NSMutableArray *rowTypesList = himo; //himo is a nsmutablearray that contains info from NSXMLParser
        [_table setRowTypes:rowTypesList];
        for (NSInteger i = 0; i < _table.numberOfRows; i++)
        {
            NSDictionary *itemAtIndex =(NSDictionary *)[himo objectAtIndex:i];
            NSObject *row = [_table rowControllerAtIndex:i];
            Cell *importantRow = (Cell *) row;
            [importantRow.label setText:@"hi"];
        }
NSLog(@"produce");

A: It looks like you are mixing your data you want to display in your table with the row controller type.  If you just have a single row controller type of Cell which it appears you do by your code you want the following:
[_table setNumberOfRows:[himo count] withRowType:@"theIdentiferYouGaveTheRowControllerInTheStoryboard"];
for (NSInteger i = 0; i < [himo count]; i++) {
    NSDictionary *item = (NSDictionary *)[himo objectAtIndex:i];
    Cell *rowController = [_table rowControllerAtIndex:i];
    [rowController.label setText:@"hi"]; // you probably want to use the data from item here
}