int main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc,argv);

    if (arguments.read("--help") || argc==1)
    {
        OE_WARN << "Usage: " << argv[0] << " [earthFile] [--model modelToLoad]"
            << std::endl;
        return 0;
    }

    osgViewer::Viewer viewer(arguments);

    // install the programmable manipulator.
    EarthManipulator* manip = new EarthManipulator();
    viewer.setCameraManipulator( manip );

    // UI:
    Container* help = createHelp(&viewer);

    osg::Node* earthNode = MapNodeHelper().load( arguments, &viewer, help );
    if (!earthNode)
    {
        OE_WARN << "Unable to load earth model." << std::endl;
        return -1;
    }

    osg::Group* root = new osg::Group();
    root->addChild( earthNode );

    osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode( earthNode );

    // user model?
    osg::ref_ptr<osg::Node> model;
    std::string modelFile;
    if (arguments.read("--model", modelFile))
        model = osgDB::readRefNodeFile(modelFile + ".osgearth_shadergen");

    osg::Group* sims = new osg::Group();
    root->addChild( sims );

    const SpatialReference* wgs84 = SpatialReference::get("wgs84");

    // Simulator for tethering:
    Simulator* sim1 = new Simulator(sims, manip, mapNode, model.get(), "Thing 1", '8');
    sim1->_start = GeoPoint(wgs84, 45.0, 55.0, 10000);
    sim1->_end = GeoPoint(wgs84, -45, -55.0, 10000);
    viewer.addEventHandler(sim1);

    Simulator* sim2 = new Simulator(sims, manip, mapNode, model.get(), "Thing 2", '9');
    sim2->_name = "Thing 2";
    sim2->_start = GeoPoint(wgs84, 45.0, 54.0, 10000);
    sim2->_end = GeoPoint(wgs84, -44.0, -54.0, 10000);
    viewer.addEventHandler(sim2);

    manip->getSettings()->getBreakTetherActions().push_back( EarthManipulator::ACTION_GOTO );    

    // Set the minimum distance to something larger than the default
    manip->getSettings()->setMinMaxDistance(10.0, manip->getSettings()->getMaxDistance());

    // Sets the maximum focal point offsets (usually for tethering)
    manip->getSettings()->setMaxOffset(5000.0, 5000.0);
    
    // Pitch limits.
    manip->getSettings()->setMinMaxPitch(-90, 90);


    viewer.setSceneData( root );

    manip->getSettings()->bindMouse(
        EarthManipulator::ACTION_EARTH_DRAG,
        osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON,
        osgGA::GUIEventAdapter::MODKEY_SHIFT );

    manip->getSettings()->bindMouseClick(
        EarthManipulator::ACTION_GOTO,
        osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON,
        osgGA::GUIEventAdapter::MODKEY_SHIFT);

    manip->getSettings()->setArcViewpointTransitions( true );    

    manip->setTetherCallback( new TetherCB() );
    
    //viewer.addEventHandler(new FlyToViewpointHandler( manip ));
    viewer.addEventHandler(new LockAzimuthHandler('u', manip));
    viewer.addEventHandler(new ToggleArcViewpointTransitionsHandler('a', manip));
    viewer.addEventHandler(new ToggleThrowingHandler('q', manip));
    viewer.addEventHandler(new ToggleCollisionHandler('k', manip));
    viewer.addEventHandler(new ToggleProjMatrix('o', manip));
    viewer.addEventHandler(new BreakTetherHandler('b', manip));
    viewer.addEventHandler(new CycleTetherMode('t', manip));
    viewer.addEventHandler(new SetPositionOffset(manip));
    viewer.addEventHandler(new ToggleLDB('L'));
    viewer.addEventHandler(new ToggleSSL(sims, ')'));
    viewer.addEventHandler(new FitViewToPoints('j', manip, mapNode->getMapSRS()));
    
    CalculateWindowCoords* calc = new CalculateWindowCoords('W', manip, sim1);
    viewer.addEventHandler(calc);
    manip->setUpdateCameraCallback(new CameraUpdater(calc));

    viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);

    while(!viewer.done())
    {
        viewer.frame();

        // simulate slow frame rate
        //OpenThreads::Thread::microSleep(1000*1000);
    }
    return 0;
}