text:
#include <QDate>
#include <QLocale>
#include <QTime>
#include <QVariant>
#include <QThread>
#include <QStringList>

#include <e32std.h>
#include <e32const.h>
#include <e32base.h>
#include <e32property.h>
#include <numberconversion.h>
#include <bacntf.h>
#include "private/qcore_symbian_p.h"
#include "private/qcoreapplication_p.h"
#include "private/qlocale_p.h"
#include <qdebug.h>

QT_BEGIN_NAMESPACE

static TExtendedLocale _s60Locale;

/*
  Definition of struct for mapping Symbian to ISO locale
*/
struct symbianToISO {
    int symbian_language;
    char iso_name[8];
    char uilanguage[8];
};

/*
  Mapping from Symbian to ISO locale.
  NOTE: This array should be sorted by the first column!
*/
static const symbianToISO symbian_to_iso_list[] = {
    { ELangEnglish,             "en_GB", "en" },    // 1
    { ELangFrench,              "fr_FR", "fr" },    // 2
    { ELangGerman,              "de_DE", "de" },    // 3
    { ELangSpanish,             "es_ES", "es" },    // 4
    { ELangItalian,             "it_IT", "it" },    // 5
    { ELangSwedish,             "sv_SE", "sv" },    // 6
    { ELangDanish,              "da_DK", "da" },    // 7
    { ELangNorwegian,           "nb_NO", "nb" },    // 8
    { ELangFinnish,             "fi_FI", "fi" },    // 9
    { ELangAmerican,            "en_US", "en-US" }, // 10
    { ELangPortuguese,          "pt_PT", "pt" },    // 13
    { ELangTurkish,             "tr_TR", "tr" },    // 14
    { ELangIcelandic,           "is_IS", "is" },    // 15
    { ELangRussian,             "ru_RU", "ru" },    // 16
    { ELangHungarian,           "hu_HU", "hu" },    // 17
    { ELangDutch,               "nl_NL", "nl" },    // 18
    { ELangCzech,               "cs_CZ", "cs" },    // 25
    { ELangSlovak,              "sk_SK", "sk" },    // 26
    { ELangPolish,              "pl_PL", "pl" },    // 27
    { ELangSlovenian,           "sl_SI", "sl" },    // 28
    { ELangTaiwanChinese,       "zh_TW", "zh-TW" }, // 29
    { ELangHongKongChinese,     "zh_HK", "zh-HK" }, // 30
    { ELangPrcChinese,          "zh_CN", "zh" },    // 31
    { ELangJapanese,            "ja_JP", "ja" },    // 32
    { ELangThai,                "th_TH", "th" },    // 33
    { ELangArabic,              "ar_AE", "ar" },    // 37
    { ELangTagalog,             "tl_PH", "tl" },    // 39
    { ELangBulgarian,           "bg_BG", "bg" },    // 42
    { ELangCatalan,             "ca_ES", "ca" },    // 44
    { ELangCroatian,            "hr_HR", "hr" },    // 45
    { ELangEstonian,            "et_EE", "et" },    // 49
    { ELangFarsi,               "fa_IR", "fa" },    // 50
    { ELangCanadianFrench,      "fr_CA", "fr-CA" }, // 51
    { ELangGreek,               "el_GR", "el" },    // 54
    { ELangHebrew,              "he_IL", "he" },    // 57
    { ELangHindi,               "hi_IN", "hi" },    // 58
    { ELangIndonesian,          "id_ID", "id" },    // 59
    { 63/*ELangKazakh*/,        "kk_KZ", "kk" },    // 63
    { ELangKorean,              "ko_KO", "ko" },    // 65
    { ELangLatvian,             "lv_LV", "lv" },    // 67
    { ELangLithuanian,          "lt_LT", "lt" },    // 68
    { ELangMalay,               "ms_MY", "ms" },    // 70
    { ELangNorwegianNynorsk,    "nn_NO", "nn" },    // 75
    { ELangBrazilianPortuguese, "pt_BR", "pt-BR" }, // 76
    { ELangRomanian,            "ro_RO", "ro" },    // 78
    { ELangSerbian,             "sr_RS", "sr" },    // 79
    { ELangLatinAmericanSpanish,"es_419", "es-419" },// 83
    { ELangUkrainian,           "uk_UA", "uk" },    // 93
    { ELangUrdu,                "ur_PK", "ur" },    // 94 - India/Pakistan
    { ELangVietnamese,          "vi_VN", "vi" },    // 96
#ifdef __E32LANG_H__
// 5.0
    { ELangBasque,              "eu_ES", "eu" },    // 102
    { ELangGalician,            "gl_ES", "gl" },    // 103
#endif
#if !defined(__SERIES60_31__)
    { ELangEnglish_Apac,        "en_GB", "en" },     // 129
    { ELangEnglish_Taiwan,      "en_TW", "en-TW" },  // 157 ### Not supported by CLDR
    { ELangEnglish_HongKong,    "en_HK", "en-HK" },  // 158
    { ELangEnglish_Prc,         "en_CN", "en-CN" },  // 159 ### Not supported by CLDR
    { ELangEnglish_Japan,       "en_JP", "en" },     // 160 ### Not supported by CLDR
    { ELangEnglish_Thailand,    "en_TH", "en" },     // 161 ### Not supported by CLDR
    { 230/*ELangEnglish_India*/,"en_IN", "en" },     // 230
    { ELangMalay_Apac,          "ms_MY", "ms" },     // 326
#endif
    { 327/*ELangIndonesian_Apac*/, "id_ID", "id" }   // 327 - appeared in Symbian^3
};

enum LocaleNameType {
    ISO,
    UILanguage
};

QByteArray qt_resolveSymbianLocaleName(int code, LocaleNameType type)
{
    //Number of Symbian to ISO locale mappings
    static const int symbian_to_iso_count
        = sizeof(symbian_to_iso_list)/sizeof(symbianToISO);

    int cmp = code - symbian_to_iso_list[0].symbian_language;
    if (cmp < 0)
        return 0;

    if (cmp == 0) {
        if (type == ISO)
            return symbian_to_iso_list[0].iso_name;
        return symbian_to_iso_list[0].uilanguage;
    }

    int begin = 0;
    int end = symbian_to_iso_count;

    while (end - begin > 1) {
        uint mid = (begin + end)/2;

        const symbianToISO *elt = symbian_to_iso_list + mid;
        int cmp = code - elt->symbian_language;
        if (cmp < 0) {
            end = mid;
        } else if (cmp > 0) {
            begin = mid;
        } else {
            if (type == ISO)
                return elt->iso_name;
            return elt->uilanguage;
        }
    }

    return 0;
}

/*!
    Returns ISO name corresponding to the Symbian locale code \a sys_fmt.
*/
QByteArray qt_symbianLocaleName(int code)
{
    return qt_resolveSymbianLocaleName(code, ISO);
}

// Rows are: normal, abbr, nmode, nmode+abbr
// First three values on a row are used for three component date,
// while the last two are used for two component date (i.e. no year).
static const char *us_locale_dep[] = {
    "MM", "dd", "yyyy", "MM", "dd",
    "M", "d", "yy", "M", "d",
    "MMMM", "dd", "yyyy", "MMMM", "dd",
    "MMM", "d", "yy", "MMM", "d" };

static const char *eu_locale_dep[] = {
    "dd", "MM", "yyyy", "dd", "MM",
    "d", "M", "yy", "d", "M",
    "dd", "MMMM", "yyyy", "dd", "MMMM",
    "d", "MMM", "yy", "d", "MMM" };

static const char *jp_locale_dep[] = {
    "yyyy", "MM", "dd", "MM", "dd",
    "yy", "M", "d", "M", "d",
    "yyyy", "MMMM", "dd", "MMMM", "dd",
    "yy", "MMM", "d", "MMM", "d" };

// 0 = day, 1 = month, 2 = year
static const int digit_map[] = {
    1, 0, 2, 1, 0, // American
    0, 1, 2, 0, 1, // European
    2, 1, 0, 1, 0  // Japanese
};

/*!
    Returns a Qt version of the given \a sys_fmt Symbian locale format string.
*/
static QString s60ToQtFormat(const QString &sys_fmt)
{
    TLocale *locale = _s60Locale.GetLocale();

    QString result;
    QString other;
    QString qtformatchars = QString::fromLatin1("adhmsyzAHM");

    QChar c;
    int i = 0;
    bool open_escape = false;
    bool abbrev_next = false;
    bool abbrev_day = false;
    bool abbrev_month = false;
    bool abbrev_year = false;
    bool locale_indep_ordering = false;
    bool minus_mode = false;
    bool plus_mode = false;
    bool n_mode = false;
    TTimeFormat tf = locale->TimeFormat();

    while (i < sys_fmt.size()) {

        c = sys_fmt.at(i);

        // let formatting thru
        if (c.unicode() == '%') {
            // if we have gathered string, concat it
            if (!other.isEmpty()) {
                result += other;
                other.clear();
            }
            // if we have open escape, end it
            if (open_escape) {
                result += QLatin1Char('\'');
                open_escape = false;
            }

            ++i;
            if (i >= sys_fmt.size())
                break;

            c = sys_fmt.at(i);

            // process specials
            abbrev_next = c.unicode() == '*';
            plus_mode = c.unicode() == '+';
            minus_mode = c.unicode() == '-';

            if (abbrev_next || plus_mode || minus_mode) {
                ++i;
                if (i >= sys_fmt.size())
                    break;

                c = sys_fmt.at(i);

                if (plus_mode || minus_mode) {
                    // break on undefined plus/minus mode
                    if (c.unicode() != 'A' && c.unicode() != 'B')
                        break;
                }
            }

            switch (c.unicode()) {
                case 'F':
                {
                    // locale indep mode on
                    locale_indep_ordering = true;
                    break;
                }

                case '/':
                {
                    // date sep 0-3
                    ++i;
                    if (i >= sys_fmt.size())
                        break;

                    c = sys_fmt.at(i);
                    if (c.isDigit() && c.digitValue() <= 3) {
                        TChar s = locale->DateSeparator(c.digitValue());
                        TUint val = s;
                        // some indexes return zero for empty
                        if (val > 0)
                            result += QChar(val);
                    }
                    break;
                }

                case 'D':
                {
                    if (!locale_indep_ordering) {
                        if (abbrev_next)
                            abbrev_day = true;
                        break;
                    }

                    if (!abbrev_next)
                        result += QLatin1String("dd");
                    else
                        result += QLatin1Char('d');

                    break;
                }

                case 'M':
                {
                    if (!locale_indep_ordering) {
                        if (abbrev_next)
                            abbrev_month = true;
                        break;
                    }

                    if (!n_mode) {
                        if (!abbrev_next)
                            result += QLatin1String("MM");
                        else
                            result += QLatin1String("M");
                    } else {
                        if (!abbrev_next)
                            result += QLatin1String("MMMM");
                        else
                            result += QLatin1String("MMM");
                    }

                    break;
                }

                case 'N':
                {
                    n_mode = true;

                    if (!locale_indep_ordering) {
                        if (abbrev_next)
                            abbrev_month = true;
                        break;
                    }

                    if (!abbrev_next)
                        result += QLatin1String("MMMM");
                    else
                        result += QLatin1String("MMM");

                    break;
                }

                case 'Y':
                {
                    if (!locale_indep_ordering) {
                        if (abbrev_next)
                            abbrev_year = true;
                        break;
                    }

                    if (!abbrev_next)
                        result += QLatin1String("yyyy");
                    else
                        result += QLatin1String("yy");

                    break;
                }

                case 'E':
                {
                    if (!abbrev_next)
                        result += QLatin1String("dddd");
                    else
                        result += QLatin1String("ddd");

                    break;
                }

                case ':':
                {
                    // timesep 0-3
                    ++i;
                    if (i >= sys_fmt.size())
                        break;

                    c = sys_fmt.at(i);
                    if (c.isDigit() && c.digitValue() <= 3) {
                        TChar s = locale->TimeSeparator(c.digitValue());
                        TUint val = s;
                        // some indexes return zero for empty
                        if (val > 0)
                            result += QChar(val);
                    }

                    break;
                }

                case 'J':
                {
                    if (tf == ETime24 && !abbrev_next)
                        result += QLatin1String("hh");
                    else
                        result += QLatin1Char('h');

                    break;
                }

                case 'H':
                {
                    if (!abbrev_next)
                        result += QLatin1String("hh");
                    else
                        result += QLatin1Char('h');

                    break;
                }

                case 'I':
                {
                    result += QLatin1Char('h');
                    break;
                }

                case 'T':
                {
                    if (!abbrev_next)
                        result += QLatin1String("mm");
                    else
                        result += QLatin1Char('m');

                    break;
                }

                case 'S':
                {
                    if (!abbrev_next)
                        result += QLatin1String("ss");
                    else
                        result += QLatin1Char('s');

                    break;
                }

                case 'B':
                {
                    // only done for 12h clock
                    if (tf == ETime24)
                        break;
                }

                    // fallthru to A
                case 'A': {
                    // quickie to get capitalization, can't use s60 string as is because Qt 'hh' format's am/pm logic
                    TAmPmName ampm = TAmPmName();
                    TChar first(ampm[0]);
                    QString qtampm = QString::fromLatin1(first.IsUpper() ? "AP" : "ap");

                    int pos = locale->AmPmSymbolPosition();

                    if ((minus_mode && pos != ELocaleBefore) ||
                        (plus_mode && pos != ELocaleAfter))
                        break;

                    if (!abbrev_next && locale->AmPmSpaceBetween()) {
                        if (pos == ELocaleBefore)
                            qtampm.append(QLatin1Char(' '));
                        else
                            qtampm.prepend(QLatin1Char(' '));
                    }

                    result += qtampm;
                    }
                    break;

                case '.': {
                        // decimal sep
                        TChar s = locale->DecimalSeparator();
                        TUint val = s;
                        if (val > 0)
                            result += QChar(val);
                    }
                    break;

                case 'C':
                {
                    // six digits in s60, three digits in qt
                    if (!abbrev_next) {
                        result += QLatin1String("zzz");
                    } else {
                        // next char is number from 0-6, how many digits to display
                        ++i;
                        if (i >= sys_fmt.size())
                            break;

                        c = sys_fmt.at(i);

                        if (c.isDigit()) {
                            // try to match wanted digits
                            QChar val(c.digitValue());

                            if (val >= 3) {
                                result += QLatin1String("zzz");
                            } else if (val > 0) {
                                result += QLatin1Char('z');
                            }
                        }
                    }
                    break;
                }

                // these cases fallthru
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                {

                    // shouldn't parse these with %F
                    if (locale_indep_ordering)
                        break;

                    TDateFormat df = locale->DateFormat();

                    const char **locale_dep;
                    switch (df) {
                        default:
                            df = EDateAmerican;
                            // fallthru to american
                        case EDateAmerican:
                            locale_dep = us_locale_dep;
                            break;
                        case EDateEuropean:
                            locale_dep = eu_locale_dep;
                            break;
                        case EDateJapanese:
                            locale_dep = jp_locale_dep;
                            break;
                    }
                    int offset = 0;
                    int adjustedDigit = c.digitValue() - 1;

                    bool abbrev_this = abbrev_next;
                    // If abbreviation specified for this digit, use that.
                    // Otherwise abbreviate according to %D, %M, and %Y specified previously.
                    if (!abbrev_this) {
                        switch (digit_map[adjustedDigit + (static_cast<int>(df) * 5)]) {
                            case 0:
                                abbrev_this = abbrev_day;
                                break;
                            case 1:
                                abbrev_this = abbrev_month;
                                break;
                            case 2:
                                abbrev_this = abbrev_year;
                                break;
                            default:
                                break; // never happens
                        }
                    }

                    if (abbrev_this)
                        offset += 5;
                    if (n_mode)
                        offset += 10;

                    result += QLatin1String(locale_dep[offset + (adjustedDigit)]);
                    break;
                }

                case '%': // fallthru percent
                {
                // any junk gets copied as is
                }
                default:
                {
                    result += c;
                    break;
                }

                case 'Z': // Qt doesn't support these :(
                case 'X':
                case 'W':
                {
                    break;
                }
            }
        } else {
            // double any single quotes, don't begin escape
            if (c.unicode() == '\'') {
                // end open escape
                if (open_escape) {
                    result += other;
                    other.clear();
                    result += QLatin1Char('\'');
                    open_escape = false;
                }

                other += c;
            }

            // gather chars and escape them in one go if any format chars are found
            if (!open_escape && qtformatchars.indexOf(c) != -1) {
                result += QLatin1Char('\'');
                open_escape = true;
            }
            other += c;
        }

        ++i;
    }

    if (!other.isEmpty())
        result += other;
    if (open_escape)
        result += QLatin1Char('\'');

    return result;
}

/*!
    Retrieves Symbian locale decimal separator.
*/
static QString symbianDecimalPoint()
{
    TLocale *locale = _s60Locale.GetLocale();

    TChar decPoint = locale->DecimalSeparator();
    int val = decPoint;
    return QChar(val);
}

/*!
    Retrieves Symbian locale group separator.
*/
static QString symbianGroupSeparator()
{
    TLocale *locale = _s60Locale.GetLocale();

    TChar grpSep = locale->ThousandsSeparator();
    int val = grpSep;
    return QChar(val);
}

/*!
    Retrieves Symbian locale zero digit.
*/
static QString symbianZeroDigit()
{
    TLocale *locale = _s60Locale.GetLocale();

    // TDigitType enumeration value returned by TLocale
    // will always correspond to zero digit unicode value.
    TDigitType digit = locale->DigitType();
    return QChar(digit);
}

/*!
    Retrieves a day name from Symbian locale. The \a day is an integer
    from 1 to 7. When \a short_format is true the method returns
    the day in short format. Otherwise it returns the day in a long format.
*/
static QString symbianDayName(int day, bool short_format)
{
    day -= 1;

    if (day < 0 || day > 6)
        return QString();

    if (short_format) {
        return qt_TDes2QString(TDayNameAbb(TDay(day)));
    } else {
        return qt_TDes2QString(TDayName(TDay(day)));
    }
}

/*!
    Retrieves a month name from Symbian locale. The \a month is an integer
    from 1 to 12. When \a short_format is true the method returns
    the month in short format. Otherwise it returns the month in a long format.
*/
static QString symbianMonthName(int month, bool short_format)
{
    month -= 1;
    if (month < 0 || month > 11)
        return QString();

    if (short_format) {
        return qt_TDes2QString(TMonthNameAbb(TMonth(month)));
    } else {
        return qt_TDes2QString(TMonthName(TMonth(month)));
    }
}

/*!
    Retrieves date format from Symbian locale and
    transforms it to Qt format.

    When \a short_format is true the method returns
    short date format. Otherwise it returns the long format.
*/
static QString symbianDateFormat(bool short_format)
{
    TPtrC dateFormat;

    if (short_format) {
        dateFormat.Set(_s60Locale.GetShortDateFormatSpec());
    } else {
        dateFormat.Set(_s60Locale.GetLongDateFormatSpec());
    }

    return s60ToQtFormat(qt_TDesC2QString(dateFormat));
}

/*!
    Retrieves time format from Symbian locale and
    transforms it to Qt format.
*/
static QString symbianTimeFormat()
{
    return s60ToQtFormat(qt_TDesC2QString(_s60Locale.GetTimeFormatSpec()));
}

/*!
    Returns localized string representation of given \a date
    formatted with Symbian locale date format.

    If \a short_format is true the format will be a short version.
    Otherwise it uses a longer version.
*/
static QString symbianDateToString(const QDate &date, bool short_format)
{
    int month = date.month() - 1;
    int day = date.day() - 1;
    int year = date.year();

    TDateTime dateTime;
    dateTime.Set(year, TMonth(month), day, 0, 0, 0, 0);

    TTime timeStr(dateTime);
    TBuf<KMaxLongDateFormatSpec*2> buffer;

    TPtrC dateFormat;
    if (short_format) {
        dateFormat.Set(_s60Locale.GetShortDateFormatSpec());
    } else {
        dateFormat.Set(_s60Locale.GetLongDateFormatSpec());
    }

    TLocale *formatLocale = _s60Locale.GetLocale();
    TRAPD(err, timeStr.FormatL(buffer, dateFormat, *formatLocale);)

    if (err == KErrNone) {
        NumberConversion::ConvertDigits(buffer, formatLocale->DigitType());
        return qt_TDes2QString(buffer);
    } else {
        return QString();
    }
}

/*!
    Returns localized string representation of given \a time
    formatted with Symbian locale time format.
*/
static QString symbianTimeToString(const QTime &time)
{
    int hour = time.hour();
    int minute = time.minute();
    int second = time.second();
    int milliseconds = 0;

    TDateTime dateTime;
    dateTime.Set(0, TMonth(0), 0, hour, minute, second, milliseconds);

    TTime timeStr(dateTime);
    TBuf<KMaxTimeFormatSpec*2> buffer;

    TLocale *formatLocale = _s60Locale.GetLocale();
    TRAPD(err, timeStr.FormatL(buffer, _s60Locale.GetTimeFormatSpec(), *formatLocale);)

    if (err == KErrNone) {
        NumberConversion::ConvertDigits(buffer, formatLocale->DigitType());
        return qt_TDes2QString(buffer);
    } else {
        return QString();
    }
}

/*!
    Returns the measurement system stored in Symbian locale

    \sa QLocale::MeasurementSystem
*/
static QLocale::MeasurementSystem symbianMeasurementSystem()
{
    TLocale *locale = _s60Locale.GetLocale();

    TUnitsFormat unitFormat = locale->UnitsGeneral();
    if (unitFormat == EUnitsImperial)
        return QLocale::ImperialSystem;
    else
        return QLocale::MetricSystem;
}

void qt_symbianUpdateSystemPrivate()
{
    // load system data before query calls
    _s60Locale.LoadSystemSettings();
}

QLocale QSystemLocale::fallbackLocale() const
{
    TLanguage lang = User::Language();
    QString locale = QLatin1String(qt_symbianLocaleName(lang));
    return QLocale(locale);
}

static QStringList symbianUILanguages()
{
    TLanguage lang = User::Language();
    QString s = QLatin1String(qt_resolveSymbianLocaleName(lang, UILanguage));
    return QStringList(s);
}

QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
{
    switch(type) {
        case DecimalPoint:
            return symbianDecimalPoint();
        case GroupSeparator:
            return symbianGroupSeparator();

        case ZeroDigit:
             return symbianZeroDigit();

        case DayNameLong:
        case DayNameShort:
            return symbianDayName(in.toInt(), (type == DayNameShort) );

        case MonthNameLong:
        case MonthNameShort:
            return symbianMonthName(in.toInt(), (type == MonthNameShort) );

        case DateFormatLong:
        case DateFormatShort:
            return symbianDateFormat( (type == DateFormatShort) );
        case TimeFormatLong:
        case TimeFormatShort:
            return symbianTimeFormat();
        case DateTimeFormatLong:
        case DateTimeFormatShort:
            return QString(symbianDateFormat( (type == DateTimeFormatShort) ) + QLatin1Char(' ') + symbianTimeFormat());
        case DateToStringShort:
        case DateToStringLong:
             return symbianDateToString(in.toDate(), (type == DateToStringShort) );
        case TimeToStringShort:
        case TimeToStringLong:
             return symbianTimeToString(in.toTime());
        case DateTimeToStringShort:
        case DateTimeToStringLong: {
                const QDateTime dt = in.toDateTime();
                return QString(symbianDateToString(dt.date(), (type == DateTimeToStringShort) )
                       + QLatin1Char(' ') + symbianTimeToString(dt.time()));
            }
        case MeasurementSystem:
            return static_cast<int>(symbianMeasurementSystem());
        case LanguageId:
        case CountryId: {
                TLanguage language = User::Language();
                QString locale = QLatin1String(qt_symbianLocaleName(language));
                QLocale::Language lang;
                QLocale::Script script;
                QLocale::Country cntry;
                QLocalePrivate::getLangAndCountry(locale, lang, script, cntry);
                if (type == LanguageId)
                    return lang;
                // few iso codes have no country and will use this
                if (cntry == QLocale::AnyCountry)
                    return fallbackLocale().country();

                return cntry;
            }
        case ScriptId:
            return QVariant(QLocale::AnyScript);
        case NegativeSign:
        case PositiveSign:
            break;
        case AMText:
            return qt_TDes2QString(TAmPmName(TAmPm(EAm)));
        case PMText:
            return qt_TDes2QString(TAmPmName(TAmPm(EPm)));
        case UILanguages:
            return QVariant(symbianUILanguages());
        default:
            break;
    }
    return QVariant();
}

#if !defined(QT_NO_SYSTEMLOCALE)
QEnvironmentChangeNotifier::QEnvironmentChangeNotifier()
{
    // Create the change notifier and install the callback function
    const TCallBack callback(&QEnvironmentChangeNotifier::localeChanged, this);
    QT_TRAP_THROWING(iChangeNotifier = CEnvironmentChangeNotifier::NewL(CActive::EPriorityStandard, callback));
    iChangeNotifier->Start();
}

TInt QEnvironmentChangeNotifier::localeChanged(TAny *data)
{
    QEnvironmentChangeNotifier *that = reinterpret_cast<QEnvironmentChangeNotifier *>(data);

    TInt flag = that->iChangeNotifier->Change();
    if (flag & EChangesLocale) {
        static bool first = true;
        if (!first) { // skip the first notification on app startup
            QT_TRYCATCH_LEAVING(QLocalePrivate::updateSystemPrivate());
            QT_TRYCATCH_LEAVING(QCoreApplication::postEvent(qApp, new QEvent(QEvent::LocaleChange)));
        }
        first = false;
    }
    return KErrNone;
}

QEnvironmentChangeNotifier::~QEnvironmentChangeNotifier()
{
    delete iChangeNotifier;
}
#endif

QT_END_NAMESPACE


text:
/**
 * @fileoverview Blocks for lexically scoped variables in App Inventor
 * @author fturbak@wellesley.edu (Lyn Turbak)
 */
'use strict';

/*
 Lyn's History:
   [lyn, 11/18/12] Renaming for globals (still working on renaming of procedure and loop params)
   [lyn, 11/17/12] Integration of simple naming into App Inventor
   [lyn, 11/11/12] More work on onchange event. Allow invalid names for untethered getters/setters
                   on workspace, but not when click in to other blocks.
   [lyn, 11/08-10/12] Get dropdown list of names in scope to work for globals and params
                      (including loops) in raw blockly. Pass along to Andrew for integration
                      into AI. Initial work on onchange event to change names when getters/setters
                      copied and moved.
   [lyn, 11/05-07/12] Add local variable declaration expressions. Get mutator working for local
                      declaration statements and expressions. But these don't save/load properly from XML
                      Helpful 10/7 hangout with Andrew and Paul.
   [lyn, 11/04/12] Created. Add global declarations. Work on local variable declaration statement.

 Lyn's Todo List
 * Renaming of globals, procedure params, locals.
 * Saving/restoring of local declaration statements and expressions
 * Correctly handle decl name changes with open mutator in local declaration stm/exp.
 * Handling of getters/setters in copies of non-top-level blocks on desktop.
 * Effect system for global definition initializers and topologically sorting them by dependency.
*/

/*
// For debugging only
function myStringify (obj) {
  var seen = [];
  return JSON.stringify(obj, function(key, val) {
   if (typeof val == "object") {
       if (seen.indexOf(val) >= 0) {
           return undefined;
       }
       seen.push(val);
   }
   return val
   });
}
*/

Blockly.Language.global_declaration = {
  // Global var defn
  category: Blockly.MSG_VARIABLE_CATEGORY,
  helpUrl: "http://fakewebsite.com", // *** [lyn, 11/10/12] Fix this
  init: function() {
    this.setColour(Blockly.VARIABLE_CATEGORY_HUE);
    this.appendValueInput('VALUE')
        .appendTitle("initialize global")
        .appendTitle(new Blockly.FieldTextInput('name', Blockly.LexicalVariable.renameGlobal), 'NAME')
        .appendTitle("to");
    this.setTooltip(Blockly.LANG_VARIABLES_GET_TOOLTIP_1);
  },
  onchange: Blockly.WarningHandler.checkErrors,
  getVars: function() {
    return [this.getTitleValue('VAR')];
  },
  renameVar: function(oldName, newName) {
    if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) {
      this.setTitleValue(newName, 'VAR');
    }
  }
};

Blockly.Language.lexical_variable_get = {
  // Variable getter.
  category: Blockly.MSG_VARIABLE_CATEGORY,
  helpUrl: "http://fakewebsite.com", // *** [lyn, 11/10/12] Fix this
  init: function() {
    this.setColour(Blockly.VARIABLE_CATEGORY_HUE);
    this.fieldVar_ = new Blockly.FieldLexicalVariable(" ");
    this.fieldVar_.setBlock(this);
    this.appendDummyInput()
        .appendTitle("get")
        .appendTitle(this.fieldVar_, 'VAR');
    this.setOutput(true, null);
    this.setTooltip(Blockly.LANG_VARIABLES_GET_TOOLTIP_1);
    this.errors = [{name:"checkIsInDefinition"},{name:"checkDropDownContainsValidValue",dropDowns:["VAR"]}]
  },
  getVars: function() {
    return [this.getTitleValue('VAR')];
  },
  onchange: function() {
     // [lyn, 11/10/12] Checks if parent has changed. If so, checks if curent variable name
     //    is still in scope. If so, keeps it as is; if not, changes to ???
     //    *** NEED TO MAKE THIS BEHAVIOR BETTER!
    if (this.fieldVar_) {
       var currentName = this.fieldVar_.getText();
       var nameList = this.fieldVar_.getNamesInScope();
       var cachedParent = this.fieldVar_.getCachedParent();
       var currentParent = this.fieldVar_.getBlock().getParent();
       // [lyn, 11/10/12] Allow current name to stay if block moved to workspace in "untethered" way.
       //   Only changed to ??? if tether an untethered block.
       if (currentParent != cachedParent) {
         this.fieldVar_.setCachedParent(currentParent);
         if  (currentParent != null) {
           for (var i = 0; i < nameList.length; i++ ) {
             if (nameList[i] === currentName) {
               return; // no change
             }
           }
           // Only get here if name not in list
           this.fieldVar_.setText(" ");
         }
       }
    }
    Blockly.WarningHandler.checkErrors.call(this);
  },
  renameLexicalVar: function(oldName, newName) {
    // console.log("Renaming lexical variable from " + oldName + " to " + newName);
    if (oldName === this.getTitleValue('VAR')) {
        this.setTitleValue(newName, 'VAR');
    }
  }
};

Blockly.Language.lexical_variable_set = {
  // Variable setter.
  category: Blockly.MSG_VARIABLE_CATEGORY,
  helpUrl: "http://fakewebsite.com", // *** [lyn, 11/10/12] Fix this
  init: function() {
    this.setColour(Blockly.VARIABLE_CATEGORY_HUE);
    this.fieldVar_ = new Blockly.FieldLexicalVariable(" ");
    this.fieldVar_.setBlock(this);
    this.appendValueInput('VALUE')
        .appendTitle("set")
        .appendTitle(this.fieldVar_, 'VAR')
        .appendTitle("to");
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setTooltip(Blockly.LANG_VARIABLES_SET_TOOLTIP_1);
    this.errors = [{name:"checkIsInDefinition"},{name:"checkDropDownContainsValidValue",dropDowns:["VAR"]}]
  },
  getVars: function() {
    return [this.getTitleValue('VAR')];
  },
  onchange: Blockly.Language.lexical_variable_get.onchange,
  renameLexicalVar: Blockly.Language.lexical_variable_get.renameLexicalVar
};

Blockly.Language.local_declaration_statement = {
  // Define a procedure with no return value.
  // category: null,  // Procedures are handled specially.
  category: Blockly.MSG_VARIABLE_CATEGORY,  // *** [lyn, 11/07/12] Abstract over this
  helpUrl: "http://fakewebsite.com", // *** [lyn, 11/07/12] Fix this
  init: function() {
    this.setColour(Blockly.VARIABLE_CATEGORY_HUE);
    this.localNames_ = ["name"]; // list of declared local variable names; has one initially
    //this.appendDummyInput('LOCAL_KEYWORD')
        //.appendTitle("local"); // [lyn, 11/05/12] tried to put this on same line with first local name;
                               // Worked fine here, but not in compose function below.

    var declInput = this.appendValueInput('DUMMYDECL');
    declInput.appendTitle("initialize local")
            .appendTitle(new Blockly.FieldTextInput("name"))
            .appendTitle("to")
            .setAlign(Blockly.ALIGN_RIGHT);

    this.appendStatementInput('DUMMYSTACK')
        .appendTitle("in do");

    // Add notch and nub for vertical statment composition
    this.setPreviousStatement(true);
    this.setNextStatement(true);

    // Add mutator for editing local variable names
    this.setMutator(new Blockly.Mutator(['local_mutatorarg']));

    this.setTooltip("Fix this tooltip!"); // *** [lyn, 11/07/12] Fix this
  },
  onchange: Blockly.WarningHandler.checkErrors,
  addDeclarationInputs_: function(names, inits) {
    // Create all inputs (except for "local" keyword) from names list using exps in inits
    // If inits is undefined, treat all initial expressions as undefined.
    for (var i = 0; i < names.length; i++) {
        var declInput = this.appendValueInput('DECL' + i);
        // [lyn, 11/06/12]
        //   This was for case where tried to put "local" keyword on same line with first local name.
        //   But even though alignment set to Blockly.ALIGN_RIGHT, the input was left justified
        //   and covered the plus sign for popping up the mutator. So I put the "local" keyword
        //   on it's own line even though this wastes vertical space. This should be fixed in the future.
        // if (i == 0) {
        //  declInput.appendTitle("local"); // Only put keyword "local" on top line.
        // }
        declInput.appendTitle("initialize local")
            .appendTitle(new Blockly.FieldTextInput(names[i], Blockly.LexicalVariable.renameParam),
                              'VAR' + i)
            .appendTitle("to")
            .setAlign(Blockly.ALIGN_RIGHT);
        if (inits && inits[i]) { // If there is an initializer, connect it
            declInput.connection.connect(inits[i]);
        }
    }
  },
  mutationToDom: function() {
    // *** [lyn, 11/07/2012] Not sure what I'm doing here --- need to understand XML rep better.
    var container = document.createElement('mutation');
    for (var i = 0; i< this.localNames_.length; i++) {
      var parameter = document.createElement('localname');
      parameter.setAttribute('name', this.localNames_[i]);
      container.appendChild(parameter);
    }
    return container;
  },
  domToMutation: function(xmlElement) {
    // *** [lyn, 11/07/2012] Not sure what I'm doing here --- need to understand XML rep better.
    if (Object.keys(xmlElement).length > 0) { // Ensure xml element is nonempty
                                              // Else we'll overwrite initial list with "name" for new block
      this.localNames_ = [];
      for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) {
        if (childNode.nodeName.toLowerCase() == 'localname') {
          this.localNames_.push(childNode.getAttribute('name'));
        }
      }
    }
    // *** [lyn, 11/07/2012] What else needs to be done here?
    // *** Perhaps something like the reconnection in procedure callers?

    this.removeInput('DUMMYDECL');
    this.removeInput('DUMMYSTACK');
    this.addDeclarationInputs_(this.localNames_); // add declarations; inits are undefined
        // Declaration body
    this.appendStatementInput('STACK')
        .appendTitle("in do");
  },
  decompose: function(workspace) {
    // Create "mutator" editor populated with name blocks with local variable names
    var containerBlock = new Blockly.Block(workspace,
                                           'local_mutatorcontainer');
    containerBlock.initSvg();
    containerBlock.setDefBlock(this);
    var connection = containerBlock.getInput('STACK').connection;
    for (var i = 0; i < this.localNames_.length; i++) {
      // alert("decompose local:getting input");
      // var decl = this.getInput('DECL' + i);
      var localName = this.getTitleValue('VAR' + i);
      // alert("field VAR" + i + ":" + JSON.stringify(field));
      // alert("nameInput:" + myStringify(nameInput));
      var nameBlock = new Blockly.Block(workspace, 'local_mutatorarg');
      nameBlock.initSvg();
      nameBlock.setTitleValue(localName, 'NAME');
      // Store the old location.
      nameBlock.oldLocation = i;
      connection.connect(nameBlock.previousConnection);
      connection = nameBlock.nextConnection;
    }
    return containerBlock;
  },
  compose: function(containerBlock) {
    // Modify this local-in-do block according to arrangement of name blocks in mutator editor.

    // Remove all the local declaration inputs ...
    for (var i = 0; i < this.localNames_.length; i++) {
      this.removeInput('DECL' + i);
    }

    // ... and the body
    if (this.getInput('STACK')) this.removeInput('STACK'); // for local variable declaration statement
    else if (this.getInput('RETURN')) this.removeInput('RETURN'); // for local variable declaration expression

    // Now rebuild the block from the mutator.
    this.localNames_ = [];
    var initializers = [];
    var nameBlock = containerBlock.getInputTargetBlock('STACK');
    // First find the new names
    while (nameBlock) {
        var localNameFromEditor = nameBlock.getTitleValue('NAME');
        this.localNames_.push(localNameFromEditor);
        initializers.push(nameBlock.valueConnection_); // pushes undefined if doesn't exist
        nameBlock = nameBlock.nextConnection && nameBlock.nextConnection.targetBlock();
    }

    // Now add in the names inputs into the local var block
    this.addDeclarationInputs_(this.localNames_, initializers);

    // Finally add any body block remembers in the mutator container
    if (containerBlock.isStatement_) {
        // for local variable declaration statement
        var doInput = this.appendStatementInput('STACK') // add slot for body stack
                          .appendTitle("in do");
        if (containerBlock.bodyStatementConnection_) {
            doInput.connection.connect(containerBlock.bodyStatementConnection_);
        }
    } else {
        // for local variable declaration expression
        var returnInput = this.appendValueInput('RETURN')
                              .appendTitle("in return")
                              .setAlign(Blockly.ALIGN_RIGHT);
        if (containerBlock.bodyExpressionConnection_) { // for local variable declaration expression
            returnInput.connection.connect(containerBlock.bodyExpressionConnection_);
        }
    }
  },
  dispose: function() {
    // *** [lyn, 11/07/12] Dunno if anything needs to be done here.
    // Call parent's destructor.
    Blockly.Block.prototype.dispose.apply(this, arguments);
    // [lyn, 11/07/12] In above line, don't know where "arguments" param comes from,
    // but if it's remove, there's no clicking sound upon deleting the block!
  },
  saveConnections: function(containerBlock) {
    // Store body block (in-do statement for local declaration statement,
    //   in-return expression for local declaration expression) with containerBlock
    // containerBlock.isStatement_ remembers whether declaration is a statement or expression.
    if (this.getInput('STACK')) {
      containerBlock.isStatement_ = true;
      containerBlock.bodyStatementConnection_ = this.getInput('STACK').connection.targetConnection;
    }
    else if (this.getInput('RETURN')) {
      containerBlock.isStatement_ = false;
      containerBlock.bodyExpressionConnection_ = this.getInput('RETURN').connection.targetConnection;
    }

    // Store child initializer blocks for local name declarations with name blocks in mutator editor
    var nameBlock = containerBlock.getInputTargetBlock('STACK');
    var i = 0;
    while (nameBlock) {
      var localDecl = this.getInput('DECL' + i);
      nameBlock.valueConnection_ =
        localDecl && localDecl.connection.targetConnection;
      i++;
      nameBlock = nameBlock.nextConnection &&
      nameBlock.nextConnection.targetBlock();
    }
  },
  getVars: function() {
    // New on [11/18/12]
    var varList = [];
    var i = 0;
    var currentVar = this.getTitleValue('VAR' + i);
    while (currentVar) {
        varList.push(currentVar);
        i++;
        currentVar = this.getTitleValue('VAR' + i);
    }
    return varList;
  },
  blocksInScope: function () {
    var doBody = this.getInputTargetBlock('STACK'); // *** [lyn, 11/24/12] This will go away with DO-AND-RETURN block
    var doBodyList = (doBody && [doBody]) || []; // List of non-null doBody or empty list for null doBody
    return doBodyList; // List of non-null body elements.
  },
  declaredNames: function () {
    var varNames = [];
    for(var i=0;this.getTitleValue('VAR' + i);i++){
      varNames.push(this.getTitleValue('VAR' + i));
    }
    return varNames;
  },
  renameVar: function(oldName, newName) {
    // *** [lyn, 11/07/12] Still need to handle renaming of local variable names
        /*
    var change = false;
    for (var x = 0; x < this.arguments_.length; x++) {
      if (Blockly.Names.equals(oldName, this.arguments_[x])) {
        this.arguments_[x] = newName;
        change = true;
      }
    }
    if (change) {
      this.updateParams_();
      // Update the mutator's variables if the mutator is open.
      if (this.mutator.isVisible_()) {
        var blocks = this.mutator.workspace_.getAllBlocks();
        for (var x = 0, block; block = blocks[x]; x++) {
          if (block.type == 'local_mutatorarg' &&
              Blockly.Names.equals(oldName, block.getTitleValue('NAME'))) {
            block.setTitleValue(newName, 'NAME');
          }
        }
      }
    }
        */
    }
};

Blockly.Language.local_declaration_expression = {
  // Define a procedure with a return value.
  category: Blockly.MSG_VARIABLE_CATEGORY,  // *** [lyn, 11/07/12] Abstract over this
  helpUrl: "http://fakewebsite.com", // *** [lyn, 11/07/12] Fix this
  init: function() {
    this.setColour(Blockly.VARIABLE_CATEGORY_HUE);
    this.localNames_ = ["name"]; // list of declared local variable names; has one initially
    //this.appendDummyInput('LOCAL_KEYWORD')
        //.appendTitle("local"); // [lyn, 11/05/12] See notes on this above in local_declaration_statement

    var declInput = this.appendValueInput('DUMMYDECL');
    declInput.appendTitle("initialize local")
            .appendTitle(new Blockly.FieldTextInput("name"))
            .appendTitle("to")
            .setAlign(Blockly.ALIGN_RIGHT);

	this.appendValueInput('DUMMYRETURN')
        .setAlign(Blockly.ALIGN_RIGHT)
        .appendTitle("in return");

    // Create plug for expression output
    this.setOutput(true, null);

    // Add mutator for editing local variable names
    this.setMutator(new Blockly.Mutator(['local_mutatorarg']));

    this.setTooltip("Fix this tooltip!"); // *** [lyn, 11/07/12] Fix this
  },
  onchange: Blockly.WarningHandler.checkErrors,
  addDeclarationInputs_: Blockly.Language.local_declaration_statement.addDeclarationInputs_,
  mutationToDom: Blockly.Language.local_declaration_statement.mutationToDom,
  domToMutation: function(xmlElement) {
    // *** [lyn, 11/07/2012] Not sure what I'm doing here --- need to understand XML rep better.
    if (Object.keys(xmlElement).length > 0) { // Ensure xml element is nonempty
                                              // Else we'll overwrite initial list with "name" for new block
      this.localNames_ = [];
      for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) {
        if (childNode.nodeName.toLowerCase() == 'localname') {
          this.localNames_.push(childNode.getAttribute('name'));
        }
      }
    }
    this.removeInput('DUMMYDECL');
    this.removeInput('DUMMYRETURN');
    // *** [lyn, 11/07/2012] What else needs to be done here?
    // *** Perhaps something like the reconnection in procedure callers?
    this.addDeclarationInputs_(this.localNames_); // add declarations; inits are undefined

    // Declaration body = return value of expression
    this.appendValueInput('RETURN')
        .setAlign(Blockly.ALIGN_RIGHT)
        .appendTitle("in return");
  },
  blocksInScope: function () {
    var doBody = this.getInputTargetBlock('RETURN'); // *** [lyn, 11/24/12] This will go away with DO-AND-RETURN block
    var doBodyList = (doBody && [doBody]) || []; // List of non-null doBody or empty list for null doBody
    return doBodyList; // List of non-null body elements.
  },
  decompose: Blockly.Language.local_declaration_statement.decompose,
  compose: Blockly.Language.local_declaration_statement.compose,
  dispose: Blockly.Language.local_declaration_statement.dispose,
  saveConnections: Blockly.Language.local_declaration_statement.saveConnections,
  declaredNames: Blockly.Language.local_declaration_statement.declaredNames,
  renameVar: Blockly.Language.local_declaration_statement.renameVar
};

Blockly.Language.local_mutatorcontainer = {
  // Local variable container (for mutator dialog).
  init: function() {
    this.setColour(Blockly.VARIABLE_CATEGORY_HUE);
    this.appendDummyInput()
        .appendTitle("local names");
    this.appendStatementInput('STACK');
    this.setTooltip('');
    this.contextMenu = false;
  },
  // [lyn. 11/24/12] Set procBlock associated with this container.
  setDefBlock: function (defBlock) {
    this.defBlock_ = defBlock;
  },
  // [lyn. 11/24/12] Set procBlock associated with this container.
  // Invariant: should not be null, since only created as mutator for a particular proc block.
  getDefBlock: function () {
    return this.defBlock_;
  },
  // [lyn. 11/24/12] Return list of param names in this container
  // Invariant: there should be no duplicates!
  declaredNames: function () {
    var paramNames = [];
    var paramBlock = this.getInputTargetBlock('STACK');
    while (paramBlock) {
      paramNames.push(paramBlock.getTitleValue('NAME'));
      paramBlock = paramBlock.nextConnection &&
                   paramBlock.nextConnection.targetBlock();
    }
    return paramNames;
  }
};

Blockly.Language.local_mutatorarg = {
  // Procedure argument (for mutator dialog).
  init: function() {
    this.setColour(Blockly.VARIABLE_CATEGORY_HUE);
    this.appendDummyInput()
        .appendTitle("name")
        .appendTitle(new Blockly.FieldTextInput('x', Blockly.LexicalVariable.renameParam), 'NAME');
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setTooltip('');
    this.contextMenu = false;
  },
  getContainerBlock: function () {
    var parent = this.getParent();
    while (parent && ! (parent.type === "local_mutatorcontainer")) {
      parent = parent.getParent();
    }
    // [lyn, 11/24/12] Cache most recent container block so can reference it upon removal from mutator arg stack
    this.cachedContainerBlock_ = (parent && (parent.type === "local_mutatorcontainer") && parent) || null;
    return this.cachedContainerBlock_;
  },
  getDefBlock: function () {
    var container = this.getContainerBlock();
    return (container && container.getDefBlock()) || null;
  },
  blocksInScope: function () {
    var defBlock = this.getDefBlock();
    return (defBlock && defBlock.blocksInScope()) || [];
  },
  declaredNames: function () {
    var container = this.getContainerBlock();
    return (container && container.declaredNames()) || [];
  },

  // [lyn, 11/24/12] Check for situation in which mutator arg has been removed from stack,
  onchange: function() {
    var paramName = this.getTitleValue('NAME');
    if (paramName) { // paramName is null when delete from stack
      // console.log("Mutatorarg onchange: " + paramName);
      var cachedContainer = this.cachedContainerBlock_;
      var container = this.getContainerBlock(); // Order is important; this must come after cachedContainer
                                                // since it sets cachedContainerBlock_
      // console.log("Mutatorarg onchange: " + paramName
      //            + "; cachedContainer = " + JSON.stringify((cachedContainer && cachedContainer.type) || null)
      //            + "; container = " + JSON.stringify((container && container.type) || null));
      if ((! cachedContainer) && container) {
        // Event: added mutator arg to container stack
        // console.log("Mutatorarg onchange ADDED: " + paramName);
        var declaredNames = this.declaredNames();
        var firstIndex = declaredNames.indexOf(paramName);
        if (firstIndex != -1) {
          // Assertion: we should get here, since paramName should be among names
          var secondIndex = declaredNames.indexOf(paramName, firstIndex+1);
          if (secondIndex != -1) {
            // If we get here, there is a duplicate on insertion that must be resolved
            var newName = Blockly.FieldLexicalVariable.nameNotIn(paramName,declaredNames);
            this.setTitleValue(newName, 'NAME');
          }
        }
      }
    }
  }
};

redpajama_set_name: RedPajamaGithub


text:
cask 'adguard' do
  version '1.5.8'
  sha256 '0a15a2c1dc46ebeb78b8909d1d3af90b4f60e728bb2ead2b8638181f86325d55'

  url "https://static.adguard.com/mac/Adguard-#{version}.release.dmg"
  appcast 'https://static.adguard.com/mac/adguard-release-appcast.xml',
          checkpoint: 'fb3b65fe55fe28d940321273626b9f136a9e8236e1c97920919f4bc75ea91651'
  name 'Adguard for Mac'
  homepage 'https://adguard.com/'

  app 'Adguard.app'

  zap trash: [
               '/Library/Application Support/com.adguard.Adguard',
               '~/Library/Application Support/Adguard',
               '~/Library/Application Support/com.adguard.Adguard',
               '~/Library/Caches/com.adguard.Adguard',
               '~/Library/Cookies/com.adguard.Adguard.binarycookies',
               '~/Library/Logs/Adguard',
               '~/Library/Preferences/com.adguard.Adguard.plist',
             ]
end


text:
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wrmsr.wava.java.lang;

import com.google.common.base.MoreObjects;

import javax.annotation.concurrent.Immutable;

import java.util.Objects;

@Immutable
public final class JArg
{
    private final JTypeSpecifier type;
    private final JName name;

    public JArg(JTypeSpecifier type, JName name)
    {
        this.type = type;
        this.name = name;
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        JArg arg = (JArg) o;
        return Objects.equals(type, arg.type) &&
                Objects.equals(name, arg.name);
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(type, name);
    }

    @Override
    public String toString()
    {
        return MoreObjects.toStringHelper(this)
                .add("type", type)
                .add("name", name)
                .toString();
    }

    public JTypeSpecifier getType()
    {
        return type;
    }

    public JName getName()
    {
        return name;
    }
}


text:
/**
 * @overview
 * This file contains the contact picker classes.
 *
 */

/**
 * Creates a dialog that lets the user select addresses from a contact list.
 * @constructor
 * @class
 * This class creates and manages a dialog that lets the user select addresses
 * from a contact list. Two lists are maintained, one with contacts to select
 * from, and one that contains the selected addresses. Between them are buttons
 * to shuffle addresses back and forth between the two lists.
 *
 * @author Conrad Damon
 *
 * @param {Array}	buttonInfo		the transfer button IDs and labels
 *
 * @extends		DwtDialog
 */
ZmContactPicker = function(buttonInfo) {

	DwtDialog.call(this, {parent:appCtxt.getShell(), title:ZmMsg.selectAddresses, id: "ZmContactPicker"});

	this._buttonInfo = buttonInfo;
	this._initialized = false;
	this._emailListOffset = 0; //client side paginating over email list. Offset of current page of email addresses. Quite different than _lastServerOffset if contacts have 0 or more than 1 email addresses.
	this._serverContactOffset = 0; //server side paginating over contact list. Offset of last contact block we got from the server (each contact could have 0, 1, or more emails so we have to keep track of this separate from the view offset.
	this._ascending = true; //asending or descending search. Keep it stored for pagination to do the right sort.
	this._defaultQuery = ".";
	this._emailList = new AjxVector();
	this._detailedSearch = appCtxt.get(ZmSetting.DETAILED_CONTACT_SEARCH_ENABLED);
	this._searchCleared = {};
	this._ignoreSetDragBoundries = true;

	this._searchErrorCallback = new AjxCallback(this, this._handleErrorSearch);
};

ZmContactPicker.prototype = new DwtDialog;
ZmContactPicker.prototype.constructor = ZmContactPicker;

// Consts

ZmContactPicker.CHOOSER_HEIGHT = 300;

ZmContactPicker.SEARCH_BASIC = "search";
ZmContactPicker.SEARCH_NAME = "name";
ZmContactPicker.SEARCH_EMAIL = "email";
ZmContactPicker.SEARCH_DEPT = "dept";
ZmContactPicker.SEARCH_PHONETIC = "phonetic";

ZmContactPicker.HINT = {};
ZmContactPicker.HINT[ZmContactPicker.SEARCH_BASIC] = ZmMsg.contactPickerHint;
ZmContactPicker.HINT[ZmContactPicker.SEARCH_NAME] = ZmMsg.contactPickerHint;
ZmContactPicker.HINT[ZmContactPicker.SEARCH_EMAIL] = ZmMsg.contactPickerEmailHint;
ZmContactPicker.HINT[ZmContactPicker.SEARCH_DEPT] = ZmMsg.contactPickerDepartmentHint;
ZmContactPicker.HINT[ZmContactPicker.SEARCH_PHONETIC] = ZmMsg.contactPickerPhoneticHint;

ZmContactPicker.SHOW_ON_GAL = [ZmContactPicker.SEARCH_BASIC, ZmContactPicker.SEARCH_NAME, ZmContactPicker.SEARCH_EMAIL, ZmContactPicker.SEARCH_DEPT];
ZmContactPicker.SHOW_ON_NONGAL = [ZmContactPicker.SEARCH_BASIC, ZmContactPicker.SEARCH_NAME, ZmContactPicker.SEARCH_PHONETIC, ZmContactPicker.SEARCH_EMAIL];

// Public methods

/**
 * Returns a string representation of the object.
 *
 * @return		{String}		a string representation of the object
 */
ZmContactPicker.prototype.toString =
function() {
	return "ZmContactPicker";
};

/**
* Displays the contact picker dialog. The source list is populated with
* contacts, and the target list is populated with any addresses that are
* passed in. The address button that was used to popup the dialog is set
* as the active button.
*
* @param {String}	buttonId	the button ID of the button that called us
* @param {Hash}	addrs		a hash of 3 vectors (one for each type of address)
* @param {String}	str		initial search string
*/
ZmContactPicker.prototype.popup =
function(buttonId, addrs, str, account) {

	if (!this._initialized) {
		this._initialize(account);
		this._initialized = true;
	}
	else if (appCtxt.multiAccounts && this._account != account) {
		this._account = account;
		this._resetSelectDiv();
	}
	this._emailListOffset = 0;

	var searchFor = this._searchInSelect ? this._searchInSelect.getValue() : ZmContactsApp.SEARCHFOR_CONTACTS;

	// reset column sorting preference
	this._chooser.sourceListView.setSortByAsc(ZmItem.F_NAME, true);

	// reset button states
	this._chooser.reset();
	if (buttonId) {
		this._chooser._setActiveButton(buttonId);
	}

	// populate target list if addrs were passed in
	if (addrs) {
		for (var id in addrs) {
			this._chooser.addItems(addrs[id], DwtChooserListView.TARGET, true, id);
		}
	}

	for (var fieldId in this._searchField) {
		var field = this._searchField[fieldId];
		field.disabled = false;
		if (str) {
			field.className = "";
			field.value = AjxUtil.isObject(str) ? (str[fieldId] || "") : str;
			this._searchCleared[fieldId] = true;
		} else {
			field.className = "searchFieldHint";
			field.value = ZmContactPicker.HINT[fieldId];
			this._searchCleared[fieldId] = false;
		}
	}
	var focusField = this._searchField[ZmContactPicker.SEARCH_BASIC] || this._searchField[ZmContactPicker.SEARCH_NAME];
	focusField.focus();

	// reset paging buttons
	this._prevButton.setEnabled(false);
	this._nextButton.setEnabled(false);

	this.search(null, true, true);

	DwtDialog.prototype.popup.call(this);
    if ((this.getLocation().x < 0 ||  this.getLocation().y < 0) ){
                // parent window size is smaller than Dialog size
                this.setLocation(0,30);
                var size = Dwt.getWindowSize();
                var currentSize = this.getSize();
                var dragElement = document.getElementById(this._dragHandleId);
                DwtDraggable.setDragBoundaries(dragElement, 100 - currentSize.x, size.x - 100, 0, size.y - 100);
    }
};

ZmContactPicker.prototype._resetResults =
function() {
	this._emailList.removeAll();
	this._serverContactOffset = 0;
	this._emailListOffset = 0;
};

/**
 * Closes the dialog.
 *
 */
ZmContactPicker.prototype.popdown =
function() {
	// disable search field (hack to fix bleeding cursor)

	for (var fieldId in this._searchField) {
		this._searchField[fieldId].disabled = true;
	}

	this._contactSource = null;
	this._resetResults();

	DwtDialog.prototype.popdown.call(this);
};

/**
 * Performs a search.
 *
 * @private
 */
ZmContactPicker.prototype.search =
function(colItem, ascending, firstTime, lastId, lastSortVal, offset) {
	if (offset == undefined) {
		//this could be a call from DwtChooserListView.prototype._sortColumn, which means we have to reset the result and both server and client pagination.
		//In any case the results should be reset or are already reset so doesn't hurt to reset.
		this._resetResults();
	}

	if (ascending === null || ascending === undefined) {
		ascending = this._ascending;
	}
	else {
		this._ascending = ascending;
	}

	var query;
	var queryHint = [];
	var conds = [];
	if (this._detailedSearch) {
		var nameQuery = this.getSearchFieldValue(ZmContactPicker.SEARCH_NAME);
		var emailQuery = this.getSearchFieldValue(ZmContactPicker.SEARCH_EMAIL);
		var deptQuery = this.getSearchFieldValue(ZmContactPicker.SEARCH_DEPT);
		var phoneticQuery = this.getSearchFieldValue(ZmContactPicker.SEARCH_PHONETIC);
		var isGal = this._searchInSelect && (this._searchInSelect.getValue() == ZmContactsApp.SEARCHFOR_GAL);
		query = nameQuery || "";
		if (emailQuery) {
			if (isGal) {
				conds.push([{attr:ZmContact.F_email, op:"has", value: emailQuery},
				{attr:ZmContact.F_email2, op:"has", value: emailQuery},
				{attr:ZmContact.F_email3, op:"has", value: emailQuery},
				{attr:ZmContact.F_email4, op:"has", value: emailQuery},
				{attr:ZmContact.F_email5, op:"has", value: emailQuery},
				{attr:ZmContact.F_email6, op:"has", value: emailQuery},
				{attr:ZmContact.F_email7, op:"has", value: emailQuery},
				{attr:ZmContact.F_email8, op:"has", value: emailQuery},
				{attr:ZmContact.F_email9, op:"has", value: emailQuery},
				{attr:ZmContact.F_email10, op:"has", value: emailQuery},
				{attr:ZmContact.F_email11, op:"has", value: emailQuery},
				{attr:ZmContact.F_email12, op:"has", value: emailQuery},
				{attr:ZmContact.F_email13, op:"has", value: emailQuery},
				{attr:ZmContact.F_email14, op:"has", value: emailQuery},
				{attr:ZmContact.F_email15, op:"has", value: emailQuery},
				{attr:ZmContact.F_email16, op:"has", value: emailQuery}
				]);
			} else {
				queryHint.push("to:"+emailQuery+"*");
			}
		}
		if (deptQuery && isGal) {
			conds.push({attr:ZmContact.F_department, op:"has", value: deptQuery});
		}
		if (phoneticQuery && !isGal) {
			var condArr = [];
			var phoneticQueryPieces = phoneticQuery.split(/\s+/);
			for (var i=0; i<phoneticQueryPieces.length; i++) {
				condArr.push("#"+ZmContact.F_phoneticFirstName + ":" + phoneticQueryPieces[i]);
				condArr.push("#"+ZmContact.F_phoneticLastName + ":" + phoneticQueryPieces[i]);
			}
			queryHint.push(condArr.join(" || "));
		}
	} else {
		query = this.getSearchFieldValue(ZmContactPicker.SEARCH_BASIC);
	}

	if (this._searchInSelect) {
		var searchFor = this._searchInSelect.getValue();
		this._contactSource = (searchFor == ZmContactsApp.SEARCHFOR_CONTACTS || searchFor == ZmContactsApp.SEARCHFOR_PAS)
			? ZmItem.CONTACT
			: ZmId.SEARCH_GAL;

		if (searchFor == ZmContactsApp.SEARCHFOR_PAS) {
			queryHint.push(ZmSearchController.generateQueryForShares([ZmId.ITEM_CONTACT]) || "is:local");
		} else if (searchFor == ZmContactsApp.SEARCHFOR_CONTACTS) {
			queryHint.push("is:local");
		} else if (searchFor == ZmContactsApp.SEARCHFOR_GAL) {
            ascending = true;
        }
	} else {
		this._contactSource = appCtxt.get(ZmSetting.CONTACTS_ENABLED, null, this._account)
			? ZmItem.CONTACT
			: ZmId.SEARCH_GAL;

		if (this._contactSource == ZmItem.CONTACT) {
			queryHint.push("is:local");
		}
	}

    if (!query.length && this._contactSource == ZmId.SEARCH_GAL) {
		query = this._defaultQuery;
	}

    if (this._contactSource == ZmItem.CONTACT && query != "") {
        query = query.replace(/\"/g, '\\"');
        query = "\"" + query + "\"";
    }

	if (this._searchIcon) { //does not exist in ZmGroupView case
		this._searchIcon.className = "DwtWait16Icon";
	}

	// XXX: line below doesn't have intended effect (turn off column sorting for GAL search)
	if (this._chooser) { //_chooser not defined in ZmGroupView but we also do not support sorting there anyway
		this._chooser.sourceListView.sortingEnabled = (this._contactSource == ZmItem.CONTACT);
	}

	var params = {
		obj:			this,
		ascending:		ascending,
		query:			query,
		queryHint:		queryHint.join(" "),
		conds:			conds,
		offset:			offset || 0,
		lastId:			lastId,
		lastSortVal:	lastSortVal,
		respCallback:	(new AjxCallback(this, this._handleResponseSearch, [firstTime])),
		errorCallback:	this._searchErrorCallback,
		accountName:	(this._account && this._account.name),
		expandDL:		true
	};
	ZmContactsHelper.search(params);
};

/**
 * @private
 */
ZmContactPicker.prototype._contentHtml =
function(account) {
	var showSelect;
	if (appCtxt.multiAccounts) {
		var list = appCtxt.accountList.visibleAccounts;
		for (var i = 0; i < list.length; i++) {
			var account = list[i];
			if (appCtxt.get(ZmSetting.CONTACTS_ENABLED, null, account) &&
				(appCtxt.get(ZmSetting.GAL_ENABLED, null, account) ||
				 appCtxt.get(ZmSetting.SHARING_ENABLED, null, account)))
			{
				showSelect = true;
				break;
			}
		}
	} else {
		showSelect = (appCtxt.get(ZmSetting.CONTACTS_ENABLED) &&
					  (appCtxt.get(ZmSetting.GAL_ENABLED) ||
					   appCtxt.get(ZmSetting.SHARING_ENABLED)));
	}

	var subs = {
		id: this._htmlElId,
		showSelect: showSelect,
		detailed: this._detailedSearch
	};

	return (AjxTemplate.expand("abook.Contacts#ZmContactPicker", subs));
};

/**
 * @private
 */
ZmContactPicker.prototype._resetSelectDiv =
function() {
    this._searchInSelect.clearOptions();

    if (appCtxt.multiAccounts) {
        var accts = appCtxt.accountList.visibleAccounts;
        var org = ZmOrganizer.ITEM_ORGANIZER;
        org = ZmOrganizer.ITEM_ORGANIZER[ZmItem.CONTACT];

        for (var i = 0; i < accts.length; i++) {
            this._searchInSelect.addOption(accts[i].displayName, false, accts[i].id);
            var folderTree = appCtxt.getFolderTree(accts[i]);
            var data = [];
            data = data.concat(folderTree.getByType(org));
            for (var j = 0; j < data.length; j++) {
                var addrsbk = data[j];
                if(addrsbk.noSuchFolder) { continue; }
                this._searchInSelect.addOption(addrsbk.getName(), false, addrsbk.id, "ImgContact");
            }
            if(accts[i].isZimbraAccount && !accts[i].isMain) {
                if (appCtxt.get(ZmSetting.CONTACTS_ENABLED, null, this._account)) {
                    if (appCtxt.get(ZmSetting.SHARING_ENABLED, null, this._account))
                        this._searchInSelect.addOption(ZmMsg.searchPersonalSharedContacts, false, ZmContactsApp.SEARCHFOR_PAS, "ImgContact");
                }

                if (appCtxt.get(ZmSetting.GAL_ENABLED, null, this._account)) {
                    this._searchInSelect.addOption(ZmMsg.GAL, true, ZmContactsApp.SEARCHFOR_GAL, "ImgContact");
                }

                if (!appCtxt.get(ZmSetting.INITIALLY_SEARCH_GAL, null, this._account) ||
                        !appCtxt.get(ZmSetting.GAL_ENABLED, null, this._account))
                {
                    this._searchInSelect.setSelectedValue(ZmContactsApp.SEARCHFOR_CONTACTS);
                }
            }
        }

        for (var k = 0; k < accts.length; k++) {
            this._searchInSelect.enableOption(accts[k].id, false);
        }
    } else {

        if (appCtxt.get(ZmSetting.CONTACTS_ENABLED, null, this._account)) {
            this._searchInSelect.addOption(ZmMsg.contacts, false, ZmContactsApp.SEARCHFOR_CONTACTS);

            if (appCtxt.get(ZmSetting.SHARING_ENABLED, null, this._account))
                this._searchInSelect.addOption(ZmMsg.searchPersonalSharedContacts, false, ZmContactsApp.SEARCHFOR_PAS);
        }

        if (appCtxt.get(ZmSetting.GAL_ENABLED, null, this._account)) {
            this._searchInSelect.addOption(ZmMsg.GAL, true, ZmContactsApp.SEARCHFOR_GAL);
        }

        if (!appCtxt.get(ZmSetting.INITIALLY_SEARCH_GAL, null, this._account) ||
                !appCtxt.get(ZmSetting.GAL_ENABLED, null, this._account))
        {
            this._searchInSelect.setSelectedValue(ZmContactsApp.SEARCHFOR_CONTACTS);
        }

    }
};

ZmContactPicker.prototype.clearSearch =
function(el) {
	if (el) {
		for (var fieldId in this._searchField) {
			if (el == this._searchField[fieldId]) {
				if (!this._searchCleared[fieldId]) {
					el.className = el.value = "";
					this._searchCleared[fieldId] = true;
				}
				break;
			}
		}
	}
};

ZmContactPicker.prototype.getSearchFieldValue =
function(fieldId) {
	if (!fieldId && !this._detailedSearch) {
		fieldId = ZmContactPicker.SEARCH_BASIC;
	}
	var field = this._searchField[fieldId];
	return (this._searchCleared[fieldId] && field) ? AjxStringUtil.trim(field.value) : "";
};

/**
 * called only when ZmContactPicker is first created. Sets up initial layout.
 *
 * @private
 */
ZmContactPicker.prototype._initialize =
function(account) {

	// create static content and append to dialog parent
	this.setContent(this._contentHtml(account));

	this._searchIcon = document.getElementById(this._htmlElId + "_searchIcon");

	// add search button
	this._searchButton = new DwtButton({parent:this, parentElement:(this._htmlElId+"_searchButton")});
	this._searchButton.setText(ZmMsg.search);
	this._searchButton.addSelectionListener(new AjxListener(this, this._searchButtonListener));

	// add select menu
	var selectCellId = this._htmlElId + "_listSelect";
	var selectCell = document.getElementById(selectCellId);
	if (selectCell) {
		this._searchInSelect = new DwtSelect({parent:this, parentElement:selectCellId, id: Dwt.getNextId("ZmContactPickerSelect_")});
		this._resetSelectDiv();
		this._searchInSelect.addChangeListener(new AjxListener(this, this._searchTypeListener));
	} else {
		this.setSize("600");
	}

	// add chooser
	this._chooser = new ZmContactChooser({parent:this, buttonInfo:this._buttonInfo});
	this._chooser.reparentHtmlElement(this._htmlElId + "_chooser");
	this._chooser.resize(this.getSize().x-25, ZmContactPicker.CHOOSER_HEIGHT);

	// add paging buttons
	var pageListener = new AjxListener(this, this._pageListener);
	this._prevButton = new DwtButton({parent:this, parentElement:(this._htmlElId+"_pageLeft")});
	this._prevButton.setText(ZmMsg.previous);
	this._prevButton.setImage("LeftArrow");
	this._prevButton.addSelectionListener(pageListener);

	this._nextButton = new DwtButton({parent:this, style:DwtLabel.IMAGE_RIGHT, parentElement:(this._htmlElId+"_pageRight")});
	this._nextButton.setText(ZmMsg.next);
	this._nextButton.setImage("RightArrow");
	this._nextButton.addSelectionListener(pageListener);

	var pageContainer = document.getElementById(this._htmlElId + "_paging");
	if (pageContainer) {
		Dwt.setSize(pageContainer, this._chooser.sourceListView.getSize().x);
	}

	// init listeners
	this.setButtonListener(DwtDialog.OK_BUTTON, new AjxListener(this, this._okButtonListener));
	this.setButtonListener(DwtDialog.CANCEL_BUTTON, new AjxListener(this, this._cancelButtonListener));

	var fieldMap = {};
	var rowMap = {};
	this.mapFields(fieldMap, rowMap);

	this._searchField = {};
	for (var fieldId in fieldMap) {
		var field = Dwt.byId(fieldMap[fieldId]);
		if (field) {
			this._searchField[fieldId] = field;
			Dwt.setHandler(field, DwtEvent.ONKEYUP, ZmContactPicker._keyPressHdlr);
			Dwt.setHandler(field, DwtEvent.ONCLICK, ZmContactPicker._onclickHdlr);
		}
	}

	this._searchRow = {};
	for (var rowId in rowMap) {
		row = Dwt.byId(rowMap[rowId]);
		if (row) {
			this._searchRow[rowId] = row;
		}
	}
	this._updateSearchRows(this._searchInSelect && this._searchInSelect.getValue() || ZmContactsApp.SEARCHFOR_CONTACTS);
	this._keyPressCallback = new AjxCallback(this, this._searchButtonListener);
};

ZmContactPicker.prototype.mapFields =
function(fieldMap, rowMap) {
	if (this._detailedSearch) {
		fieldMap[ZmContactPicker.SEARCH_NAME] = this._htmlElId + "_searchNameField";
		fieldMap[ZmContactPicker.SEARCH_EMAIL] = this._htmlElId + "_searchEmailField";
		fieldMap[ZmContactPicker.SEARCH_DEPT] = this._htmlElId + "_searchDepartmentField";
		fieldMap[ZmContactPicker.SEARCH_PHONETIC] = this._htmlElId + "_searchPhoneticField";
		rowMap[ZmContactPicker.SEARCH_NAME] = this._htmlElId + "_searchNameRow";
		rowMap[ZmContactPicker.SEARCH_PHONETIC] = this._htmlElId + "_searchPhoneticRow";
		rowMap[ZmContactPicker.SEARCH_EMAIL] = this._htmlElId + "_searchEmailRow";
		rowMap[ZmContactPicker.SEARCH_DEPT] = this._htmlElId + "_searchDepartmentRow";
	}
	else {
		fieldMap[ZmContactPicker.SEARCH_BASIC] = this._htmlElId + "_searchField";
		rowMap[ZmContactPicker.SEARCH_BASIC] = this._htmlElId + "_searchRow";
	}
};

// Listeners

/**
 * @private
 */
ZmContactPicker.prototype._searchButtonListener =
function(ev) {
	this._resetResults();
	this.search();
};

/**
 * @private
 */
ZmContactPicker.prototype._handleResponseSearch =
function(firstTime, result) {
	var resp = result.getResponse();
	var serverHasMore = resp.getAttribute("more");
	var serverPaginationSupported = resp.getAttribute("paginationSupported") !== false; //if it's not specified (such as the case of SearchResponse, i.e. not Gal) it IS supported.
	this._serverHasMoreAndPaginationSupported = serverHasMore && serverPaginationSupported;
	var offset = resp.getAttribute("offset");
	this._serverContactOffset = offset || 0;
	var info = resp.getAttribute("info");
	var expanded = info && info[0].wildcard[0].expanded == "0";

	//the check for firstTime is so when the picker is popped up we probably don't want to overwhelm them with a warning message. So only show it if the user plays with the picker, using the drop-down or the search box.
	if (!firstTime && !serverPaginationSupported && (serverHasMore || expanded)) { //no idea what the expanded case is
		var d = appCtxt.getMsgDialog();
		d.setMessage(ZmMsg.errorSearchNotExpanded);
		d.popup();
		if (expanded) { return; }
	}

	// this method will expand the list depending on the number of email
	// addresses per contact.
	var emailArray = ZmContactsHelper._processSearchResponse(resp, this._includeContactsWithNoEmail); //this._includeContactsWithNoEmail - true in the ZmGroupView case
	var emailList = AjxVector.fromArray(emailArray);

	if (serverPaginationSupported) {
		this._emailList.addList(emailArray); //this internally calls concat. we do not need "merge" here because we use the _serverContactOffset as a marker of where to search next, never searching a block we already did.
	}
	else {
		this._emailList = emailList;
	}

	this._showResults();

};

ZmContactPicker.prototype._showResults =
function() {

	var list = this.getSubList();

	// special case 1 - search forward another server block, to fill up a page. Could search several times.
	if (list.size() < ZmContactsApp.SEARCHFOR_MAX && this._serverHasMoreAndPaginationSupported) {
		this.search(null, null, null, null, null, this._serverContactOffset + ZmContactsApp.SEARCHFOR_MAX); //search another page
		return;
	}

	if (this._searchIcon) { //does not exist in ZmGroupView case
		this._searchIcon.className = "ImgSearch";
	}
	this._searchButton.setEnabled(true);

	// special case 2 - no results, and no more to search (that was covered in special case 1) - so display the "no results" text.
	if (list.size() == 0 && this._emailListOffset == 0) {
		this._setResultsInView(list); //empty the list
		this._nextButton.setEnabled(false);
		this._prevButton.setEnabled(false);
		this._setNoResultsHtml();
		return;
	}

	// special case 3 - If the AB ends with a long list of contacts w/o addresses,
	// we may get an empty list.  If that's the case, roll back the offset
	// not 100% sure this case could still happen after all my changes but it was there in the code, so I keep it just in case.
	if (list.size() == 0) {
		this._emailListOffset -= ZmContactsApp.SEARCHFOR_MAX;
		this._emailListOffset  = Math.max(0, this._emailListOffset);
	}

	var more = this._serverHasMoreAndPaginationSupported  //we can get more from the server
				|| (this._emailListOffset + ZmContactsApp.SEARCHFOR_MAX) < this._emailList.size(); //or we have more on the client we didn't yet show
	this._prevButton.setEnabled(this._emailListOffset > 0);
	this._nextButton.setEnabled(more);

	this._resetSearchColHeaders(); // bug #2269 - enable/disable sort column per type of search
	this._setResultsInView(list);

};

/**
 * extracted this so it can be used in ZmGroupView where this is different.
 * @param list
 */
ZmContactPicker.prototype._setResultsInView =
function(list) {
	this._chooser.setItems(list);
};

/**
 * extracted this so it can be used in ZmGroupView where this is different.
 * @param list
 */
ZmContactPicker.prototype._setNoResultsHtml =
function(list) {
	this._chooser.sourceListView._setNoResultsHtml();
};

ZmContactPicker.prototype._updateSearchRows =
function(searchFor) {
	var fieldIds = (searchFor == ZmContactsApp.SEARCHFOR_GAL) ? ZmContactPicker.SHOW_ON_GAL : ZmContactPicker.SHOW_ON_NONGAL;
	for (var fieldId in this._searchRow) {
		Dwt.setVisible(this._searchRow[fieldId], AjxUtil.indexOf(fieldIds, fieldId)!=-1);
	}
	for (var fieldId in this._searchField) {
		var field = this._searchField[fieldId];
		if (this._tabGroup.contains(field))
			this._tabGroup.removeMember(field);
	}
	for (var i=0; i<fieldIds.length; i++) {
		this._tabGroup.addMember(this._searchField[fieldIds[i]]);
	}
};

/**
 * @private
 */
ZmContactPicker.prototype._handleErrorSearch =
function() {
	this._searchButton.setEnabled(true);
	return false;
};

/**
 * @private
 */
ZmContactPicker.prototype._pageListener =
function(ev) {
	if (ev.item == this._prevButton) {
		this._emailListOffset -= ZmContactsApp.SEARCHFOR_MAX;
		this._emailListOffset  = Math.max(0, this._emailListOffset);
	}
	else {
		this._emailListOffset += ZmContactsApp.SEARCHFOR_MAX;
	}
	this._showResults();
};

/**
 * Gets a sub-list of contacts.
 *
 * @return	{AjxVector}		a vector of {ZmContact} objects
 */
ZmContactPicker.prototype.getSubList =
function() {
	var size = this._emailList.size();

	var end = this._emailListOffset + ZmContactsApp.SEARCHFOR_MAX;

	if (end > size) {
		end = size;
	}

	var a = (this._emailListOffset < end) ? this._emailList.getArray().slice(this._emailListOffset, end) : [];
	return AjxVector.fromArray(a);
};

/**
 * @private
 */
ZmContactPicker.prototype._searchTypeListener =
function(ev) {
	var oldValue = ev._args.oldValue;
	var newValue = ev._args.newValue;

	if (oldValue != newValue) {
		this._updateSearchRows(newValue);
		this._searchButtonListener();
	}
};

/**
 * @private
 */
ZmContactPicker.prototype._resetSearchColHeaders =
function() {
	var slv = this._chooser.sourceListView;
	slv.headerColCreated = false;
	var isGal = this._searchInSelect && (this._searchInSelect.getValue() == ZmContactsApp.SEARCHFOR_GAL);

	// find the participant column
	var part = 0;
	for (var i = 0; i < slv._headerList.length; i++) {
		var field = slv._headerList[i]._field;
		if (field == ZmItem.F_NAME) {
			part = i;
		}
		if (field == ZmItem.F_DEPARTMENT) {
			slv._headerList[i]._visible = isGal && this._detailedSearch;
		}
	}

	var sortable = isGal ? null : ZmItem.F_NAME;
	slv._headerList[part]._sortable = sortable;
	slv.createHeaderHtml(sortable);
};

/**
 * Done choosing addresses, add them to the compose form.
 *
 * @private
 */
ZmContactPicker.prototype._okButtonListener =
function(ev) {
	var data = this._chooser.getItems();
	DwtDialog.prototype._buttonListener.call(this, ev, [data]);
};

/**
 * Call custom popdown method.
 *
 * @private
 */
ZmContactPicker.prototype._cancelButtonListener =
function(ev) {
	DwtDialog.prototype._buttonListener.call(this, ev);
	this.popdown();
};

/**
 * @private
 */
ZmContactPicker._keyPressHdlr =
function(ev) {
	var stb = DwtControl.getTargetControl(ev);
	var charCode = DwtKeyEvent.getCharCode(ev);
	stb.clearSearch(DwtUiEvent.getTarget(ev));
	if (stb._keyPressCallback && (charCode == 13 || charCode == 3)) {
		stb._keyPressCallback.run();
		return false;
	}
	return true;
};

/**
 * @private
 */
ZmContactPicker._onclickHdlr =
function(ev) {
	var stb = DwtControl.getTargetControl(ev);
	stb.clearSearch(DwtUiEvent.getTarget(ev));
};

/***********************************************************************************/

/**
 * Creates a contact chooser.
 * @class
 * This class creates a specialized chooser for the contact picker.
 *
 * @param {DwtComposite}	parent			the contact picker
 * @param {Array}		buttonInfo		transfer button IDs and labels
 *
 * @extends		DwtChooser
 *
 * @private
 */
ZmContactChooser = function(params) {
	DwtChooser.call(this, params);
};

ZmContactChooser.prototype = new DwtChooser;
ZmContactChooser.prototype.constructor = ZmContactChooser;

/**
 * @private
 */
ZmContactChooser.prototype._createSourceListView =
function() {
	return new ZmContactChooserSourceListView(this);
};

/**
 * @private
 */
ZmContactChooser.prototype._createTargetListView =
function() {
	return new ZmContactChooserTargetListView(this, (this._buttonInfo.length > 1));
};

/**
 * The item is a AjxEmailAddress. Its address is used for comparison.
 *
 * @param {AjxEmailAddress}	item	an email address
 * @param {AjxVector}	list	list to check in
 *
 * @private
 */
ZmContactChooser.prototype._isDuplicate =
function(item, list) {
	return list.containsLike(item, item.getAddress);
};

/***********************************************************************************/

/**
 * Creates a source list view.
 * @class
 * This class creates a specialized source list view for the contact chooser.
 *
 * @param {DwtComposite}	parent			the contact picker
 *
 * @extends		DwtChooserListView
 *
 * @private
 */
ZmContactChooserSourceListView = function(parent) {
	DwtChooserListView.call(this, {parent:parent, type:DwtChooserListView.SOURCE});
	this.setScrollStyle(Dwt.CLIP);
};

ZmContactChooserSourceListView.prototype = new DwtChooserListView;
ZmContactChooserSourceListView.prototype.constructor = ZmContactChooserSourceListView;

/**
 * Returns a string representation of the object.
 *
 * @return		{String}		a string representation of the object
 * @private
 */
ZmContactChooserSourceListView.prototype.toString =
function() {
	return "ZmContactChooserSourceListView";
};

ZmContactChooserSourceListView.prototype.getToolTipContent =
function(ev) {

	if (this._hoveredItem) {
		var ttParams = {
			address:		this._hoveredItem.address,
			contact:		this._hoveredItem.__contact,
			ev:				ev,
			noRightClick:	true
		};
		var ttCallback = new AjxCallback(this,
			function(callback) {
				appCtxt.getToolTipMgr().getToolTip(ZmToolTipMgr.PERSON, ttParams, callback);
			});
		return {callback:ttCallback};
	}
	else {
		return "";
	}
};

/**
 * @private
 */
ZmContactChooserSourceListView.prototype._getHeaderList =
function() {
	var headerList = [];
	headerList.push(new DwtListHeaderItem({field:ZmItem.F_TYPE, icon:"Folder", width:ZmMsg.COLUMN_WIDTH_FOLDER_CN}));
	headerList.push(new DwtListHeaderItem({field:ZmItem.F_NAME, text:ZmMsg._name, width:ZmMsg.COLUMN_WIDTH_NAME_CN, resizeable: true}));
	headerList.push(new DwtListHeaderItem({field:ZmItem.F_DEPARTMENT, text:ZmMsg.department, width:ZmMsg.COLUMN_WIDTH_DEPARTMENT_CN, resizeable: true}));
	headerList.push(new DwtListHeaderItem({field:ZmItem.F_EMAIL, text:ZmMsg.email, resizeable: true}));

	return headerList;
};

// Override of DwtListView.prototype._resetColWidth to set width; without overrriding causes vertical scrollbars to disapper
// on header resize
ZmContactChooserSourceListView.prototype._resetColWidth =
function() {

	if (!this.headerColCreated) { return; }

	var lastColIdx = this._getLastColumnIndex();
    if (lastColIdx) {
        var lastCol = this._headerList[lastColIdx];
        var lastCell = document.getElementById(lastCol._id);
		if (lastCell) {
			var div = lastCell.firstChild;
			lastCell.style.width = div.style.width = (lastCol._width || "");
		}
    }
};

/**
 * override for scrollbars in IE
 * @param headerIdx
 */
ZmContactChooserSourceListView.prototype._calcRelativeWidth =
function(headerIdx) {
	var column = this._headerList[headerIdx];
	if (!column._width || (column._width && column._width == "auto")) {
		var cell = document.getElementById(column._id);
		// UGH: clientWidth is 5px more than HTML-width (20px for IE to deal with scrollbars)
		return (cell) ? (cell.clientWidth - (AjxEnv.isIE ? Dwt.SCROLLBAR_WIDTH : 5)) : null;
	}
	return column._width;
};

/**
 * @private
 */
ZmContactChooserSourceListView.prototype._mouseOverAction =
function(ev, div) {
	DwtChooserListView.prototype._mouseOverAction.call(this, ev, div);
	var id = ev.target.id || div.id;
	var item = this.getItemFromElement(div);
	this._hoveredItem = (id && item) ? item : null;
	return true;
};

/**
 * @private
 */
ZmContactChooserSourceListView.prototype._getCellContents =
function(html, idx, item, field, colIdx, params) {
	if (field == ZmItem.F_EMAIL && AjxEnv.isIE) {
		var maxWidth = AjxStringUtil.getWidth(item.address);
		html[idx++] = "<div style='float; left; overflow: visible; width: " + maxWidth + ";'>";
		idx = ZmContactsHelper._getEmailField(html, idx, item, field, colIdx, params);
		html[idx++] = "</div>";
	}
	else {
		idx = ZmContactsHelper._getEmailField(html, idx, item, field, colIdx, params);
	}
	return idx;
};

/**
 * Returns a string of any extra attributes to be used for the TD.
 *
 * @param item		[object]	item to render
 * @param field		[constant]	column identifier
 * @param params	[hash]*		hash of optional params
 *
 * @private
 */
ZmContactChooserSourceListView.prototype._getCellAttrText =
function(item, field, params) {
	if (field == ZmItem.F_EMAIL) {
		return "style='position: relative; overflow: visible;'";
	}
};

/***********************************************************************************/

/**
 * Creates the target list view.
 * @class
 * This class creates a specialized target list view for the contact chooser.
 *
 * @param {DwtComposite}	parent			the contact picker
 * @param {constant}		showType		the show type
 * @extends		DwtChooserListView
 *
 * @private
 */
ZmContactChooserTargetListView = function(parent, showType) {
	this._showType = showType; // call before base class since base calls getHeaderList

	DwtChooserListView.call(this, {parent:parent, type:DwtChooserListView.TARGET});

	this.setScrollStyle(Dwt.CLIP);
};

ZmContactChooserTargetListView.prototype = new DwtChooserListView;
ZmContactChooserTargetListView.prototype.constructor = ZmContactChooserTargetListView;

/**
 * Returns a string representation of the object.
 *
 * @return		{String}		a string representation of the object
 */
ZmContactChooserTargetListView.prototype.toString =
function() {
	return "ZmContactChooserTargetListView";
};

/**
 * @private
 */
ZmContactChooserTargetListView.prototype._getHeaderList =
function() {
	var headerList = [];
	var view = this._view;
	if (this._showType) {
		headerList.push(new DwtListHeaderItem({field:ZmItem.F_TYPE, icon:"ContactsPicker", width:ZmMsg.COLUMN_WIDTH_TYPE_CN}));
	}
	headerList.push(new DwtListHeaderItem({field:ZmItem.F_NAME, text:ZmMsg._name, width:ZmMsg.COLUMN_WIDTH_NAME_CN, resizeable: true}));
	headerList.push(new DwtListHeaderItem({field:ZmItem.F_EMAIL, text:ZmMsg.email, resizeable: true}));

	return headerList;
};

ZmContactChooserTargetListView.prototype._mouseOverAction =
ZmContactChooserSourceListView.prototype._mouseOverAction;

/**
 * The items are AjxEmailAddress objects.
 *
 * @private
 */
ZmContactChooserTargetListView.prototype._getCellContents =
function(html, idx, item, field, colIdx, params) {
	if (field == ZmItem.F_TYPE) {
		item.setType(item._buttonId);
		html[idx++] = ZmMsg[item.getTypeAsString()];
		html[idx++] = ":";
	}
	else if (field == ZmItem.F_EMAIL && AjxEnv.isIE) {
		var maxWidth = AjxStringUtil.getWidth(item.address) + 10;
		html[idx++] = "<div style='float; left;  width: " + maxWidth + ";'>";
		idx = ZmContactsHelper._getEmailField(html, idx, item, field, colIdx, params);
		html[idx++] = "</div>";
	}
	else {
		idx = ZmContactsHelper._getEmailField(html, idx, item, field, colIdx);
	}
	return idx;
};

// Override of DwtListView.prototype._resetColWidth to set width; without overrriding causes vertical scrollbars to disapper
// on header resize
ZmContactChooserTargetListView.prototype._resetColWidth =
function() {

	if (!this.headerColCreated) { return; }

	var lastColIdx = this._getLastColumnIndex();

    if (lastColIdx) {
        var lastCol = this._headerList[lastColIdx];
        var lastCell = document.getElementById(lastCol._id);
		if (lastCell) {
			var div = lastCell.firstChild;
			lastCell.style.width = div.style.width = (lastCol._width || "");
		}
    }
};

/**
 * override for scrollbars in IE
 * @param headerIdx
 */
ZmContactChooserTargetListView.prototype._calcRelativeWidth =
function(headerIdx) {
	var column = this._headerList[headerIdx];
	if (!column._width || (column._width && column._width == "auto")) {
		var cell = document.getElementById(column._id);
		// UGH: clientWidth is 5px more than HTML-width (20px for IE to deal with scrollbars)
		return (cell) ? (cell.clientWidth - (AjxEnv.isIE ? Dwt.SCROLLBAR_WIDTH : 5)) : null;
	}
	return column._width;
};

/**
 * Returns a string of any extra attributes to be used for the TD.
 *
 * @param item		[object]	item to render
 * @param field		[constant]	column identifier
 * @param params	[hash]*		hash of optional params
 *
 * @private
 */
ZmContactChooserTargetListView.prototype._getCellAttrText =
function(item, field, params) {
	if (field == ZmItem.F_EMAIL) {
		return "style='position: relative; overflow: visible;'";
	}
};


text:
package multibase

import (
	"encoding/base64"
	"encoding/hex"
	"fmt"

	b58 "gx/ipfs/QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY/go-base58-fast/base58"
	b32 "gx/ipfs/QmfVj3x4D6Jkq9SEoi5n2NmoUomLwoeiwnYz2KQa15wRw6/base32"
)

// Encoding identifies the type of base-encoding that a multibase is carrying.
type Encoding int

// These are the supported encodings
const (
	Identity          = 0x00
	Base1             = '1'
	Base2             = '0'
	Base8             = '7'
	Base10            = '9'
	Base16            = 'f'
	Base16Upper       = 'F'
	Base32            = 'b'
	Base32Upper       = 'B'
	Base32pad         = 'c'
	Base32padUpper    = 'C'
	Base32hex         = 'v'
	Base32hexUpper    = 'V'
	Base32hexPad      = 't'
	Base32hexPadUpper = 'T'
	Base58Flickr      = 'Z'
	Base58BTC         = 'z'
	Base64            = 'm'
	Base64url         = 'u'
	Base64pad         = 'M'
	Base64urlPad      = 'U'
)

// ErrUnsupportedEncoding is returned when the selected encoding is not known or
// implemented.
var ErrUnsupportedEncoding = fmt.Errorf("selected encoding not supported")

// Encode encodes a given byte slice with the selected encoding and returns a
// multibase string (<encoding><base-encoded-string>). It will return
// an error if the selected base is not known.
func Encode(base Encoding, data []byte) (string, error) {
	switch base {
	case Identity:
		// 0x00 inside a string is OK in golang and causes no problems with the length calculation.
		return string(Identity) + string(data), nil
	case Base16:
		return string(Base16) + hex.EncodeToString(data), nil
	case Base16Upper:
		return string(Base16Upper) + hexEncodeToStringUpper(data), nil
	case Base32:
		return string(Base32) + base32StdLowerNoPad.EncodeToString(data), nil
	case Base32Upper:
		return string(Base32Upper) + base32StdUpperNoPad.EncodeToString(data), nil
	case Base32hex:
		return string(Base32hex) + base32HexLowerNoPad.EncodeToString(data), nil
	case Base32hexUpper:
		return string(Base32hexUpper) + base32HexUpperNoPad.EncodeToString(data), nil
	case Base32pad:
		return string(Base32pad) + base32StdLowerPad.EncodeToString(data), nil
	case Base32padUpper:
		return string(Base32padUpper) + base32StdUpperPad.EncodeToString(data), nil
	case Base32hexPad:
		return string(Base32hexPad) + base32HexLowerPad.EncodeToString(data), nil
	case Base32hexPadUpper:
		return string(Base32hexPadUpper) + base32HexUpperPad.EncodeToString(data), nil
	case Base58BTC:
		return string(Base58BTC) + b58.EncodeAlphabet(data, b58.BTCAlphabet), nil
	case Base58Flickr:
		return string(Base58Flickr) + b58.EncodeAlphabet(data, b58.FlickrAlphabet), nil
	case Base64pad:
		return string(Base64pad) + base64.StdEncoding.EncodeToString(data), nil
	case Base64urlPad:
		return string(Base64urlPad) + base64.URLEncoding.EncodeToString(data), nil
	case Base64url:
		return string(Base64url) + base64.RawURLEncoding.EncodeToString(data), nil
	case Base64:
		return string(Base64) + base64.RawStdEncoding.EncodeToString(data), nil
	default:
		return "", ErrUnsupportedEncoding
	}
}

// Decode takes a multibase string and decodes into a bytes buffer.
// It will return an error if the selected base is not known.
func Decode(data string) (Encoding, []byte, error) {
	if len(data) == 0 {
		return 0, nil, fmt.Errorf("cannot decode multibase for zero length string")
	}

	enc := Encoding(data[0])

	switch enc {
	case Identity:
		return Identity, []byte(data[1:]), nil
	case Base16, Base16Upper:
		bytes, err := hex.DecodeString(data[1:])
		return enc, bytes, err
	case Base32, Base32Upper:
		bytes, err := b32.RawStdEncoding.DecodeString(data[1:])
		return enc, bytes, err
	case Base32hex, Base32hexUpper:
		bytes, err := b32.RawHexEncoding.DecodeString(data[1:])
		return enc, bytes, err
	case Base32pad, Base32padUpper:
		bytes, err := b32.StdEncoding.DecodeString(data[1:])
		return enc, bytes, err
	case Base32hexPad, Base32hexPadUpper:
		bytes, err := b32.HexEncoding.DecodeString(data[1:])
		return enc, bytes, err
	case Base58BTC:
		bytes, err := b58.DecodeAlphabet(data[1:], b58.BTCAlphabet)
		return Base58BTC, bytes, err
	case Base58Flickr:
		bytes, err := b58.DecodeAlphabet(data[1:], b58.FlickrAlphabet)
		return Base58Flickr, bytes, err
	case Base64pad:
		bytes, err := base64.StdEncoding.DecodeString(data[1:])
		return Base64pad, bytes, err
	case Base64urlPad:
		bytes, err := base64.URLEncoding.DecodeString(data[1:])
		return Base64urlPad, bytes, err
	case Base64:
		bytes, err := base64.RawStdEncoding.DecodeString(data[1:])
		return Base64, bytes, err
	case Base64url:
		bytes, err := base64.RawURLEncoding.DecodeString(data[1:])
		return Base64url, bytes, err
	default:
		return -1, nil, ErrUnsupportedEncoding
	}
}


text:
**WARN**: This tool is now **deprecated**. You can use the [de-workbench](https://github.com/github-vipera/de-workbench) tool instead taht contains all the features of dynamicengine-tools and additional features as well as support for Cordova 8 and the latest Android and iOS platforms.

# dynamicengine-debugger package

Dynamic Engine Debugger Plugin for ATOM

![A screenshot of your package](https://f.cloud.github.com/assets/69169/2290250/c35d867a-a017-11e3-86be-cd7c5bf3ff9b.gif)


text:
object Test extends App {
  val c1 = new A with C {}
  val c2 = new C with A {}
  val c3 = new C with A { override def t(): Unit = macro Macro.t }
  val c4 = new C with A { override def t(): Unit = () }
}


text:
<?php

namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * MenuMain
 *
 * @ORM\Table(name="menu_main", indexes={@ORM\Index(name="menu_main_parent-menu_main_id", columns={"Parent"})})
 * @ORM\Entity
 */
class MenuMain
{
    /**
     * @var integer
     *
     * @ORM\Column(name="Id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="Title", type="string", length=50, nullable=true)
     */
    private $title;

    /**
     * @var integer
     *
     * @ORM\Column(name="Order", type="integer", nullable=false)
     */
    private $order = '0';

    /**
     * @var string
     *
     * @ORM\Column(name="Route", type="string", length=255, nullable=false)
     */
    private $route = '';

    /**
     * @var \Application\Entity\MenuMain
     *
     * @ORM\ManyToOne(targetEntity="Application\Entity\MenuMain")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="Parent", referencedColumnName="Id")
     * })
     */
    private $parent;

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set title
     *
     * @param string $title
     *
     * @return MenuMain
     */
    public function setTitle($title)
    {
        $this->title = $title;

        return $this;
    }

    /**
     * Get title
     *
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * Set order
     *
     * @param integer $order
     *
     * @return MenuMain
     */
    public function setOrder($order)
    {
        $this->order = $order;

        return $this;
    }

    /**
     * Get order
     *
     * @return integer
     */
    public function getOrder()
    {
        return $this->order;
    }

    /**
     * Set route
     *
     * @param string $route
     *
     * @return MenuMain
     */
    public function setRoute($route)
    {
        $this->route = $route;

        return $this;
    }

    /**
     * Get route
     *
     * @return string
     */
    public function getRoute()
    {
        return $this->route;
    }

    /**
     * Set parent
     *
     * @param \Application\Entity\MenuMain $parent
     *
     * @return MenuMain
     */
    public function setParent(\Application\Entity\MenuMain $parent = null)
    {
        $this->parent = $parent;

        return $this;
    }

    /**
     * Get parent
     *
     * @return \Application\Entity\MenuMain
     */
    public function getParent()
    {
        return $this->parent;
    }
}