vþ�@†¾Üð¹¾‚cÜ'²ÇÛ¯êE¢=Jn4	ä€w©°Oñ^ÒJ?¨7:�ÙìïßÁY´ŒWð=Â(ÿ5ÄÏm„^ÚBí/ø×ù>šŽT*f,ç8Mx+�#í³qIjú0Ÿ\„lœ»á¥9Üœíñ‰$QÞˆÚ"¾¶»Ã^Vâ÷°ò‘XÍs:6¼
õ@+sÿÛ¢íÿ¸ØÉæÞtÖÆ>Š¯ç¬ÿÏîJ»œ·_oÙ¸$6Vð*¬Ü4N¾“®’ !`�ë�ç­""dNÊ¦£i¹¬Æy¬ž›ŽTÊ±Z§²›ë%híQ÷Am§¥àYˆlÏªcð×°Q�<&ƒjÍ–½YˆøB�ÇìFÒHúÚ¼o±™NéqäGE Eýo'¼ZEBÜåÐ½»,û$˜.[àqõ‚‘ï_ç]ç9²Â˜bê«rðÇ£Ìc^54ìât=Lößÿ:jâŽë·Yie@ Ø0°±ù>k¿N9ÃáK³½s•k‹é*¸�2F9Ç;RîžÖ‡99Z»¡<�©¿„ð‘AC‘Äqá	[‰?�M‹cIÏ[ï4 “gqr†™í©Î¹º"=%ävež¦‚Æ~mËîsûèºò¦IÜo4N ±ÏÓá·'ºL„òdRÎòFN3POÝ<ÓŒ›UÔ¿½åç“a’´7-4r¦¹	AÙ`8$‡OGâºuUÑÖw”Žh·8\pCÙNa„2/y,(ø‡_ã.Ÿ–#®j«o¸!bM¸ÓKDBNó7•Øëí¦Óƒ…6¸¸'ÊÎ—ln˜9'Õ:È^X½ç n7!oÃÈ.�RgAáÀv×|3Ûi2@Û…œ+«xA>ŠñÅ­Åºxª×bŽÀ´\F¿9'Õ:È^X½ç n7!o2A�Ò¡A¨'Ñây71_£Ã"2¬!ÂÃe6œ/ÛÜ €ø.ƒÍ':Ê§ëïÈ€ÐñÊédeÝ]P@„¿ì �‘þtÛ‚<›¥,º³ü°)R2\ð”ùœÅ3#¡ú~4ƒá !`�˜ñ#/L'ÁÉOŽ$ÖfÁñ8#‹«Wð îó†5ûˆ™«Lßš·£þ²­p”Ûo*|*5`�…<¼2" ä»Ë|¢*™Ø¨ž×9‚‰õÁ:€gä¡üî8$‡OGâºuUÑÖw”ŽˆñÊÏâ^VËÄ’±7´ÉhÓA¥¢3àëÜ©çÌõ T/N“‚ÖèòøS¡ü�Š¢”<ì0 ŠÛƒNìwÍ° N-r¶¸nW!¤åm21oGô›XÙ;n„îr%�;YÛËB;Ðÿ¹o�äù²�J¡¨ÚèTÞ],™Ùv¦;Ý`†Þ7jí¾zÐ`K¨6{×?Ä¸÷Ù‚ßr¯$|F˜�ž(É-ZÏêÑe¹û=bB©9{‡¹:f—¤ý3pöˆµ„ ¤—r³?i`³š�õÿŸI…ÿG&7è¢ÏÕ‰Ó€ï´Ë4ÿü=+j‘�_N94ÕŒßœí\#œIV![SèÆÏ$ˆkƒKc,héV[ñÁˆƒZnn¥±pë¨wœ_Ý~�²$¾'ÜU÷aHë!#aß©<]ñ¿[€K84_µi]õ�"vR?<í¼ŠJpÒ§ –}^c°ve²fŒñÔ<ƒB«yO"6T5¸ëi¼þôUœ¡§?7 ÷càÍXa\pR�Ø0L‚IGÅ°æÚn�l šÈ­™Ã:û+xÐ©¬<¸ä'Ú¶D\jäª§&ûZ¯¡:™9*c}óÀ59tìb&7ïpw‘ƒmË|Ô,ýì:r ¡È´%Äo‰’)aå®4]ßC0Æ†ƒÏ`ÃÑ]?Ýd¹n[ï4¨óCæUm]á*x¨ófxÂëÓ<÷ýæ†"%óëB7Rˆë=ñ_Q™+f¥Ìßžß¨%ÔæVøÀáÝ›ÒSÅ$Ÿ¦ðGa¯"ä”Šo\V&Ä!>'t˜S=åÙò¶»À¨™ˆØ.}A‰º±åÚ/K“¤D{D
üèZ[¥g˜”e¸å7ÄP»gïìf'…áíaX„¹Y˜?O
Úi¡¤’ç¸’£'þJï½
<ëv�Òšv|; ýP>I*	+Y÷@g–AÐx¬R¶5Ù†o-ÓK/ƒHÂÃ+Enõ{{ïa\[ƒ€�Lc‚¢‚7ì\ð¦v¤Þ`'>äZÊAQÐ×\Ô¦ â
uúqÛ…‰R'¸Ž¶%†ã£vwš¯A�Üo÷ÒäŠ,ZÅ£°Ýûƒ÷w´ÝFÙä°©³';úç&�Ñ‡ÕHÜ:«ºj­~ÔT²ˆ/x{å6¨ ÆôÏ+âQí�c,é½«îêô9�d�Op� —²¿<ƒ84·é˜&.Ø*ªAOÚ†Á�
	_rFñÅ<;dÈÖ…ßØÙ­]ôÕ`Ý¿e¬~-ÓÑÀö‡Ö’[ý”]NõÒÃkcfþyÁØ¥9@®ðHŽØËWöiü% yŒ‘a3·ODj�¡ úØ¸9òiwŸŽ�JÆ+â`•¾\ö£æé�Ïd_pÛzbÌ£ëApYï‰£ð&RbGE�™wqñ îJ§™•¿o3Vä§ðòûð_K$šï÷?šºoÙ%)p1'*ùd‹8˜¢¨_îñÁï‰»×øudêhB„F·ù�£ Òa¿•™3C°1<Þö¿�ÕàáW*"aÂlŠÔº©Ó%ª¬¢ŒÌ2Cyp÷­!ÔÕC%ý V¢[uÛ¿òáL›añ}Žr.ø}ª l6ÿqE‘�:#GòNÔj÷w�Íði²€ÕÞSk­’§V­ð÷U¦ñóGC¡¬Ã@`¿jž�“|¸7F:NoÑe¦VÌ‚çxå#Ó°¶-×‡Ï¼ˆ©ôìP0<%’µ)YXxúx‡•ÁáBúx¯Lú¸1ÄæÉgÚTp]êîF¹wÜAdZ;û ¹\˜X{Žx*Voh«wI¬VÈ¶.ol)Èì”T+È
ÿj$‘&±ÿniõ®e³½l(©AÇKFUÝ¢Í0ÜCè:;ÔáÜ9§vZ…æ1Ç/»Ø¡.z!Ä]Î¤ÀkÔ|«·H5þÉÉ?ƒx¸1.ÉÜf‰û"Ë™E±@‹`‰¥" åÝà,Ð¥ïºwÙÝÆ°ƒGŠÔÁîáN…Q²ýÊ#Ýö¤ªêw,ð~Lò|ÁJ‰dò`Îß5•˜BœßJs^4E[«<dödÞ€LŒ+4çA7RÂðáõJ™7ók•…¿A¸
äØ+ü1ƒ]¯Cj çäù•Ö¢)€òï¡¾•Ý=•P7Ã÷‰¢É;üš{FƒHñ=~6‹=u^’jà*€Qâ¦µåz{­aÙŽ!…ôà'3H‚[¥…µo#UåªºQ¿ MöG’9y÷Møû(VÇa6—aÃê,\º	ÛcÙDuv/§†ØÒçaE±_Å …�¾CR%�y­Î2cìæ+ð’´åmæ¼uÖñ]Êƒt-¢ÉšûAÏ+tU�øj„"fòÛµÖÝ5šQbšÕ¡“'AŒ¥¼…Õ�”˜§ëO‹Ž]0|G�úGž¯±áÕ>0ñM½0Ë-Ú�Ëea‹lT£¨\†¡¾Uá=R³MF­,‰ítò/¡œ%|ÐeKq¬á`V7
c‡9ÍÉ÷&«O4ÜßJÌ¥82göB­À¾´tºtÌ 2/žkUk9òtj{›ë“0/<Ä«7ZúÁL(^ó‘pôsù,€º†4ëª…¤ômÏ�U=[çò]>à4œ¼GÒîG=¶p5u9kW}ƒ¨r×�YÉ¿4+Oô‰/0ÃÏfFàèÏpnX4gøaŒ§D¶0Gú _©·qçoM8g+ìRR´õñ¡`©§¸^G¶£)*ï´}ˆQ_ÙYM	Y°­Uý-œ³±Kå°•´PfJéŒ6ï(Ù±Æ�¹{Š ¼¸Ëÿl•Üóbæ¤9<û�ë.ò„Ö7)r»í€o+Ö n^ßA— (§–ƒ¦×L|‘BIU’±:"isAG9õŸyÃQ_þSåÐ8W‡A{íZäšÔ�&é \UÌ`Ñ•ÚXŽšÍÍV`o‰t`ò½®fö�ï­‘~‰?%Té3¬|Ð»c.ñé¥OÔÉ_è
ÀÉòÒWüµ×´ˆ&á•I·éèXïÒW´ÿ:a¥:³s$‚¶»(ÈyÔ¿0øñþw^ókËY„,1•ÞSc©[…võŠm:…Í¡§SàÊ�Lq’¦íuÃP‚à²;ßQöí ñ!¯�sÕjh[óT]L“}×y´ß)yF¥Nò9½wåIžì!êë0]³E„ŸW¹¾pØaR¾Ú¬l¨?“mÜåvÂ³5½627(ÎMîLÝ'2“¸|b³¢¢ò¹¤Ø$’ÖåÃ2î°™+7Dõp¥éVÆY0ü�â@MŸ¡)m°`’ðê¯¢äú%ü?½Ý•±b²“u-—b=ö¾¼º~nQn@ìv¡roÓ:?kVõ²X�•�Ÿtr½ÀÃ°{r|;¥×‘‡õ&�Ýf6M¸!€Õ×?Í¾åu°[æØ•ÎS.�ÏDœúoÌ±qœP0äÖËßJÛÓæà¸žGR™Zb&Zz.PÊ1}/@`+éÎn‘ÜclVW4�²ò«¥&ø…æ" ×´é‡ù?æ‹1}¥¿�v æGÅž: zá×Vœ{þsTuçaüÂd Éä+
Ñ“²À­óí�…&É_¨(UÔÓ0IÈÇ zr8÷˜Œ®QJ“<kÐ¨ó›ALH'sxÖT'Ý,äpžË«NZ'ê al%Y ¥$ls›hr”€€«¤Ê‘õC—¨Ùxmžª1N¹Î°zjÀùœ¼÷�#å½MZz]Õ¡\&}Š`b5öìcnÂ|£¥œäPšç|šaZ…iZ*fŠàÚj]»—þÔ.‚+Zl=	ðâ$Y�p4–ÙŒÏU€fQœ»ºEŽ 
¢,®Á¬ssBz€<ö�Ð•ä€‹öIô¦‚=�ÛÛ˜ŸéøÞ;CØˆ�•HïÒqõ.»9dáÈèÜKïPÇt&gý¿Çià�/Öµhl-’ˆ»;nŠFúª=�¹Üµ-Ü£ž´I§eudc…ìºþ\ãüLh›a¦èKuÈâ`.;Ò˜y–¼ßËÓýÐò;Â~ö÷„Ùí&Vô34T·íoQØÎ:ëNÍdY¸[m�Ä7¥�.ý7—š—â œnÙÌ´úô´
õ�SvY0R||1wû1A§óÙ"”yÉ@²¬»‹Þ¹c·šÆ—`¤0‚|â�[Œ”}g{bé°Q\µ�P~»~-ÛJ.\…1…(Vüìf#ã;â‹Ò•šrc‘;yD²8Ø‘ÏKa†úI[2»XÉ"®BÎ‘f½‡i‘*‰Þ€OÚƒW{ÿqÑ˜úVµBackup objects").ThrowAsJavaScriptException();
        return;
    }

    auto length = info.Length();

    if (length <= 0 || !Database::HasInstance(info[0])) {
        Napi::TypeError::New(env, "Database object expected").ThrowAsJavaScriptException();
        return;
    }
    else if (length <= 1 || !info[1].IsString()) {
        Napi::TypeError::New(env, "Filename expected").ThrowAsJavaScriptException();
        return;
    }
    else if (length <= 2 || !info[2].IsString()) {
        Napi::TypeError::New(env, "Source database name expected").ThrowAsJavaScriptException();
        return;
    }
    else if (length <= 3 || !info[3].IsString()) {
        Napi::TypeError::New(env, "Destination database name expected").ThrowAsJavaScriptException();
        return;
    }
    else if (length <= 4 || !info[4].IsBoolean()) {
        Napi::TypeError::New(env, "Direction flag expected").ThrowAsJavaScriptException();
        return;
    }
    else if (length > 5 && !info[5].IsUndefined() && !info[5].IsFunction()) {
        Napi::TypeError::New(env, "Callback expected").ThrowAsJavaScriptException();
        return;
    }

    this->db = Napi::ObjectWrap<Database>::Unwrap(info[0].As<Napi::Object>());
    this->db->Ref();

    auto filename = info[1].As<Napi::String>();
    auto sourceName = info[2].As<Napi::String>();
    auto destName = info[3].As<Napi::String>();
    auto filenameIsDest = info[4].As<Napi::Boolean>();

    info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filename", filename));
    info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("sourceName", sourceName));
    info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("destName", destName));
    info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filenameIsDest", filenameIsDest));

    auto* baton = new InitializeBaton(this->db, info[5].As<Napi::Function>(), this);
    baton->filename = filename.Utf8Value();
    baton->sourceName = sourceName.Utf8Value();
    baton->destName = destName.Utf8Value();
    baton->filenameIsDest = filenameIsDest.Value();

    this->db->Schedule(Work_BeginInitialize, baton);
}

void Backup::Work_BeginInitialize(Database::Baton* baton) {
    assert(baton->db->open);
    baton->db->pending++;
    auto env = baton->db->Env();
    CREATE_WORK("sqlite3.Backup.Initialize", Work_Initialize, Work_AfterInitialize);
}

void Backup::Work_Initialize(napi_env e, void* data) {
    BACKUP_INIT(InitializeBaton);

    // In case stepping fails, we use a mutex to make sure we get the associated
    // error message.
    auto* mtx = sqlite3_db_mutex(baton->db->_handle);
    sqlite3_mutex_enter(mtx);

    backup->status = sqlite3_open(baton->filename.c_str(), &backup->_otherDb);

    if (backup->status == SQLITE_OK) {
        backup->_handle = sqlite3_backup_init(
            baton->filenameIsDest ? backup->_otherDb : backup->db->_handle,
            baton->destName.c_str(),
            baton->filenameIsDest ? backup->db->_handle : backup->_otherDb,
            baton->sourceName.c_str());
    }
    backup->_destDb = baton->filenameIsDest ? backup->_otherDb : backup->db->_handle;

    if (backup->status != SQLITE_OK) {
        backup->message = std::string(sqlite3_errmsg(backup->_destDb));
        sqlite3_close(backup->_otherDb);
        backup->_otherDb = NULL;
        backup->_destDb = NULL;
    }

    sqlite3_mutex_leave(mtx);
}

void Backup::Work_AfterInitialize(napi_env e, napi_status status, void* data) {
    std::unique_ptr<InitializeBaton> baton(static_cast<InitializeBaton*>(data));
    auto* backup = baton->backup;

    auto env = backup->Env();
    Napi::HandleScope scope(env);

    if (backup->status != SQLITE_OK) {
        Error(baton.get());
        backup->FinishAll();
    }
    else {
        backup->inited = true;
        Napi::Function cb = baton->callback.Value();
        if (!cb.IsEmpty() && cb.IsFunction()) {
            Napi::Value argv[] = { env.Null() };
            TRY_CATCH_CALL(backup->Value(), cb, 1, argv);
        }
    }
    BACKUP_END();
}

Napi::Value Backup::Step(const Napi::CallbackInfo& info) {
    auto* backup = this;
    auto env = backup->Env();

    REQUIRE_ARGUMENT_INTEGER(0, pages);
    OPTIONAL_ARGUMENT_FUNCTION(1, callback);

    auto* baton = new StepBaton(backup, callback, pages);
    backup->GetRetryErrors(baton->retryErrorsSet);
    backup->Schedule(Work_BeginStep, baton);
    return info.This();
}

void Backup::Work_BeginStep(Baton* baton) {
    BACKUP_BEGIN(Step);
}

void Backup::Work_Step(napi_env e, void* data) {
    BACKUP_INIT(StepBaton);
    if (backup->_handle) {
        backup->status = sqlite3_backup_step(backup->_handle, baton->pages);
        backup->remaining = sqlite3_backup_remaining(backup->_handle);
        backup->pageCount = sqlite3_backup_pagecount(backup->_handle);
    }
    if (backup->status != SQLITE_OK) {
        // Text of message is a little awkward to get, since the error is not associated
        // with a db connection.
#if SQLITE_VERSION_NUMBER >= 3007015
        // sqlite3_errstr is a relatively new method
        backup->message = std::string(sqlite3_errstr(backup->status));
#else
        backup->message = "Sqlite error";
#endif
        if (baton->retryErrorsSet.size() > 0) {
            if (baton->retryErrorsSet.find(backup->status) == baton->retryErrorsSet.end()) {
                backup->FinishSqlite();
            }
        }
    }
}

void Backup::Work_AfterStep(napi_env e, napi_status status, void* data) {
    std::unique_ptr<StepBaton> baton(static_cast<StepBaton*>(data));
    auto* backup = baton->backup;

    auto env = backup->Env();
    Napi::HandleScope scope(env);

    if (backup->status == SQLITE_DONE) {
        backup->completed = true;
    } else if (!backup->_handle) {
        backup->failed = true;
    }

    if (backup->status != SQLITE_OK && backup->status != SQLITE_DONE) {
        Error(baton.get());
    }
    else {
        // Fire callbacks.
        Napi::Function cb = baton->callback.Value();
        if (!cb.IsEmpty() && cb.IsFunction()) {
            Napi::Value argv[] = { env.Null(), Napi::Boolean::New(env, backup->status == SQLITE_DONE) };
            TRY_CATCH_CALL(backup->Value(), cb, 2, argv);
        }
    }

    BACKUP_END();
}

Napi::Value Backup::Finish(const Napi::CallbackInfo& info) {
    auto* backup = this;
    auto env = backup->Env();

    OPTIONAL_ARGUMENT_FUNCTION(0, callback);

    auto* baton = new Baton(backup, callback);
    backup->Schedule(Work_BeginFinish, baton);
    return info.This();
}

void Backup::Work_BeginFinish(Baton* baton) {
    BACKUP_BEGIN(Finish);
}

void Backup::Work_Finish(napi_env e, void* data) {
    BACKUP_INIT(Baton);
    backup->FinishSqlite();
}

void Backup::Work_AfterFinish(napi_env e, napi_status status, void* data) {
    std::unique_ptr<Baton> baton(static_cast<Baton*>(data));
    auto* backup = baton->backup;

    auto env = backup->Env();
    Napi::HandleScope scope(env);

    backup->FinishAll();

    // Fire callback in case there was one.
    Napi::Function cb = baton->callback.Value();
    if (!cb.IsEmpty() && cb.IsFunction()) {
        TRY_CATCH_CALL(backup->Value(), cb, 0, NULL);
    }

    BACKUP_END();
}

void Backup::FinishAll() {
    assert(!finished);
    if (!completed && !failed) {
        failed = true;
    }
    finished = true;
    CleanQueue();
    FinishSqlite();
    db->Unref();
}

void Backup::FinishSqlite() {
    if (_handle) {
        sqlite3_backup_finish(_handle);
        _handle = NULL;
    }
    if (_otherDb) {
        sqlite3_close(_otherDb);
        _otherDb = NULL;
    }
    _destDb = NULL;
}

Napi::Value Backup::IdleGetter(const Napi::CallbackInfo& info) {
    auto* backup = this;
    bool idle = backup->inited && !backup->locked && backup->queue.empty();
    return Napi::Boolean::New(this->Env(), idle);
}

Napi::Value Backup::CompletedGetter(const Napi::CallbackInfo& info) {
    auto* backup = this;
    return Napi::Boolean::New(this->Env(), backup->completed);
}

Napi::Value Backup::FailedGetter(const Napi::CallbackInfo& info) {
    auto* backup = this;
    return Napi::Boolean::New(this->Env(), backup->failed);
}

Napi::Value Backup::RemainingGetter(const Napi::CallbackInfo& info) {
    auto* backup = this;
    return Napi::Number::New(this->Env(), backup->remaining);
}

Napi::Value Backup::PageCountGetter(const Napi::CallbackInfo& info) {
    auto* backup = this;
    return Napi::Number::New(this->Env(), backup->pageCount);
}

Napi::Value Backup::RetryErrorGetter(const Napi::CallbackInfo& info) {
    auto* backup = this;
    return backup->retryErrors.Value();
}

void Backup::RetryErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value) {
    auto* backup = this;
    auto env = backup->Env();
    if (!value.IsArray()) {
        Napi::Error::New(env, "retryErrors must be an array").ThrowAsJavaScriptException();
        return;
    }
    Napi::Array array = value.As<Napi::Array>();
    backup->retryErrors.Reset(array, 1);
}

void Backup::GetRetryErrors(std::set<int>& retryErrorsSet) {
    retryErrorsSet.clear();
    Napi::Array array = retryErrors.Value();
    auto length = array.Length();
    for (size_t i = 0; i < length; i++) {
        Napi::Value code = (array).Get(static_cast<uint32_t>(i));
        if (code.IsNumber()) {
            retryErrorsSet.insert(code.As<Napi::Number>().Int32Value());
        }
    }
}
