text:
Florian Weigand
Conflict and Transnational Crime: Borders, Bullets & Business in Southeast Asia
2020, Edward Elgar Publishing
Kabul: Bridging the Gap between the State and the People; in: Kaldor, Mary and Sassen, Saskia (eds): Cities at War Global Insecurity and Urban Resistance
March 2020, Columbia University Press
The Aid Bunker: Security Risk Management in Conflict Zones; in: Lemay-Hébert, Nicolas (ed): Handbook on Intervention and Statebuilding
This chapter explores the trend of bunkerized international aid interventions in conflict-torn spaces. In response to insecurity, aid agencies and other organizations that operate in conflict-torn spaces increasingly attempt to protect their staff though 'hard' security measures. However, this trend of bunkerization and fortification is at odds with basic values and goals of statebuilding, peacebuilding and the delivery of humanitarian aid. In particular, the trend draws new 'hard' borders between 'locals' and 'expatriate' staff, isolates foreign staff and creates new security risks, particularly for local staff. In order to illustrate these dynamics, the chapter draws on interviews conducted with people in Afghanistan and on a survey conducted with aid workers in various conflict zones around the world.
The Taliban's War for Legitimacy in Afghanistan
with Ashley Jackson; 2019, Current History (April)
Institutionalized Intervention: The 'Bunker Politics' of International Aid in Afghanistan
with Ruben Andersson; 2019, Journal of Intervention and Statebuilding
Afghanistan has come to be seen as emblematic of the security threats besetting peace and security operations, and in this article we consider the response to such threats via the 'bunkering' of international staff. Drawing on an in-depth qualitative survey with aid and peacebuilding officials in Kabul, we illustrate how seemingly mundane risk management procedures have negative consequences for intervening institutions; for the relation between interveners and national actors; and for the purpose of intervention itself. Bunkering, we argue, is deeply political – 'imprisoning' staff behind ramparts while generating an illusion of presence and control for ill-conceived modes of international intervention.
Book Review | Crossed Swords: Pakistan, its Army and the Wars Within by Shuja Nawaz (Blog post)
2019, South Asia @LSE
Building Legitimacy during Armed Conflict – Learning from the Taliban (Blog post)
2017, Political Violence @ at Glance.
Afghanistan's Taliban – Legitimate Jihadists or Coercive Extremists?
2017, Journal of Intervention and Statebuilding, 11(3), pp.359-381.
The military intervention in Afghanistan in 2001 was portrayed as a fight to oust the extremist Taliban. But the Taliban have long been regaining influence, with the military victory of the Afghan government and its foreign allies now seeming less likely than ever. In light of these developments, this article investigates what the affected people – rather than the foreign interveners – think about the Taliban, and whether they perceive them as coercive or legitimate. Building on a conceptual understanding of legitimacy that has been adjusted to the dynamics of conflict-torn spaces, the article suggests that people judge the Taliban on the basis of how their day-to-day behaviour is perceived. While the Taliban are a coercive threat in urban centres and other areas where they launch attacks, they nonetheless manage to construct legitimacy in some of the places which they control or can access easily. A major source of their legitimacy in these areas is the way in which they provide services – such as conflict resolution – which some people consider to be faster and fairer than the state's practices.
The Afghan Local Police – Closing the Security Gap?
with Sam Vincent and Hameed Hakimi; 2015; Stability: International Journal of Security & Development, 4(1): 45, pp. 1–26.
The Afghan Local Police (ALP) was designed as an international counterinsurgency programme that works by raising small, village-level defence forces from within rural Afghan communities. Despite being driven by counterinsurgency objectives – that is, seeking to defeat insurgents – its emphasis upon harnessing local populations reflects broader fashions in development and security policy circles. Such policies, in turn, are commonly seen as emerging from a body of theoretical literature that is rethinking the nature of political order in conflict-torn spaces. At face value the range of well-documented controversies surrounding the ALP suggests, however, that the practice is much more 'messy'. Using the case study of the ALP in the district of Andar, we make two main arguments. First, the mess and ambiguity surrounding the ALP reveal a gap between objectives and practices, suggesting that interventions that work by seeking to harness the 'local' introduce problems that have yet to be fully recognised. Second, however, in explaining the 'mess' of the ALP we argue that the theoretically-driven work that is commonly taken to justify 'bottom-up' interventions, if taken seriously, is well-suited to understanding and even anticipating the supposedly unexpected consequences of intervenors seeking to tap local dynamics.
Intervention at Risk: The Vicious Cycle of Distance and Danger in Mali and Afghanistan
with Ruben Andersson; 2015, Journal of Intervention and Statebuilding, 9(4), pp.519–541.
In crisis-hit countries, intensive risk management increasingly characterizes the presence of international interveners, with measures ranging from fortified compounds to 'remote programming'. This article investigates the global drive for 'security' from an ethnographic perspective, focusing on Afghanistan and Mali. By deploying the concepts of distance and proximity, the article shows how frontline 'outsourcing' and bunkering have generated an unequal 'risk economy' while distancing interveners from local society in a trend that itself generates novel risks. To conclude, the article asks whether alternative forms of proximity may help to break the vicious cycle of danger and distance at work in today's crisis zones.
Investigating the role of legitimacy in the political order of conflict-torn spaces
2015; Working papers, SiT/WP/04/15. Security in Transition, LSE, London, UK.
Conflict-affected spaces that are far from exhibiting a Weberian monopoly of the legitimate use of force have been categorised as 'fragile' and 'failed' states for years. However, there is a growing tendency to understand conflicts as a form of order and to adapt the definition of statehood accordingly. But while the post-Weberian approaches indeed help to overcome some of the flaws of the dominant understanding of statehood, they do not substantively consider the role of legitimacy. The statebuilding discourse illustrates the problematic implications of the limited understanding of legitimacy on the policy level. In response, this paper suggests in line with post-Weberian scholars to understand political order as a field with multiple authorities but to consider both force and legitimacy as sources underpinning obedience to social control. An analytical framework is developed that acknowledges multiple dimensions of legitimacy as well as its dynamics. This framework may help to analyse legitimacy in empirical cases to inductively advance the theoretical understanding of legitimacy and to enable statebuilding which strengthens those authorities and institutions that are actually considered to be legitimate.
Human vs. state security: how can security sector reforms contribute to state-building? The case of the Afghan police reform
2015; Working paper series, 13-135. Department of International Development, LSE, London, UK.
The paper analyses how security sector reforms (SSRs) can contribute to statebuilding. It is argued that successful state-building requires an endogenous political process which aims at creating political legitimacy instead of certain ideal type Western state structures. In a conflict-torn society this demands security for citizens – an environment in which they feel safe and protected – allowing them to express their opinion freely and participate in a state-building process. The example of the Afghan police reform illustrates that a state-centric SSR is in danger of delegitimising and destabilising the state. In contrast, a human-centric security approach is more likely to support an endogenous process of building legitimate institutions.
www.florianweigand.com


By now, you've probably heard that we bought a building! We are so excited to be moving just a block back from where we are currently located to 283 N. Ocoee St. in downtown Cleveland, TN (on the corner of Central and Ocoee). We believe this is a great investment in both our local community and the women we serve (present and future). This building will house our workspace, storefront, offices, apartments, and more, which we believe will only unify our Free2Fly family even more and give us a chance to serve our community to a greater capacity. As creatives, we want to restore this building to be something really beautiful to reflect the beautiful restorative work that God is doing in the lives of the women we serve. We've begun the process of cleaning out the building, and we hope to be moved in by April of 2019.
If you're interested in giving to this endeavor, click HERE.


text:
class RemoveMaximumScoreFromBoard < ActiveRecord::Migration
  def change
    remove_column :boards, :maximum_score, :integer
  end
end

redpajama_set_name: RedPajamaGithub


text:
THE VILAR PERFORMING ARTS CENTER
History STAFF
Our 530-seat theatre is operated by the non-profit organization, the Vail Valley Foundation, and presents a variety of year-round performances including Broadway musicals, theatre, rock concerts, family shows, jazz, comedy, dance, film and more. The Vilar Performing Arts Center (VPAC) is a 501(c)3 non-profit organization located in the heart of Colorado's Beaver Creek Resort. We now have 12 full-time staff and host approximately 150 events each year with more than 8,000 Eagle County students attending STARS (Support the Arts Reaching Students) performances.
The Vilar Performing Arts Center prides itself on being a community resource. As such, the theatre is committed to nurturing the cultural passions of our youth and all members of our community through the Community Performance Fund. Through this fund we are able to open our doors to other Eagle County non-profits by underwriting the technical, production, labor and theatre-usage costs. This gives artists and organizations the opportunity to experience the excitement of performing on an incredible stage with professional production qualities and support. It also allows us to play an integral role in the community we reside in.
We encourage you to join our e-mail list to receive periodic updates on upcoming events, season announcements and special offers.
PRINTABLE VENUE OVERVIEW
The founders of Beaver Creek had always imagined a central theatre since it was first projected as a resort community. In February of 1998, that vision was realized. With the opening of the Vilar Performing Arts Center, Beaver Creek became the first mountain resort community in the world to include its own performing arts facility presenting an annual series of diverse cultural events.
Managed by the Vail Valley Foundation, the building of the Vilar Performing Arts Center was financed by donors who are both full and part-time residents of the Vail Valley. This theatre has added yet another unique dimension to what is already one of the world's premier vacation and recreation destinations. A state-of-the-art facility, the Vilar Performing Arts Center contains a 530-seat theatre, two 2,200 square-foot lobbies and a 2,000 square-foot May Gallery Patrons Lounge.
Located in the heart of the Beaver Creek Village, directly beneath the outdoor ice skating rink, the cultural complex hosts a variety of acclaimed artistic performances that one would expect to see at Carnegie Hall in New York or the Kennedy Center in Washington, D.C., but might not expect to find within walking distance of ski lifts, hiking trails and golf fairways. The intimate and inviting performance space was designed to exacting specifications to create perfect acoustics and unobstructed views from every seat.
Littman's Kunstler theatre in Munich provided inspiration for the wood-paneled columns, walls and ceilings that are combined with the curved horseshoe seating layout also found in many traditional European halls. The natural wood and stone in the lobby are highlighted by carpets and fabrics woven with autumnal colors. The walls are painted in the muted tones of the sky at dusk which complete the theater's harmonious complement to the Rocky Mountain environment that surrounds it.
One of the country's leading designers for the performing and visual arts and one of Colorado's finest resort design talents collaborated on the design for the Vilar Performing Arts Center. Hardy Holzman Pfeiffer Associates of Los Angeles has completed over 30 theatre buildings and 40 theatre studies throughout the world. Among its projects are Minneapolis' Orchestra Hall, Denver's Boettcher Hall and major performing arts centers in Anchorage, Alaska and Eugene, Oregon.
Pierce Segerberg and Associates, with offices in Vail and Denver, has created many renowned projects in the Vail Valley, including the Sonnenalp Hotel at Vail Village and the Chateau, Greystone and Pines developments in Beaver Creek. Through the use of natural material and a keen understanding of the climate, these buildings exude regional imagery and contribute to the area's unique identity.
Beaver Creek is at the center of a thirty-mile chain of communities stretching from East-Vail to Gypsum. The popularity of Vail and Beaver Creek Mountains as winter and summer destinations, the easy drive from Denver International Airport and the Vail/Eagle Airport located just twenty minutes away have made it possible to for such a small community to support a facility of the VPAC's caliber. The VPAC is well served by its location at the heart of Beaver Creek, it is easily accessible by car or bus and is walking distance to the village's many lodges, cafes, restaurants and retail shops.
The Vilar Performing Arts Center's programming ranges from jazz, blues, country and classical concerts to contemporary and ballet dance troupes, comedy, theatre and family productions. The Vilar Center also hosts a number of community productions, awards shows and fundraisers for local organizations throughout the year.
Interest in the performing and visual arts has developed along with the success of the Vail Valley as a year-round destination. Summer performances at the Ford Amphitheater and rock concerts at the Dobson Ice Arena in Vail are immensely popular, but until the construction of the VPAC there had not been a year-round space suitable for an enriching cultural experience by a variety of artists here in the Vail Valley.
The venue's naming patron, Alberto Vilar, is passionate about performing arts. He has a particular affinity for opera and ballet, as well as symphonic, classical choral and chamber music. "Culture enriches our life," says Vilar. "'What would life be without Mozart?' as the saying goes."
THE MAY GALLERY PATRONS LOUNGE:
The VPAC is home to the beautiful May Gallery Patrons Lounge, an exclusive gathering place for members at the Patron Society level and above, as well as the theater's original Capital Campaign donors. Named in honor of founding patrons Peter & Leni May, the opening of the gallery was celebrated on the evening of November 26, 1999 following a performance by jazz trumpeter virtuoso Maynard Ferguson. For nearly 20 years, a selection of 33 architectural drawings were showcased from the May's private collection, depicting cultural institutions, train stations, fountains, and other public structures dated from 1843 through mid 20th century.
On July 5, 2019 – opening night of the 2019 summer season featuring comedian Jay Leno – the May Gallery was unveiled once again, this time bridging contemporary and traditional design in the first complete remodel of the space. Notable improvements include an open floor plan to accommodate a wider range of events and performances, custom-built furnishings, Swarovski crystal chandeliers, state-of-the-art sound and lighting technology, and a rotating collection of artwork provided by local galleries and private collectors. The May Gallery continues to be a celebrated pre-show enclave for theater members and a cultural jewel of the community.
Amenities include a full-service bar, nightly snacks, coatroom, private restrooms, and a livestream of performances on a 80" television.
The VPAC box office is located in the theater, directly below the ice rink on Beaver Creek Plaza. Tickets can be purchased in person, by phone or directly at: vilarpactickets.org
Contact the Box Office: 970.845.8497 / 888.920.2787 / 970.748.1396 (fax) / boxoffice@vvf.org
Owen Hutchinson
Hometown: Otisco, NY
Lauren Gary
Director of Ticketing
Hometown: Scarsdale, NY
Amy Sherman
Box Office Assistant
Hometown: Avon, CO
Dean Davis
Hometown: Denver, CO
Ruthie Hamrick
Hometown: Urbana, IL
Shane Huebner
Hometown: Sandy Hook, CT
Erik Brown
Director of Special Projects & Infrastructure
Hometown: Placentia, CA
Tess Reinhold
Programming & Artist Relations Manager
Hometown: Philadelphia, PA
Katie Gervais
Hometown: Annapolis,MD
Filter Calendar Events: All ConcertsBroadwayComedyFamilyClassicalDanceFilmsSTARSOtherSpeaker
Head to the Mountains for These Under the Radar Art Events
www.5280.com
DiGiCo Helps Intimate Vilar Performing Arts Center Achieve Grand Ambitions
www.digico.biz
STARS Program receives $1 million endowment from Frechette Family Foundation
vaildaily.com
Tony Award-winning 'Kinky Boots,' 'Rent' headline Vilar Center's Broadway Series
Consistent Commitment: A Steady Path to Higher Production Values at Performing Arts Venue
Check out VPAC Technical Director Erik Brown's article about the latest sound system upgrades
Why you Should Strongly Consider skiing Beaver Creek
6 Under-the-Radar Family Vacations in Colorado
How to Plan Your First Ski Vacation

redpajama_set_name: RedPajamaCommonCrawl


plan maison plain pied passive. Thank You for visiting our website. Nowadays we are delighted to announce that we have found an incredibly interesting content to be reviewed, namely plan maison plain pied passive. Many individuals trying to find details about plan maison plain pied passive and certainly one of them is you, is not it?
There are lots of explanation why you are researching for details about plan maison plain pied passive, but certainly, you are searching for new suggestions for your considerations. We identified this on the web sources and we believe this can be one of several excellent content for reference. And you know, initially when I first found it, we liked it, we hope you are too. We believe, we may own different viewpoints, but, what we do just like to support you in finding more suggestions concerning plan maison plain pied passive.


The second troubling proposal concerns the rules of origin. Currently, 62.5% of a car or a truck must be produced in the U.S., Mexico or Canada for it to qualify for duty-free treatment under NAFTA. The U.S.'s proposal would require that 50% of the vehicle be produced in the U.S. This would be immensely harmful to the North American auto industry. It's impossible to replace long-established multi-billiondollar supply chains so most companies would simply pay the generally low U.S. tariffs. Manufacturers would then source more inputs from Asia.


text:
Corybas may refer to:

 Corybas, a genus of orchid
 Corybas, a character in Greek mythology
 Corybas, a synonym for a genus of sponges (Amphilectus)

redpajama_set_name: RedPajamaWikipedia


text:
//==================================================================================
// Copyright (c) 2016 , Advanced Micro Devices, Inc.  All rights reserved.
//
/// \author AMD Developer Tools Team
/// \file acDoubleSlider.cpp
///
//==================================================================================

//------------------------------ acDoubleSlider.cpp ------------------------------

// Qt
#include <AMDTApplicationComponents/Include/acQtIncludes.h>

// Infra:
#include <AMDTBaseTools/Include/gtAssert.h>
#include <AMDTBaseTools/Include/gtAlgorithms.h>
#include <AMDTAPIClasses/Include/apParameters.h>
#include <AMDTOSWrappers/Include/osDebuggingFunctions.h>

// Local:
#include <AMDTApplicationComponents/Include/acColours.h>
#include <AMDTApplicationComponents/Include/acDefinitions.h>
#include <AMDTApplicationComponents/Include/acDoubleSlider.h>
#include <AMDTApplicationComponents/Include/acMessageBox.h>

// Icons:
//#include <AMDTApplicationComponents/Include/res/icons/double_slider_tickbox.xpm>
//#include <AMDTApplicationComponents/Include/res/icons/double_slider_background_pattern.xpm>
//#include <AMDTApplicationComponents/Include/res/icons/double_slider_selected_region_pattern.xpm>
//#include <AMDTApplicationComponents/Include/res/icons/double_slider_above_region_pattern.xpm>
//#include <AMDTApplicationComponents/Include/res/icons/double_slider_below_region_pattern.xpm>

// Defines the size of the text boxes showing the values
#define AC_DOUBLE_SLIDER_TEXT_BOXES_SIZE QSize(76, 20)

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::acQtDoubleSlider
// Description: Constructor
// Arguments:   QWidget* parent
// Author:      Sigal Algranaty
// Date:        27/6/2012
// ---------------------------------------------------------------------------
acQtDoubleSlider::acQtDoubleSlider(QWidget* parent) : QSlider(Qt::Horizontal, parent),
    m_sliderMinPossibleValue(0), m_sliderMaxPossibleValue(1), m_currentSliderLeftValue(0), m_currentSliderRightValue(1),
    m_offset(0), m_position(0), m_blockTracking(false), m_firstMovement(false), m_lastPressed(NoHandle), m_mainControl(LeftHandle),
    m_leftPressed(QStyle::SC_None), m_rightPressed(QStyle::SC_None), m_movement(acQtDoubleSlider::FreeMovement), m_ignoreInvalidText(false)
{
    // Connect the range change signal and slot:
    bool rc = connect(this, SIGNAL(rangeChanged(int, int)), this, SLOT(resetSliderRange(int, int)));
    GT_ASSERT(rc);

    // Set the initial range:
    emit spanChanged(m_sliderMinPossibleValue, m_sliderMaxPossibleValue);
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::~acQtDoubleSlider
// Description: Destructor
// Author:      Sigal Algranaty
// Date:        28/6/2012
// ---------------------------------------------------------------------------
acQtDoubleSlider::~acQtDoubleSlider()
{
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::initStyleOption
// Description: Init a style option object
// Arguments:   QStyleOptionSlider* option
//              SpanHandle handle
// Author:      Sigal Algranaty
// Date:        2/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::initStyleOption(QStyleOptionSlider* pStyleOption, SpanHandle handle) const
{
    if (pStyleOption != NULL)
    {

        // Initialize from myself:
        pStyleOption->initFrom(this);

        //
        pStyleOption->subControls = QStyle::SC_None;
        pStyleOption->activeSubControls = QStyle::SC_None;
        pStyleOption->orientation = orientation();
        pStyleOption->maximum = maximum();
        pStyleOption->minimum = minimum();
        pStyleOption->tickPosition = tickPosition();
        pStyleOption->tickInterval = tickInterval();
        pStyleOption->upsideDown = false;
        pStyleOption->direction = Qt::LeftToRight;

        // Set the slider positions:
        pStyleOption->sliderPosition = (handle == LeftHandle ? leftPosition() : rightPosition());
        pStyleOption->sliderValue = (handle == LeftHandle ? leftMinValuePosition() : rightMaxValuePosition());
        pStyleOption->singleStep = singleStep();
        pStyleOption->pageStep = pageStep();
        pStyleOption->state |= QStyle::State_Horizontal;
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::pixelPosToRangeValue
// Description: Translates a pixel position to range value (pixel on the widget to
//              a range within the slider)
// Arguments:   int pos
// Return Val:  int
// Author:      Sigal Algranaty
// Date:        1/7/2012
// ---------------------------------------------------------------------------
int acQtDoubleSlider::pixelPosToRangeValue(int pos) const
{
    int retVal = 0;

    // Define a style option object:
    QStyleOptionSlider opt;
    initStyleOption(&opt);

    // Get the slider and groove rectangles:
    int sliderMin = 0;
    int sliderMax = 0;
    int sliderLength = 0;
    const QRect grooveRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this);
    const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);

    // Get the slider length, min and max:
    sliderLength = sliderRect.width();
    sliderMin = grooveRect.x();
    sliderMax = grooveRect.right() - sliderLength + 1;

    // Get the slider value from position:
    retVal = QStyle::sliderValueFromPosition(minimum(), maximum(), pos - sliderMin, sliderMax - sliderMin, opt.upsideDown);

    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::setupPainter
// Description: Set the pPainter
// Arguments:   QPainter* pPainter
//              qreal x1
//              qreal y1
//              qreal x2
//              qreal y2
// Return Val:  void
// Author:      Sigal Algranaty
// Date:        1/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::setupPainter(QPainter* pPainter, qreal x1, qreal y1, qreal x2, qreal y2, SpanType spanType) const
{
    // Sanity check:
    GT_IF_WITH_ASSERT(pPainter != NULL)
    {
        // Get the highlight color:
        QColor bgColor = palette().color(QPalette::Highlight);

        if (spanType == LeftSpan)
        {
            bgColor = acQRAW_FILE_BELOW_RANGE_COLOR;
        }
        else if (spanType == RightSpan)
        {
            bgColor = acQRAW_FILE_ABOVE_RANGE_COLOR;
        }

        // Set the gradient for the brush:
        QLinearGradient gradient(x1, y1, x2, y2);
        gradient.setColorAt(0, bgColor.dark(120));
        gradient.setColorAt(1, bgColor.light(108));

        // Set the pPainter brush:
        pPainter->setBrush(gradient);

        // Set the pPainter pen:
        pPainter->setPen(QPen(bgColor.dark(130), 0));
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::drawSpan
// Description: Draw the slider span
// Arguments:   QStylePainter* pPainter
//              const QRect& rect
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::drawSpan(QStylePainter* pPainter, const QRect& rect, SpanType spanType) const
{
    GT_IF_WITH_ASSERT(pPainter != NULL)
    {
        // Initialize style option class:
        QStyleOptionSlider opt;
        initStyleOption(&opt);
        const QSlider* p = this;

        // Get the groove area:
        QRect groove = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, p);
        groove.adjust(0, 0, -1, 0);

        // Set the pen & brush:
        pPainter->setPen(QPen(p->palette().color(QPalette::Dark).light(110), 0));

        // Set the painter:
        setupPainter(pPainter, groove.center().x(), groove.top(), groove.center().x(), groove.bottom(), spanType);

        // Draw the groove rect:
        pPainter->drawRect(rect.intersected(groove));
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::drawHandle
// Description: Draw the slider handle
// Arguments:   QStylePainter* painter
//              SpanHandle handle
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::drawHandle(QStylePainter* pPainter, SpanHandle handle) const
{
    GT_IF_WITH_ASSERT(pPainter != NULL)
    {
        // Initialize style option object:
        QStyleOptionSlider opt;
        initStyleOption(&opt, handle);
        opt.subControls = QStyle::SC_SliderHandle;

        // Set the handle state (pressed / not pressed):
        QStyle::SubControl pressed = (handle == LeftHandle ? m_leftPressed : m_rightPressed);

        if (pressed == QStyle::SC_SliderHandle)
        {
            opt.activeSubControls = pressed;
            opt.state |= QStyle::State_Sunken;
        }

        // Set the position according to the right / left handle:
        // If left value == right value set left handle to leftmost position,
        // right handle to rightmost position and disable dragging

        if (handle == acQtDoubleSlider::LeftHandle)
        {
            if (m_currentSliderLeftValue == m_currentSliderRightValue)
            {
                opt.sliderPosition = minimum();
            }
            else
            {
                opt.sliderPosition = sliderPositionFromValue(m_currentSliderLeftValue);
            }
        }

        else if (handle == acQtDoubleSlider::RightHandle)
        {
            if (m_currentSliderLeftValue == m_currentSliderRightValue)
            {
                opt.sliderPosition = maximum();
            }
            else
            {
                opt.sliderPosition = sliderPositionFromValue(m_currentSliderRightValue);
            }
        }

        pPainter->drawComplexControl(QStyle::CC_Slider, opt);
    }
}

void acQtDoubleSlider::triggerAction(QAbstractSlider::SliderAction action, bool main)
{
    float value = 0;
    bool noAction = false;
    bool up = false;
    const float min = m_sliderMinPossibleValue;
    const float max = m_sliderMaxPossibleValue;
    const SpanHandle altControl = (m_mainControl == LeftHandle ? RightHandle : LeftHandle);

    m_blockTracking = true;

    switch (action)
    {
        case QAbstractSlider::SliderSingleStepAdd:
            if ((main && m_mainControl == RightHandle) || (!main && altControl == RightHandle))
            {
                value = qBound(min, m_sliderMaxPossibleValue + singleStepValue(), max);
                up = true;
                break;
            }

            value = qBound(min, m_sliderMinPossibleValue + singleStepValue(), max);
            break;

        case QAbstractSlider::SliderSingleStepSub:
            if ((main && m_mainControl == RightHandle) || (!main && altControl == RightHandle))
            {
                value = qBound(min, m_sliderMaxPossibleValue - singleStepValue(), max);
                up = true;
                break;
            }

            value = qBound(min, m_sliderMinPossibleValue - singleStepValue(), max);
            break;

        case QAbstractSlider::SliderToMinimum:
            value = min;

            if ((main && m_mainControl == RightHandle) || (!main && altControl == RightHandle))
            {
                up = true;
            }

            break;

        case QAbstractSlider::SliderToMaximum:
            value = max;

            if ((main && m_mainControl == RightHandle) || (!main && altControl == RightHandle))
            {
                up = true;
            }

            break;

        case QAbstractSlider::SliderMove:
            if ((main && m_mainControl == RightHandle) || (!main && altControl == RightHandle))
            {
                up = true;
            }

            break;

        case QAbstractSlider::SliderNoAction:
            noAction = true;
            break;

        default:
            qWarning("acQtDoubleSlider::triggerAction: Unknown action");
            break;
    }

    if (!noAction && !up)
    {
        if (m_movement == acQtDoubleSlider::NoCrossing)
        {
            value = qMin(value, m_sliderMaxPossibleValue);
        }
        else if (m_movement == acQtDoubleSlider::NoOverlapping)
        {
            value = qMin(value, m_sliderMaxPossibleValue - 1);
        }

        if (m_movement == acQtDoubleSlider::FreeMovement && value > m_sliderMaxPossibleValue)
        {
            swapSliderHandles();
            setRightPosition(value);
        }
        else
        {
            setLeftPosition(value);
        }
    }
    else if (!noAction)
    {
        bool shouldSetValue = true;

        if (m_movement == acQtDoubleSlider::NoCrossing)
        {
            value = qMax(value, m_sliderMinPossibleValue);
        }
        else if (m_movement == acQtDoubleSlider::NoOverlapping)
        {
            value = qMax(value, m_sliderMinPossibleValue + 1);
        }
        else
        {
            shouldSetValue = false;
        }

        if (shouldSetValue)
        {
            if (m_movement == acQtDoubleSlider::FreeMovement && value < m_sliderMinPossibleValue)
            {
                swapSliderHandles();
                setLeftPosition(value);
            }
            else
            {
                setRightPosition(value);
            }
        }
    }

    m_blockTracking = false;

    setSpan(m_currentSliderLeftValue, m_currentSliderRightValue);
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::swapSliderHandles
// Description: Swap right and left handles
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::swapSliderHandles()
{
    qSwap(m_currentSliderRightValue, m_currentSliderLeftValue);
    qSwap(m_leftPressed, m_rightPressed);
    m_lastPressed = (m_lastPressed == LeftHandle ? RightHandle : LeftHandle);
    m_mainControl = (m_mainControl == LeftHandle ? RightHandle : LeftHandle);
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::resetSliderRange
// Description: Reset the range
// Arguments:   int min
//              int max
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::resetSliderRange(int min, int max)
{
    Q_UNUSED(min);
    Q_UNUSED(max);
    // setSpan() takes care of keeping span in range
    setSpan(m_sliderMinPossibleValue, m_sliderMaxPossibleValue);
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::leftValue
// Description: This property holds the m_sliderMinPossibleValue value of the span
// Return Val:  float
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
float acQtDoubleSlider::leftValue() const
{
    return qMin(m_sliderMinPossibleValue, m_sliderMaxPossibleValue);
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::rightValue
// Description: This property holds the m_sliderMaxPossibleValue value of the span
// Return Val:  float
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
float acQtDoubleSlider::rightValue() const
{
    return qMax(m_sliderMinPossibleValue, m_sliderMaxPossibleValue);
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::setSpan
// Description: Set the slider span
// Arguments:   float leftValue
//              float rightValue
// Return Val:  void
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::setSpan(float leftValue, float rightValue)
{
    // Check if the new values are in the span:
    const float left = qBound(m_sliderMinPossibleValue, qMin(leftValue, m_currentSliderRightValue), m_sliderMaxPossibleValue);
    const float right = qBound(m_sliderMinPossibleValue, qMax(m_currentSliderLeftValue, rightValue), m_sliderMaxPossibleValue);

    if (left != m_currentSliderLeftValue || right != m_currentSliderRightValue)
    {
        // Set the new values:
        m_currentSliderLeftValue = left;
        m_currentSliderRightValue = right;

        // gtString dbg;
        // dbg.appendFormattedString(L"setSpan: %f, %f\n", m_currentSliderLeftValue, m_currentSliderRightValue);
        // osOutputDebugString(dbg);

        // Emit a span changed signal:
        emit spanChanged(m_currentSliderLeftValue, m_currentSliderRightValue);

        // Update the control:
        update();
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::leftPosition
// Description: Return the slider left position
// Return Val:  int
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
int acQtDoubleSlider::leftPosition() const
{
    int retVal = 0;

    retVal = sliderPositionFromValue(m_currentSliderLeftValue);
    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::leftMinValuePosition
// Description: Left minimum position
// Return Val:  int
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
int acQtDoubleSlider::leftMinValuePosition() const
{
    int retVal = 0;

    retVal = sliderPositionFromValue(m_sliderMinPossibleValue);
    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::rightMaxValuePosition
// Description: Right maximum position
// Return Val:  int
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
int acQtDoubleSlider::rightMaxValuePosition() const
{
    int retVal = 0;

    retVal = sliderPositionFromValue(m_sliderMaxPossibleValue);
    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::setLeftPosition
// Description: Set the slider left position
// Arguments:   int leftPosition
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::setLeftPosition(int leftPosition)
{
    int leftPos = sliderPositionFromValue(m_currentSliderLeftValue);

    if (leftPos != leftPosition)
    {

        float newLeftValue = sliderValueFromPosition(leftPosition);

        // Set the new span:
        setSpan(newLeftValue, m_currentSliderRightValue);

        // Update the slider:
        if (!hasTracking())
        {
            update();
        }
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::rightPosition
// Description: Get the slider right position
// Return Val:  int
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
int acQtDoubleSlider::rightPosition() const
{
    int retVal = 0;

    retVal = sliderPositionFromValue(m_currentSliderRightValue);
    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::setRightPosition
// Description: Set the slider right position
// Arguments:   int rightPosition
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::setRightPosition(int rightPosition)
{
    int rightPos = sliderPositionFromValue(m_currentSliderRightValue);

    if (rightPos != rightPosition)
    {
        QStyleOptionSlider opt;
        initStyleOption(&opt);

        float newRightValue = sliderValueFromPosition(rightPosition);

        // Set the new span:
        setSpan(m_currentSliderLeftValue, newRightValue);

        // Update the control:
        if (!hasTracking())
        {
            update();
        }
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::keyPressEvent
// Description: Re-implements the key press event
// Arguments:   QKeyEvent* event
// Return Val:  void
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::keyPressEvent(QKeyEvent* pEvent)
{
    // Call the base class implementation:
    QSlider::keyPressEvent(pEvent);

    // Sanity check
    GT_IF_WITH_ASSERT(pEvent != NULL)
    {
        bool main = true;
        SliderAction action = SliderNoAction;

        switch (pEvent->key())
        {
            case Qt::Key_Left:
                main   = true;
                action = !invertedAppearance() ? SliderSingleStepSub : SliderSingleStepAdd;
                break;

            case Qt::Key_Right:
                main   = true;
                action = !invertedAppearance() ? SliderSingleStepAdd : SliderSingleStepSub;
                break;

            case Qt::Key_Up:
                main   = false;
                action = invertedControls() ? SliderSingleStepSub : SliderSingleStepAdd;
                break;

            case Qt::Key_Down:
                main   = false;
                action = invertedControls() ? SliderSingleStepAdd : SliderSingleStepSub;
                break;

            case Qt::Key_Home:
                main   = (m_mainControl == acQtDoubleSlider::LeftHandle);
                action = SliderToMinimum;
                break;

            case Qt::Key_End:
                main   = (m_mainControl == acQtDoubleSlider::RightHandle);
                action = SliderToMaximum;
                break;

            default:
                pEvent->ignore();
                break;
        }

        // If an action is required, trigger action:
        if (action)
        {
            triggerAction(action, main);
        }
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::mousePressEvent
// Description: Is handling the mouse press event
// Arguments:   QMouseEvent* pEvent
// Author:      Sigal Algranaty
// Date:        2/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::mousePressEvent(QMouseEvent* pEvent)
{
    GT_IF_WITH_ASSERT(pEvent != NULL)
    {
        // Check if this event should be ignored:
        bool shouldIgnore = ((minimum() == maximum()) || (pEvent->buttons() ^ pEvent->button()));

        if (shouldIgnore)
        {
            pEvent->ignore();
        }
        else
        {
            // Get the mouse click position:
            QPoint mouseClickPosition = pEvent->pos();

            // Check if the clicked handle is the right handle:
            QStyleOptionSlider optRightHandle;
            initStyleOption(&optRightHandle, acQtDoubleSlider::RightHandle);

            // Save the old right handle state:
            QStyle::SubControl oldControl = m_rightPressed;

            // Get the value related for the right value:
            int value = sliderPositionFromValue(m_sliderMaxPossibleValue);

            // Perform a hit test for the right handle:
            m_rightPressed = style()->hitTestComplexControl(QStyle::CC_Slider, &optRightHandle, mouseClickPosition, this);

            QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &optRightHandle, QStyle::SC_SliderHandle, this);

            bool shouldUpdate = false;

            if (m_rightPressed == QStyle::SC_SliderHandle)
            {
                // gtString debugStr;
                // debugStr.appendFormattedString(L"m_rightPressed hit test was passed! value=%d, position=(%d, %d)\n", value, mouseClickPosition.x(), mouseClickPosition.y());
                // osOutputDebugString(debugStr);

                // Check if the widget should be updated:
                shouldUpdate = m_rightPressed != oldControl;
                m_position = value;
                m_offset = (mouseClickPosition - sliderRect.topLeft()).x();
                m_lastPressed = acQtDoubleSlider::RightHandle;
                setSliderDown(true);
            }
            else
            {
                oldControl = m_leftPressed;

                // Check if the clicked handle is the right handle:
                QStyleOptionSlider optLeftHandle;
                initStyleOption(&optLeftHandle, acQtDoubleSlider::LeftHandle);

                sliderRect = style()->subControlRect(QStyle::CC_Slider, &optLeftHandle, QStyle::SC_SliderHandle, this);
                // Perform a hit test for the right handle:
                m_leftPressed = style()->hitTestComplexControl(QStyle::CC_Slider, &optLeftHandle, mouseClickPosition, this);

                // Get the value related for the right value:
                value = sliderPositionFromValue(m_sliderMinPossibleValue);

                if (m_leftPressed == QStyle::SC_SliderHandle)
                {
                    // gtString debugStr;
                    // debugStr.appendFormattedString(L"m_leftPressed hit test was passed! value=%d, position=(%d, %d)\n", value, mouseClickPosition.x(), mouseClickPosition.y());
                    // osOutputDebugString(debugStr);

                    // Check if the widget should be updated:
                    shouldUpdate = m_leftPressed != oldControl;

                    m_position = value;
                    m_offset = (mouseClickPosition - sliderRect.topLeft()).x();
                    m_lastPressed = acQtDoubleSlider::LeftHandle;
                    setSliderDown(true);
                }
            }

            if (shouldUpdate)
            {
                update(sliderRect);
            }

            m_firstMovement = true;
            pEvent->accept();
        }
    }
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::mouseMoveEvent
// Description: Re implements the mouse move event
// Arguments:   QMouseEvent* pEvent
// Author:      Sigal Algranaty
// Date:        1/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::mouseMoveEvent(QMouseEvent* pEvent)
{
    // Sanity check
    GT_IF_WITH_ASSERT(pEvent != NULL)
    {
        if (m_leftPressed != QStyle::SC_SliderHandle && m_rightPressed != QStyle::SC_SliderHandle)
        {
            // Ignore the event:
            pEvent->ignore();
        }
        else
        {
            QStyleOptionSlider opt;
            initStyleOption(&opt);
            const int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this);
            int newPosition = pixelPosToRangeValue(pEvent->pos().x() - m_offset);

            if (m >= 0)
            {
                const QRect r = rect().adjusted(-m, -m, m, m);

                if (!r.contains(pEvent->pos()))
                {
                    newPosition = m_position;
                }
            }

            // pick the preferred handle on the first movement
            if (m_firstMovement)
            {
                if (m_sliderMinPossibleValue == m_sliderMaxPossibleValue)
                {
                    if (newPosition < rightPosition())
                    {
                        swapSliderHandles();
                        m_firstMovement = false;
                    }
                }
                else
                {
                    m_firstMovement = false;
                }
            }

            if (m_leftPressed == QStyle::SC_SliderHandle)
            {
                if (m_movement == NoCrossing)
                {
                    newPosition = qMin(newPosition, rightPosition());
                }
                else if (m_movement == NoOverlapping)
                {
                    newPosition = qMin(newPosition, rightPosition() - 1);
                }

                if (m_movement == FreeMovement && newPosition > rightMaxValuePosition())
                {
                    swapSliderHandles();
                    setRightPosition(newPosition);
                }
                else
                {
                    setLeftPosition(newPosition);
                }
            }
            else if (m_rightPressed == QStyle::SC_SliderHandle)
            {
                if (m_movement == NoCrossing)
                {
                    newPosition = qMax(newPosition, rightPosition());
                }
                else if (m_movement == NoOverlapping)
                {
                    newPosition = qMax(newPosition, rightPosition() + 1);
                }

                if (m_movement == FreeMovement && newPosition < leftMinValuePosition())
                {
                    swapSliderHandles();
                    debugOutput(L"setLeftPosition: ", newPosition);
                    setLeftPosition(newPosition);
                }
                else
                {
                    debugOutput(L"setRightPosition: ", newPosition);
                    setRightPosition(newPosition);
                }
            }

            pEvent->accept();
        }
    }
}

/*!
\reimp
*/
void acQtDoubleSlider::mouseReleaseEvent(QMouseEvent* event)
{
    QSlider::mouseReleaseEvent(event);
    setSliderDown(false);
    m_leftPressed = QStyle::SC_None;
    m_rightPressed = QStyle::SC_None;
    update();
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::paintEvent
// Description: Re-implementation of the slider class paint event
// Arguments:   QPaintEvent* pEvent
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acQtDoubleSlider::paintEvent(QPaintEvent* pEvent)
{
    // Create a pPainter:
    Q_UNUSED(pEvent);
    QStylePainter painter(this);

    // Draw the slider ticks:
    QStyleOptionSlider opt;
    initStyleOption(&opt);
    opt.subControls = QStyle::SC_SliderTickmarks;
    painter.drawComplexControl(QStyle::CC_Slider, opt);

    // Draw the slider groove:
    opt.sliderValue = 0;
    opt.sliderPosition = 0;
    opt.subControls = QStyle::SC_SliderGroove;
    painter.drawComplexControl(QStyle::CC_Slider, opt);

    // Get the slider handles rects:

    // Left handle:
    opt.sliderPosition = sliderPositionFromValue(m_currentSliderLeftValue);
    const QRect leftHandleRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
    const int leftHandleRectX  = leftHandleRect.center().x();

    // Right handle:
    opt.sliderPosition = sliderPositionFromValue(m_currentSliderRightValue);
    const QRect rightHandleRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
    const int rightHandleRectX  = rightHandleRect.center().x();

    // span
    const int minv = qMin(leftHandleRectX, rightHandleRectX);
    const int maxv = qMax(leftHandleRectX, rightHandleRectX);
    const QPoint grooveCenter = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this).center();

    // Draw the left span (red):
    QRect leftSpanRect = QRect(QPoint(0, grooveCenter.y() - 2), QPoint(minv, grooveCenter.y() + 1));
    drawSpan(&painter, leftSpanRect, LeftSpan);

    // Get the span rectangle:
    QRect spanRect = QRect(QPoint(minv, grooveCenter.y() - 2), QPoint(maxv, grooveCenter.y() + 1));
    drawSpan(&painter, spanRect, MiddleSpan);

    // Draw the right span (purple):
    int grooveRightEnd = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this).right();
    QRect rightSpanRect = QRect(QPoint(maxv, grooveCenter.y() - 2), QPoint(grooveRightEnd, grooveCenter.y() + 1));
    drawSpan(&painter, rightSpanRect, RightSpan);

    // Draw the slider handles:
    switch (m_lastPressed)
    {
        case acQtDoubleSlider::LeftHandle:
            drawHandle(&painter, acQtDoubleSlider::RightHandle);
            drawHandle(&painter, acQtDoubleSlider::LeftHandle);
            break;

        case acQtDoubleSlider::RightHandle:
        default:
            drawHandle(&painter, acQtDoubleSlider::LeftHandle);
            drawHandle(&painter, acQtDoubleSlider::RightHandle);
            break;
    }

}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::sliderPositionFromValue
// Description: Return the slider requested position for a requested slider float
//              value
// Arguments:   float sliderValue
// Return Val:  int
// Author:      Sigal Algranaty
// Date:        2/7/2012
// ---------------------------------------------------------------------------
int acQtDoubleSlider::sliderPositionFromValue(float sliderValue) const
{
    int retVal = 0;

    // Get the slider range:
    int sliderRange = maximum() - minimum();

    // Get the slider full range:
    float sliderFullRange = m_sliderMaxPossibleValue - m_sliderMinPossibleValue;

    // ND check
    if (sliderFullRange != 0)
    {
        // Get the relative position:
        float relativePosition = (sliderValue - m_sliderMinPossibleValue) / sliderFullRange;
        retVal = sliderRange * relativePosition;
    }

    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acQtDoubleSlider::sliderValueFromPosition
// Description: Return the slider value given the slider position in integer numbers
// Arguments:   int sliderPosition
// Return Val:  float
// Author:      Sigal Algranaty
// Date:        2/7/2012
// ---------------------------------------------------------------------------
float acQtDoubleSlider::sliderValueFromPosition(int sliderPosition) const
{
    float retVal = 0;

    // Get the slider range:
    int sliderRange = maximum() - minimum();

    if (sliderRange != 0)
    {
        float relativePosition = (float)(sliderPosition - minimum()) / (float)sliderRange;

        // Get the slider full range:
        retVal = m_sliderMinPossibleValue + relativePosition * (m_sliderMaxPossibleValue - m_sliderMinPossibleValue);
    }

    return retVal;
}

float acQtDoubleSlider::singleStepValue() const
{
    int step = singleStep();
    float retVal = sliderValueFromPosition(step);
    return retVal;
}

void acQtDoubleSlider::debugOutput(const gtString& prefix, int number)
{
#if 0
    gtString dbg;
    dbg.appendFormattedString(L"%ls = %d\n", prefix.asCharArray(), number);
    osOutputDebugString(dbg);
#else
    GT_UNREFERENCED_PARAMETER(prefix);
    GT_UNREFERENCED_PARAMETER(number);
#endif
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::acDoubleSlider
// Description: Constructor
// Arguments:   itemId - The canvas item id.
//              position - The slider position inside the canvas.
//              width - The slider width (in pixels).
//              sliderMinPossibleVal - The slider minimum possible value
//              sliderMaxPossibleVal - The slider maximum possible value
// Author:      Eran Zinman
// Date:        2/11/2007
// ---------------------------------------------------------------------------
acDoubleSlider::acDoubleSlider(QWidget* pParent)
    : QWidget(pParent),
      m_sliderDataType(OA_FLOAT),
      m_floatAmountOfDigits(2),
      m_pDoubleSlider(NULL),
      m_pLeftValueTextCtrl(NULL),
      m_pRightValueTextCtrl(NULL),
      m_pMinValueText(NULL),
      m_pMaxValueText(NULL),
      m_needValidation(false)
{

    // Initialize the slider graphics
    initLayout();
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::~acDobuleSlider
// Description: Destructor
// Author:      Eran Zinman
// Date:        2/11/2007
// ---------------------------------------------------------------------------
acDoubleSlider::~acDoubleSlider()
{
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::displayTextError
// Description:
//   Displays a message box containing an error message of the format:
//   "Must be a numeric value between X and Y."
// Author:      Eran Zinman
// Date:        7/11/2007
// ---------------------------------------------------------------------------
void acDoubleSlider::displayTextError()
{
    GT_IF_WITH_ASSERT(m_pDoubleSlider != NULL)
    {
        // Build the error message:
        QString spinCtrlErrorMessage;
        spinCtrlErrorMessage.sprintf("Must be a numeric value between %.2f and %.2f", m_pDoubleSlider->m_sliderMinPossibleValue, m_pDoubleSlider->m_sliderMaxPossibleValue);

        // Display it to the user:
        acMessageBox::instance().critical("Error", spinCtrlErrorMessage);
    }
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::setSliderPositions
// Description: Updates the slider left and right positions
// Arguments:   newSliderLeftPosition - New slider left position
//              newSliderRightPosition - New slider right position
// Return Val:  bool - Success / Failure
// Author:      Eran Zinman
// Date:        7/11/2007
// ---------------------------------------------------------------------------
bool acDoubleSlider::setSliderPositions(double newSliderLeftPosition, double newSliderRightPosition)
{
    bool retVal = false;

    GT_IF_WITH_ASSERT(m_pDoubleSlider != NULL)
    {
        // Check that we are inside the range
        if ((newSliderLeftPosition >= m_pDoubleSlider->m_sliderMinPossibleValue) && (newSliderLeftPosition <= m_pDoubleSlider->m_sliderMaxPossibleValue))
        {
            if ((newSliderRightPosition >= m_pDoubleSlider->m_sliderMinPossibleValue) && (newSliderRightPosition <= m_pDoubleSlider->m_sliderMaxPossibleValue))
            {
                // Update the slider left and right values
                m_pDoubleSlider->m_currentSliderLeftValue = newSliderLeftPosition;
                m_pDoubleSlider->m_currentSliderRightValue = newSliderRightPosition;

                // Check if we need to readjust the range:
                if (m_pDoubleSlider->m_currentSliderLeftValue > m_pDoubleSlider->m_currentSliderRightValue)
                {
                    m_pDoubleSlider->m_currentSliderRightValue = m_pDoubleSlider->m_currentSliderLeftValue;
                }
                // Check if we need to re range:
                else if (m_pDoubleSlider->m_currentSliderRightValue < m_pDoubleSlider->m_currentSliderLeftValue)
                {
                    m_pDoubleSlider->m_currentSliderLeftValue = m_pDoubleSlider->m_currentSliderRightValue;
                }

                // Update the tick boxes positions:
                updateTextControls();

                retVal = true;
            }
        }
    }

    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::onDoubleSliderValuesChanged
// Description: Emit double slider position changed signal
// Author:      Sigal Algranaty
// Date:        28/6/2012
// ---------------------------------------------------------------------------
void acDoubleSlider::onDoubleSliderValuesChanged(double leftValue, double rightValue)
{
    // Notify my parent to my sliders position was changed:
    emit doubleSliderPositionChanged(leftValue, rightValue);

    // Update the text controls
    updateTextControls();
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::onTextChange
// Description: Is called when the text is updated inside one of the range
//              text boxes. It enables validation
// Author:      Bhattacharyya Koushik
// Date:        25/09/2012
// ---------------------------------------------------------------------------
void acDoubleSlider::onTextChange()
{
    m_needValidation = true;
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::onTextUpdate
// Description: Is called when the text is updated inside one of the range
//              text boxes. It checks if the input text is ok
// Arguments:   pEvent - The pEvent details
// Author:      Eran Zinman
// Date:        7/11/2007
// ---------------------------------------------------------------------------
void acDoubleSlider::onTextUpdate()
{
    if (!m_needValidation)
    {
        return;
    }

    m_needValidation = false;

    QLineEdit* pLineEditControl = qobject_cast<QLineEdit*>(sender());
    GT_IF_WITH_ASSERT(pLineEditControl != NULL)
    {
        // Get the new updated text, and trim it from left and right
        QString  updatedText = pLineEditControl->text().trimmed();

        // If the text box is not empty
        if (!updatedText.isEmpty())
        {
            // In order to make sure that the digits entered are building double number,
            // convert the string to a "double": and ignore the value
            bool isOK = false;
            double value = updatedText.toDouble(&isOK);

            // Sanity check
            GT_IF_WITH_ASSERT(m_pDoubleSlider != NULL)
            {
                if (((pLineEditControl == m_pLeftValueTextCtrl) && (value < m_pDoubleSlider->m_sliderMinPossibleValue)) ||
                    ((pLineEditControl == m_pRightValueTextCtrl) && (value > m_pDoubleSlider->m_sliderMaxPossibleValue)))
                {
                    isOK = false;
                }

            }

            if (!isOK)
            {
                // Notify the user that an error has occurred - value is incorrect
                displayTextError();

                // Revert the changes in the text controls:
                updateTextControls();

                // Set the focus back to the text control who triggered this error
                pLineEditControl->setFocus();
            }
        }// End of if (!updatedText.isEmpty())
    }
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::updatePossibleValuesLabels
// Description: Updates the possible values labels content
// Author:      Eran Zinman
// Date:        29/12/2007
// ---------------------------------------------------------------------------
void acDoubleSlider::updatePossibleValuesLabels()
{
    // Sanity check:
    GT_IF_WITH_ASSERT((m_pMinValueText != NULL) && (m_pMaxValueText != NULL))
    {
        // Create the minimum and maximum values strings:
        QString minValue;
        QString maxValue;

        QString formatString;
        bool rcFormat = FormatStrByDataType(formatString);
        GT_ASSERT(rcFormat);

        GT_IF_WITH_ASSERT(!formatString.isEmpty())
        {
            minValue.sprintf(formatString.toLatin1().data(), m_pDoubleSlider->m_sliderMinPossibleValue);
            maxValue.sprintf(formatString.toLatin1().data(), m_pDoubleSlider->m_sliderMaxPossibleValue);
        }

        // Add a "min" and "max" text to the values:
        minValue.append(" min");
        QString maxValueLabel = "max ";
        maxValueLabel.append(maxValue);
        maxValue = maxValueLabel;

        // Update the labels
        m_pMinValueText->setText(minValue);
        m_pMaxValueText->setText(maxValue);
        updateGeometry();
    }
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::initLayout
// Description: Initialize the slider layout
// Author:      Sigal Algranaty
// Date:        24/6/2012
// ---------------------------------------------------------------------------
void acDoubleSlider::initLayout()
{
    // Create the values text controls:
    m_pLeftValueTextCtrl = new acLineEdit(NULL);

    m_pLeftValueTextCtrl->resize(AC_DOUBLE_SLIDER_TEXT_BOXES_SIZE);

    m_pRightValueTextCtrl = new acLineEdit(NULL);

    m_pRightValueTextCtrl->resize(AC_DOUBLE_SLIDER_TEXT_BOXES_SIZE);

    // Reduce the text size inside the text controls
    QFont font = m_pLeftValueTextCtrl->font();
    font.setPointSize(font.pointSize() - 1);

    // Set the new font size and apply to both text controls
    m_pLeftValueTextCtrl->setFont(font);
    m_pRightValueTextCtrl->setFont(font);

    // Connect the text ctrl events:
    bool rc;
    rc = connect(m_pLeftValueTextCtrl, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChange()));
    GT_ASSERT(rc);

    rc = connect(m_pRightValueTextCtrl, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChange()));
    GT_ASSERT(rc);

    rc = connect(m_pLeftValueTextCtrl, SIGNAL(editingFinished()), this, SLOT(onTextUpdate()));
    GT_ASSERT(rc);
    rc = connect(m_pRightValueTextCtrl, SIGNAL(editingFinished()), this, SLOT(onTextUpdate()));
    GT_ASSERT(rc);

    // Create the grid layout for the slider:
    QGridLayout* pGridLayout = new QGridLayout;

    // Add the right and left text controls:
    pGridLayout->addWidget(m_pLeftValueTextCtrl, 0, 0, Qt::AlignLeft);
    pGridLayout->addWidget(m_pRightValueTextCtrl, 0, 1, Qt::AlignRight);

    // Create the double slider:
    m_pDoubleSlider = new acQtDoubleSlider;

    pGridLayout->addWidget(m_pDoubleSlider , 1, 0, 1, 2);

    rc = connect(m_pDoubleSlider, SIGNAL(spanChanged(double, double)), this, SLOT(onDoubleSliderValuesChanged(double, double)));
    GT_ASSERT(rc);

    // Updates the text controls values
    updateTextControls();

    // Now create them minimum and maximum values indicators:
    m_pMinValueText = new QLabel;

    m_pMaxValueText = new QLabel;

    // Updates the possible values labels content
    updatePossibleValuesLabels();

    pGridLayout->addWidget(m_pMinValueText, 2, 0, Qt::AlignLeft);
    pGridLayout->addWidget(m_pMaxValueText, 2, 1, Qt::AlignRight);

    // Set my layout:
    setLayout(pGridLayout);

    layout();
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::setSliderMinMaxPossibleValues
// Description: Sets the slider min / max values
// Arguments:   double minPossibleValue
//              double maxPossibleValue
// Author:      Sigal Algranaty
// Date:        3/7/2012
// ---------------------------------------------------------------------------
void acDoubleSlider::setSliderMinMaxPossibleValues(double minPossibleValue, double maxPossibleValue)
{
    float normalizedMaxPossibleValue = maxPossibleValue;
    float normalizedMinPossibleValue = minPossibleValue;

    // Calculate the requested digits for float display:
    double diff = fabs(maxPossibleValue - minPossibleValue);

    if (diff < 0.01)
    {
        m_floatAmountOfDigits = 3;
    }

    if (diff < 0.001)
    {
        m_floatAmountOfDigits = 4;
    }

    if (diff < 0.0001)
    {
        m_floatAmountOfDigits = 4;

        // Cut the float numbers to contain only 4 digits:
        QString number;
        number.sprintf("%2.4f", (float)maxPossibleValue);
        normalizedMaxPossibleValue = number.toDouble();
        number = "";
        number.sprintf("%2.4f", (float)minPossibleValue);
        normalizedMinPossibleValue = number.toDouble();
    }

    // Save the new minimum and maximum possible values
    m_pDoubleSlider->m_sliderMinPossibleValue = normalizedMinPossibleValue;
    m_pDoubleSlider->m_sliderMaxPossibleValue = normalizedMaxPossibleValue;

    m_pDoubleSlider->m_currentSliderLeftValue = m_pDoubleSlider->m_sliderMinPossibleValue;
    m_pDoubleSlider->m_currentSliderRightValue = m_pDoubleSlider->m_sliderMaxPossibleValue;

    // Updates the possible values labels content
    updatePossibleValuesLabels();
    updateTextControls();
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::setSliderDataType
// Description: Defines the slider data type and set the minimum and maximum
//              possible values according to the data type
// Arguments:   dataType - The slider data type
//              bool isOpenGL - is the data type displayed in OpenGL (for OpenGL
//.             the float values are in the range of 0 and 1)
// Return Val:  bool - Success / Failure
// Author:      Eran Zinman
// Date:        4/11/2007
// ---------------------------------------------------------------------------
bool acDoubleSlider::setSliderDataType(oaDataType dataType, bool isOpenGL)
{
    bool retVal = true;

    // Save the new data type
    m_sliderDataType = dataType;

    // Change the possible min and max values according to the data type
    switch (dataType)
    {
        case OA_UNSIGNED_BYTE:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = 0;
            m_pDoubleSlider->m_sliderMaxPossibleValue = UCHAR_MAX;
        }
        break;

        case OA_BYTE:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = CHAR_MIN;
            m_pDoubleSlider->m_sliderMaxPossibleValue = CHAR_MAX;
        }
        break;

        case OA_UNSIGNED_SHORT:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = 0;
            m_pDoubleSlider->m_sliderMaxPossibleValue = USHRT_MAX;
        }
        break;

        case OA_SHORT:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = SHRT_MIN;
            m_pDoubleSlider->m_sliderMaxPossibleValue = SHRT_MAX;
        }
        break;

        case OA_UNSIGNED_INT:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = (float)0;
            m_pDoubleSlider->m_sliderMaxPossibleValue = (float)UINT_MAX;
        }
        break;

        case OA_INT:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = (float)INT_MIN;
            m_pDoubleSlider->m_sliderMaxPossibleValue = (float)INT_MAX;
        }
        break;

        case OA_UNSIGNED_LONG:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = (float)0;
            m_pDoubleSlider->m_sliderMaxPossibleValue = (float)ULLONG_MAX;
        }
        break;

        case OA_LONG:
        {
            m_pDoubleSlider->m_sliderMinPossibleValue = (float)LLONG_MIN;
            m_pDoubleSlider->m_sliderMaxPossibleValue = (float)LLONG_MAX;
        }
        break;

        case OA_FLOAT:
        {
            if (isOpenGL)
            {
                // In openGL min and max for float are [0..1]
                m_pDoubleSlider->m_sliderMinPossibleValue = 0.0f;
                m_pDoubleSlider->m_sliderMaxPossibleValue = 1.0f;
            }
            else
            {
                m_pDoubleSlider->m_sliderMinPossibleValue = FLT_MAX * -1;
                m_pDoubleSlider->m_sliderMaxPossibleValue = FLT_MAX;
            }
        }
        break;

        case OA_DOUBLE:
        {
            if (isOpenGL)
            {
                // In openGL min and max for float are [0..1]
                m_pDoubleSlider->m_sliderMinPossibleValue = 0.0;
                m_pDoubleSlider->m_sliderMaxPossibleValue = 1.0;
            }
            else
            {
                m_pDoubleSlider->m_sliderMinPossibleValue = FLT_MAX * -1;
                m_pDoubleSlider->m_sliderMaxPossibleValue = FLT_MAX;
            }
        }
        break;

        default:
        {
            GT_ASSERT_EX(false, L"Unsupported Data Type!");
            retVal = false;
        }
        break;
    }

    GT_IF_WITH_ASSERT(retVal)
    {
        m_pDoubleSlider->m_currentSliderLeftValue = m_pDoubleSlider->m_sliderMinPossibleValue;
        m_pDoubleSlider->m_currentSliderRightValue = m_pDoubleSlider->m_sliderMaxPossibleValue;

        // Update min and max labels and tick positions:
        updatePossibleValuesLabels();
    }

    return retVal;
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::updateTextControls
// Description: Updates the text controls values
// Author:      Eran Zinman
// Date:        4/11/2007
// ---------------------------------------------------------------------------
void acDoubleSlider::updateTextControls()
{
    GT_IF_WITH_ASSERT(m_pLeftValueTextCtrl && m_pRightValueTextCtrl)
    {
        // Create the strings:
        QString leftTextCtrlValue;
        QString rightTextCtrlValue;

        QString formatString;
        bool rcFormat = FormatStrByDataType(formatString);
        GT_ASSERT(rcFormat);

        GT_IF_WITH_ASSERT(!formatString.isEmpty())
        {
            // Show float values:
            leftTextCtrlValue.sprintf(formatString.toLatin1().data(), m_pDoubleSlider->m_currentSliderLeftValue);
            rightTextCtrlValue.sprintf(formatString.toLatin1().data(), m_pDoubleSlider->m_currentSliderRightValue);
        }

        // Update the text controls
        m_pLeftValueTextCtrl->setText(leftTextCtrlValue);
        m_pRightValueTextCtrl->setText(rightTextCtrlValue);

        // Check if the text controls should be enabled:
        bool isEnabled = (m_pDoubleSlider->m_sliderMaxPossibleValue > m_pDoubleSlider->m_sliderMinPossibleValue);

        // Enable / Disable the text controls:
        m_pLeftValueTextCtrl->setEnabled(isEnabled);
        m_pRightValueTextCtrl->setEnabled(isEnabled);
    }
}

// ---------------------------------------------------------------------------
// Name:        acDoubleSlider::FormatStrByDataType
// Description: Return number format string according to the data type
// Return Val:  bool - Success / failure.
// Author:      Sigal Algranaty
// Date:        11/4/2011
// ---------------------------------------------------------------------------
bool acDoubleSlider::FormatStrByDataType(QString& formatStr)
{
    bool retVal = true;

    // Should we show floating point values?
    switch (m_sliderDataType)
    {
        case OA_FLOAT:
        case OA_DOUBLE:
        {
            // Show float values:
            // Notice: By default the float precision is 2 digits.
            // The precision can be changed if the values entered differences are smaller then 0.01:
            formatStr.clear();
            formatStr.sprintf("%%2.%df", m_floatAmountOfDigits);
        }
        break;

        // If normal numeric value (without floating point) just show round number:
        case OA_UNSIGNED_BYTE:
        case OA_BYTE:
        case OA_UNSIGNED_SHORT:
        case OA_SHORT:
        case OA_UNSIGNED_INT:
        case OA_INT:
        case OA_UNSIGNED_LONG:
        case OA_LONG:
        {
            formatStr = "%2.0f";
        }
        break;

        default:
        {
            formatStr = "%2.0f";
            GT_ASSERT_EX(false, L"Unsupported Data Type!");
            retVal = false;
        }
        break;
    }

    return retVal;
}


text:
Q: Flexbox item refusing to grow I'm trying to make a calculator website (codesandbox here). I have a problem where the decimal button on the calculator is not growing; for some reason it's smushed.
I'm using flexbox to display and align all the rows and buttons on the calculator. What I want is the zero button to be twice as big as the other number buttons. I want the operator buttons (=, +, etc.) to be aligned with each other as well.
I've tried messing around with width and flex css properties on my classes to no avail. I'm sure the solution is simple but for some reason it's eluding me.
Thank you for your time reading this. I appreciate any help you can give me.

A: The flex-grow CSS property sets the flex grow factor of a flex item's main size.
https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow
.decimal-button,
.equals-button {
  flex: 1;
}

.zero-button {
  flex: 2;
}

redpajama_set_name: RedPajamaStackExchange


According to statistics, the eLearning industry is expected to hit the $37.6 billion mark by 2020.
eLearning courses online are important in today's fast-growing world and many professionals from all sectors have opted to partake these courses to become better by advancing their skills and knowledge.
The greatest thing about eLearning courses is that contrary to full degree programs can equip a person with specific information about a topic. Online courses are also flexible when it comes to scheduling. Another greatest thing is that you can learn these courses from your country. You just need to enroll online and a professor or instructor will take you through the entire course in an interactive manner.
Online business courses cover the overall business aspects such as finance, accounting, and management among others.
Currently, there are lots of online courses available through platforms like Udemy, Coursera, edX and more. Whether you want a course to learn about academic writing, blogging, IT, business, you can get everything on these platforms.
If you are wondering how and where to partake eLearning courses online, then you have come to the right place.
In this post, I will share the top eLearning courses online particularly for corporate as listed in the cheap writing services platform. I hope you will be able to choose the one that suits your professional goals and needs.
Finding the right eLearning course is one thing and getting the right one is another. Enrolling for a course that does not suit your professional goals and needs can be frustrating in the end. With hundreds of thousands of online courses, how can you find the right one for yourself?
Use these tips to choose a course that suits your needs and goals.
The first step to choosing a course is to decide what you want to achieve from the course. Do you want to boost your skills? Do you want to advance your knowledge? Do you want to enroll for to the course to pass time? Do you have the time to partake the course? What topics are you interested in? This should be the first thing to establish before you start looking for a course.
Well, chances are that there are topics that you already know about, but your aim should be to take a topic that you are interested in. Remember, you are investing time and possibly money on the course. Also, ensure it is possible to apply the knowledge you obtain from the course as soon as possible.
Once you have enough idea of the course you want to take, take some time to research more about it. This way, you will be able to learn more about it before you start learning.
It is very important to take some time to read the entire course descriptions carefully. This way, you will be able to understand the course deeper, know about the syllabus and what follows the course at the end. Also, this is the best step to know who the course is meant for so that you know if it is right for you or not. The online world has tons of courses for people with no experience of a topic to professionals. You need to pick a course that matches your experience.
Once you have decided what you want from the course, you have picked a topic, done enough research on the topic, you've read the course descriptions thoroughly and you are satisfied with the course, you can now start learning.
Business Foundations Specialization is an online course available on Coursera and is meant to equip you with basic literacy in all business terms and languages. The knowledge you obtain after taking this course will help you to start or improve your small business or enroll in a business school to further your career.
There are 6 courses namely; Marketing, Financial Accounting, Managing Social and Human Capital, Introduction to Corporate, Introduction to Operations Management, and Wharton Business Foundations.
All these courses are administered by professionals who are experts in their fields of specialization. At the end of every successful course, there is a hands-on-project which upon completion earns you a Certificate.
Another course that is also available on Coursera is Business Analytics Specialization that helps you understand how data analysts utilize data when it comes to undertaking crucial business decisions especially in areas of human resources, marketing, operations, and finance.
This course will also equip you with basic data knowledge as well as analytic knowhow that can help you to use data to make calculated decisions. The course is suitable for all business professionals and people with little or no analytics knowledge.
Business Analytics Specialization is administered in 5 courses namely; Customer Analytics, Operations Analytics, People Analytics, Accounting Analytics, Business Analytics Capstone. At the end of the courses, you will be able to apply the knowledge you have obtained to interpret a real-world data set and come up with appropriate strategic business decisions.
Another eLearning course available on Coursera is How to Start Your Own Business.
Ever dreamt about starting your own business? Well, almost everyone in this era dreams of running their own business but knowing the implications of starting a business is important than starting one.
In fact, with many businesses failing within their first year of inception, it is crucial to equip yourself with all the knowledge in order to make an informed decision. This course was introduced by Michigan State University and equips you with an entrepreneurial mindset, creation of a business plan, generating business ideas and developing a business model.
It has 6 courses namely; Developing an Entrepreneurial Mindset, The Search for Great Ideas, Planning, Structure, Launch Strategy, and Capstone. The courses take three to seven weeks to complete, but you can choose the one that suits your needs.
How to Start Your Own Business is suitable for those people who want to be their own bosses by starting their own businesses.
Strategic Leadership and Management Specialization will equip you with skills to effectively lead people and manage organizations. You will also learn the tools that are necessary when it comes to analyzation of business situations.
The course covers the fundamentals of everyday leadership, day to day leadership practice, designing the organization, managing the organization, business and corporate strategy, strategic leadership, and management.
There you have it; tips to choose the right course and a list of 4 eLearning courses online. Note that these are not the only courses out there but they are the best when it comes to maters to do with business. I hope this article will serve as an inspiration and will guide you as you choose your online course.
Author Bio: Tiffany Harper is a talented writer from New York, an extremely active woman, and a real leader. She began her career as a journalist and later proceeded it as an educational writer and editor. Now she works as an experienced freelance writer with cheap writing services, mostly in technology, business and education area. Please do not hesitate to contact her on Google+ or Twitter.
Next articleIs Your Cloud-based LMS the Ideal Platform to Train Employees?