From 2c2a2fcafeb66e4193a4034ba88fab02ef81e51e Mon Sep 17 00:00:00 2001 From: dazedcat19 <59296763+dazedcat19@users.noreply.github.com> Date: Sat, 22 Feb 2020 01:55:06 +0800 Subject: [PATCH] rewrite lua module updater, now working with directories -github api has a limitation of 5000 queries per day. so authorization token is needed here. -added simple dialog with tmemo. maybe need to fix later -todo: move non website module file to other director-y --- baseunits/FMDOptions.pas | 6 +- baseunits/GithubRepo.pas | 271 +++++++++++ changelog.txt | 4 + config/base.ini | 12 +- make_release_win.bat | 4 +- mangadownloader/forms/frmDialogYesNo.lfm | 65 +++ mangadownloader/forms/frmDialogYesNo.lrj | 5 + mangadownloader/forms/frmDialogYesNo.pas | 32 ++ .../forms/frmLuaModulesUpdater.lfm | 321 ++++--------- .../forms/frmLuaModulesUpdater.pas | 441 ++++++++++-------- mangadownloader/forms/uBackupSettings.pas | 2 +- mangadownloader/md.lpi | 14 +- update | 7 +- 13 files changed, 749 insertions(+), 435 deletions(-) create mode 100644 baseunits/GithubRepo.pas create mode 100644 mangadownloader/forms/frmDialogYesNo.lfm create mode 100644 mangadownloader/forms/frmDialogYesNo.lrj create mode 100644 mangadownloader/forms/frmDialogYesNo.pas diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 79d5e0625..6cd07c1e0 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -97,7 +97,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) EXTRAS_FOLDER, MANGAFOXTEMPLATE_FOLDER, LUA_WEBSITEMODULE_FOLDER, - LUA_WEBSITEMODULE_FILE, + LUA_REPO_FOLDER, + LUA_REPO_FILE, BACKUP_FOLDER: String; // dll @@ -330,7 +331,7 @@ procedure SetAppDataDirectory(const ADir: String); CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db'; MODULES_FILE := CONFIG_FOLDER + 'modules.json'; - LUA_WEBSITEMODULE_FILE := CONFIG_FOLDER + 'luamodules.json'; + LUA_REPO_FILE := CONFIG_FOLDER + 'lua.json'; DATA_FOLDER := APPDATA_DIRECTORY + 'data' + PathDelim; @@ -343,6 +344,7 @@ procedure SetAppDataDirectory(const ADir: String); FAVORITESDB_FILE := WORK_FOLDER + 'favorites.db'; LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim; + LUA_REPO_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim; SetIniFiles; end; diff --git a/baseunits/GithubRepo.pas b/baseunits/GithubRepo.pas new file mode 100644 index 000000000..2c6db38a1 --- /dev/null +++ b/baseunits/GithubRepo.pas @@ -0,0 +1,271 @@ +unit GitHubRepo; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, httpsendthread, BaseThread, fpjson; + +type +{ TGitHubRepo } + + TGitHubRepo = class + private + ConfigFile: String; + HTTP: THTTPSendThread; + Tree: TJSONArray; + Props: TJSONObject; + protected + procedure SetAuth; + function QueryLastCommit: String; + function QueryTree: String; + function QueryProps(const ANames: TStrings): String; + public + api_url, + download_url, + owner, + name, + token, + ref, + path, + last_commit: String; + max_deep: Integer; + constructor Create(const AConfigFile: String; const AThread: TBaseThread = nil); + destructor Destroy; override; + function GetLastCommit: String; + function GetTree: TJSONArray; + function GetDownloadURL(const AName: String): String; + function GetProps(const ANames: TStrings): TJSONObject; + end; + +implementation + +uses jsonparser, jsonscanner, IniFiles, uBaseUnit; + +{ TGitHubRepo } + +procedure TGitHubRepo.SetAuth; +begin + HTTP.Headers.Values['Authorization']:=' bearer '+token; +end; + +function TGitHubRepo.QueryLastCommit: String; +var + lpath: String; +begin + lpath:=path; if lpath<>'' then lpath := ', path: "'+lpath+'"'; + Result := '{"query": "'+StringToJSONString( + '{'+ + 'repository(owner: "'+owner+'", name: "'+name+'") {'+ + 'ref(qualifiedName: "'+ref+'") {'+ + 'target {'+ + '... on Commit {'+ + 'history(first: 1'+lpath+'){ '+ + 'nodes {'+ + 'oid'+ + '}'+ + '}'+ + '}'+ + '}'+ + '}'+ + '}'+ + '}' + )+'"}'; +end; + +function TGitHubRepo.QueryTree: String; + + function onTree(const x: Integer):string; + begin + Result:= '... on Tree {'+ + 'entries {'+ + 'oid '+ + 'name '; + if x>1 then + Result+= 'object {'+ + onTree(x-1)+ + '}'; + Result+= '}'+ + '}'; + end; +begin + Result := '{"query": "'+StringToJSONString( + '{'+ + 'repository(owner: "'+owner+'", name: "'+name+'") {'+ + 'object(expression: "'+last_commit+':'+path+'") {'+ + onTree(max_deep)+ + '}'+ + '}'+ + '}' + )+'"}'; +end; + +function TGitHubRepo.QueryProps(const ANames: TStrings): String; + function onProps:String; + var + i: Integer; + lpath: String; + begin + Result:=''; + lpath :=path; if lpath<>'' then lpath+='/'; + for i:=0 to ANames.Count-1 do + begin + Result += 'p'+IntToStr(i)+': history(path: "'+lpath+ANames[i]+'", first: 1) {'+ + 'nodes {'+ + 'message '+ + 'committedDate'+ + '}'+ + '} '; + end; + end; +begin + Result := '{"query": "'+StringToJSONString( + '{'+ + 'repository(owner: "'+owner+'", name: "'+name+'") {'+ + 'object(oid: "'+last_commit+'") {'+ + '... on Commit {'+ + onProps+ + '}'+ + '}'+ + '}'+ + '}' + )+'"}'; +end; + +constructor TGitHubRepo.Create(const AConfigFile: String; + const AThread: TBaseThread); +begin + ConfigFile := AConfigFile; + HTTP := THTTPSendThread.Create(AThread); + if FileExists(ConfigFile) then + with TIniFile.Create(ConfigFile) do + try + api_url := ReadString ('GitHub', 'api_url' , ''); + download_url := ReadString ('GitHub', 'download_url', ''); + owner := ReadString ('GitHub', 'owner' , ''); + name := ReadString ('GitHub', 'name' , ''); + token := DecryptString(ReadString ('GitHub', 'token' , '')); + ref := ReadString ('GitHub', 'ref' , ''); + path := ReadString ('GitHub', 'path' , ''); + max_deep := ReadInteger ('GitHub', 'max_deep' , 2); + finally + Free; + end; + if api_url = '' then api_url := 'https://api.github.com/graphql'; + if ref = '' then ref := 'master'; + if max_deep < 1 then max_deep := 1; + last_commit:= ref; +end; + +destructor TGitHubRepo.Destroy; +begin + if Assigned(Tree) then Tree.Free; + if Assigned(Props) then Props.Free; + HTTP.Free; + inherited Destroy; +end; + +function TGitHubRepo.GetLastCommit: String; +var + d: TJSONData; + a: TJSONArray; +begin + last_commit:=''; + HTTP.Reset; + SetAuth; + d:=nil; + if HTTP.POST(api_url, QueryLastCommit) then + with TJSONParser.Create(HTTP.Document, [joUTF8]) do + try + d:=Parse; + finally + free; + end; + if Assigned(d) then + try + a:=TJSONArray(d.GetPath('data.repository.ref.target.history.nodes')); + if Assigned(a) then + last_commit:=TJSONObject(a.Items[0]).Get('oid',''); + except + end; + d.free; + Result := last_commit; +end; + +function TGitHubRepo.GetTree: TJSONArray; +var + d: TJSONData; + a: TJSONArray; +begin + result:=nil; + HTTP.Reset; + SetAuth; + if last_commit='' then + last_commit := 'master'; + d:=nil; + if HTTP.POST(api_url, QueryTree) then + with TJSONParser.Create(HTTP.Document, [joUTF8]) do + try + d:=Parse; + finally + free; + end; + if Assigned(Tree) then + FreeAndNil(Tree); + if Assigned(d) then + begin + try + a:=TJSONArray(d.GetPath('data.repository.object.entries')); + if Assigned(a) then + Tree:=TJSONArray(a.Clone); + except + end; + d.free; + end; + Result := Tree; +end; + +function TGitHubRepo.GetDownloadURL(const AName: String): String; +var + lpath: String; +begin + lpath:=path; if lpath<>'' then lpath:=lpath+'/'; + Result:=AppendURLDelim(download_url)+owner+'/'+name+'/'+ref+'/'+lpath+AName; +end; + +function TGitHubRepo.GetProps(const ANames: TStrings): TJSONObject; +var + d: TJSONData; + o: TJSONObject; +begin + result:=nil; + HTTP.Reset; + SetAuth; + if last_commit='' then + last_commit := 'master'; + d:=nil; + if HTTP.POST(api_url, QueryProps(ANames)) then + with TJSONParser.Create(HTTP.Document, [joUTF8]) do + try + d:=Parse; + finally + free; + end; + if Assigned(Props) then + FreeAndNil(Props); + if Assigned(d) then + begin + try + o:=TJSONObject(d.GetPath('data.repository.object')); + if Assigned(o) then + Props:=TJSONObject(o.Clone); + except + end; + d.free; + end; + Result := Props; +end; + +end. + diff --git a/changelog.txt b/changelog.txt index 3ca7ac9d8..56322367f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ https://github.com/fmd-project-team/FMD Changelog: ([!] Important, [+] Addition, [-] Removal, [*] Fix/Change, [?] Feedback needed) +1.2.0.0 (22.02.2020) +[*] Lua modules structure changed +Full changes: https://github.com/fmd-project-team/FMD/compare/1.1.4.0...1.2.0.0 + 1.1.4.0 (15.02.2020) [*] Various changes and bug fixes Full changes: https://github.com/fmd-project-team/FMD/compare/1.1.3.0...1.1.4.0 diff --git a/config/base.ini b/config/base.ini index 0cfae077f..5bb57edf0 100644 --- a/config/base.ini +++ b/config/base.ini @@ -4,5 +4,13 @@ DB_URL=https://raw.githubusercontent.com/fmd-project-team/FMD-WebsiteDatabases/m UPDATE_URL=https://raw.githubusercontent.com/fmd-project-team/FMD/master/update CHANGELOG_URL=https://raw.githubusercontent.com/fmd-project-team/FMD/master/changelog.txt UPDATE_PACKAGE_NAME=updatepackage.7z -MODULES_URL=https://api.github.com/repos/fmd-project-team/FMD/contents/lua/modules -MODULES_URL2=https://github.com/fmd-project-team/FMD/file-list/master/lua/modules + +[GitHub] +api_url=https://api.github.com/graphql +download_url=https://raw.githubusercontent.com/ +owner=fmd-project-team +name=FMD +token=q0NI9Ztgiv1z5s5sYwscdz/CCYQnfGkbRbDGd02dwhsFzXNH9WPNWg== +ref=master +path=lua +max_deep=4 diff --git a/make_release_win.bat b/make_release_win.bat index 4458df4ea..e221e632f 100644 --- a/make_release_win.bat +++ b/make_release_win.bat @@ -8,10 +8,10 @@ SET repodl=https://github.com/fmd-project-team/FMD/releases/download/ ECHO ; automatically build with make_release_win.bat>update CALL :makerelease i386-win32 Win32 --no-write-project -ECHO WIN32=%repodl%%fver%/%oname%>>update +ECHO WIN32=%repodl%%fverb%/%oname%>>update CALL :makerelease x86_64-win64 Win64 --no-write-project -ECHO WIN64=%repodl%%fver%/%oname%>>update +ECHO WIN64=%repodl%%fverb%/%oname%>>update ECHO VERSION=%fverb%>>update diff --git a/mangadownloader/forms/frmDialogYesNo.lfm b/mangadownloader/forms/frmDialogYesNo.lfm new file mode 100644 index 000000000..cb962b639 --- /dev/null +++ b/mangadownloader/forms/frmDialogYesNo.lfm @@ -0,0 +1,65 @@ +object frmDialogYN: TfrmDialogYN + Left = 414 + Height = 325 + Top = 174 + Width = 437 + BorderIcons = [biSystemMenu] + Caption = 'Dialog' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 + ClientHeight = 325 + ClientWidth = 437 + Color = clWindow + Position = poDesktopCenter + LCLVersion = '2.1.0.0' + object btYes: TButton + AnchorSideRight.Control = btNo + AnchorSideBottom.Control = btNo + AnchorSideBottom.Side = asrBottom + Left = 339 + Height = 25 + Top = 294 + Width = 44 + Anchors = [akRight, akBottom] + AutoSize = True + Caption = '&Yes' + Default = True + ModalResult = 6 + TabOrder = 0 + end + object btNo: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 389 + Height = 25 + Top = 294 + Width = 42 + Anchors = [akRight, akBottom] + AutoSize = True + Caption = '&No' + ModalResult = 7 + TabOrder = 1 + end + object mMessages: TMemo + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btNo + Left = 6 + Height = 282 + Top = 6 + Width = 425 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderStyle = bsNone + Color = clWindow + ReadOnly = True + ScrollBars = ssAutoBoth + TabOrder = 2 + WordWrap = False + end +end diff --git a/mangadownloader/forms/frmDialogYesNo.lrj b/mangadownloader/forms/frmDialogYesNo.lrj new file mode 100644 index 000000000..7ba8043b4 --- /dev/null +++ b/mangadownloader/forms/frmDialogYesNo.lrj @@ -0,0 +1,5 @@ +{"version":1,"strings":[ +{"hash":78611287,"name":"tfrmdialogyn.caption","sourcebytes":[68,105,97,108,111,103],"value":"Dialog"}, +{"hash":180163,"name":"tfrmdialogyn.btyes.caption","sourcebytes":[38,89,101,115],"value":"&Yes"}, +{"hash":11087,"name":"tfrmdialogyn.btno.caption","sourcebytes":[38,78,111],"value":"&No"} +]} diff --git a/mangadownloader/forms/frmDialogYesNo.pas b/mangadownloader/forms/frmDialogYesNo.pas new file mode 100644 index 000000000..db2c506c9 --- /dev/null +++ b/mangadownloader/forms/frmDialogYesNo.pas @@ -0,0 +1,32 @@ +unit frmDialogYesNo; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls; + +type + + { TfrmDialogYN } + + TfrmDialogYN = class(TForm) + btYes: TButton; + btNo: TButton; + mMessages: TMemo; + private + + public + + end; + +var + frmDialogYN: TfrmDialogYN; + +implementation + +{$R *.lfm} + +end. + diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lfm b/mangadownloader/forms/frmLuaModulesUpdater.lfm index 32acc0461..d5e18a538 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.lfm +++ b/mangadownloader/forms/frmLuaModulesUpdater.lfm @@ -11,7 +11,7 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm ClientWidth = 580 OnCreate = FormCreate OnDestroy = FormDestroy - LCLVersion = '2.0.6.0' + LCLVersion = '2.1.0.0' object vtLuaModulesRepos: TVirtualStringTree AnchorSideLeft.Control = Owner AnchorSideTop.Control = btCheckUpdate @@ -186,231 +186,100 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm left = 200 top = 128 Bitmap = { - 4C69070000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003B7F320015A9000015A9000015A9 - 000015A9000015AA009915AA00CC15AA00CC15AA009915A9000015A9000015A9 - 000015A90000094D0000FFFFFF00FFFFFF00119A0000129F000014A8000014A8 - 000014A8000014A800CC72E961FF71E860FF14A800CC14A8000014A8000014A8 - 0000129F0000119A0000FFFFFF00FFFFFF00119A0000119B0000129E000014A5 - 000014A5000014A500CC69E058FF69E058FF14A500CC14A5000014A50000129E - 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000129D - 000013A2000013A200CC62D951FF61D850FF13A200CC13A20000129D0000119B - 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000119B - 0000129C0000129E00CC5AD149FF59D048FF129E00CC129C0000119B0000119B - 0000119B0000119A0000FFFFFF00FFFFFF00119A0099119A00CC119A00CC119A - 00CC119A00CC119A00CC54CB43FF52C941FF119A00CC119A00CC119A00CC119A - 00CC119A00CC119A0099FFFFFF00FFFFFF00109600CC5ED54DFF55CC44FF54CB - 43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC63EFF4EC53DFF4DC43CFF4CC3 - 3BFF4EC53DFF109600CCFFFFFF00FFFFFF000F9200CC59D048FF50C73FFF50C7 - 3FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A920FF2CA51BFF2BA31AFF2DA5 - 1CFF33AB22FF0F9200CCFFFFFF00FFFFFF000E8E00990E8D00CC0E8D00CC0E8D - 00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D00CC0E8D00CC0E8D00CC0E8D - 00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8C - 00000E8B00000D8900CC29B618FF27B416FF0D8900CC0E8B00000E8C00000E8C - 00000E8C00000E8D0000FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8A - 00000C8400000C8400CC25C014FF24C013FF0C8400CC0C8400000E8A00000E8C - 00000E8C00000E8D0000FFFFFF00FFFFFF000747000000000000000000000320 - 00000A7D00000A7D00CC23CD12FF22CC11FF0A7D00CC0A7D0000032000000000 - 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000 - 0000021D0000066D00CC22D811FF22D811FF066D00CC021D0000000000000000 - 00000000000000000000FFFFFF00FFFFFF0000000000000000040000001B0000 - 003000000033024700A6025D00CC025D00CC024700A600000033000000310000 - 001F0000000600000000FFFFFF00FFFFFF0000000000000000020000000E0000 - 00180000001A0000001A0000001A0000001A0000001A0000001A000000190000 - 00100000000300000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE000065D0000064 - CF000069D400006AD548006AD5CC006AD5CC006AD5660069D4000064CF000065 - D0000063CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE000065D01A0064 - CF000066D1000067D2CC38C1F8F938C7F8FD0067D2C90066D1000064CF000065 - D01A0063CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE660063CECC0063 - CEB30062CD4D0063CECC3AC8F8FF2FC0F1FD0063CEB30062CD4D0063CEB30063 - CECC0063CE66FFFFFF00FFFFFF00FFFFFF00FFFFFF00005FCACC39C2F5FF34B8 - F2F9117AD7D9005FCACC38C1F4FF2AAFE9F9005FCAB71079D6D932B6F0F936BF - F3FF005FCACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00005AC5CC27A4E3F92CAD - E7FF31B3ECFF1075D3D935B9F0FF249EE1F50F74D2D930B2EBFF2CADE7FF27A4 - E3F9005AC5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF000056C13E0055C0B31074 - CDE01A87D5EC2DAAE6FF2DA9E6FF28A3E1FF2DA9E6FF1A87D5EC1074CDE00055 - C0B30056C13EFFFFFF00FFFFFF00FFFFFF00FFFFFF000050BA000050BB000050 - BB480050BBCC1C8BD6F3249CDEFF249CDEFF1C8BD6F30050BBCC0050BB480050 - BB000050BA00FFFFFF00FFFFFF00FFFFFF00FFFFFF000049B33E004BB5B31474 - CCE01B87D6EC2099DDFF2099DDFF239EE1FF2099DDFF1884D3EC1070C9E0004B - B5B30049B33EFFFFFF00FFFFFF00FFFFFF00FFFFFF000045AFCC24A1E4F91C9D - E1FF1A9ADFFF075ABBD9158BD7F520A1E5FF075ABBD91A9ADFFF1B9BE0FF1C97 - DFF90045AFCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00003DA8CC139DE2FF1192 - DCF90554B6D9003DA8B71194DCF918A2E6FF003DA8CC0554B6D91192DCF9139D - E2FF003DA8CCFFFFFF00FFFFFF00FFFFFF00FFFFFF0000329D6600309BCC0030 - 9BB300339E4D00309BB30C9EE5FD0FA4E9FF00309BCC00339E4D00309BB30030 - 9BCC00329D66FFFFFF00FFFFFF00FFFFFF00FFFFFF0000184E0000154A1A0017 - 4C00000A250000248EC908A2E8FD0899E2F900248ECC000A250000174C000015 - 4A1A00184E00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000000D0000 - 00210000002700135E79002B91D1002B91D100104B6100000027000000230000 - 001000000001FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000080000 - 00160000001A0000001A0000001A0000001A0000001A0000001A000000170000 - 000A00000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000212121006565 - 65008B8B8B002502B0002502B2002502B3002602B5372602B47B2502B47C2502 - B3382502AF002402AC002302A800000000001D1D1D005C5C5C00808080008686 - 86008B8B8B002502B0002502B2002502B3382502B37CC9B8FDFFCAB9FEFF2502 - B17E2502AF392402AC002302A800525252007373730079797900808080008686 - 86008B8B8B002502B0002502B2392502B17EC6B5FCFFB6A5ECFFB8A7ECFFCAB9 - FEFF2402AD812402AC3B2302A8006C6C6C007373730079797900808080008686 - 86008B8B8B002502B0392502B07FC4B3FBFFB3A2EAFFB5A4EBFFB6A5ECFFB8A7 - ECFFCAB9FEFF2402A9862302A83D6C6C6C007373730079797900808080008686 - 86008A8A8A2F88888866C1B0F9FFB09FE9FFB2A1E9FFB3A2EAFFB5A4EBFFB6A5 - ECFF9887DCFFAA99EEFF2302A58A6C6C6C007373730079797900808080008585 - 852F83838366F8F8F8FFF5F5F5FFAE9DE8FFB09FE9FFB2A1E9FFB3A2EAFF9584 - D9FF9786DBFFA998EDFF2202A18D6C6C6C0073737300797979007F7F7F2F7D7D - 7D66F6F6F6FFF2F2F2FFF2F2F2FFF2F2F2FFAE9DE8FFB09FE9FF9281D6FF9483 - D8FFA695EAFF22029F9022029F416C6C6C00737373007878782F76767666F4F4 - F4FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFF8E7DD2FF907FD4FFA392 - E7FF21029D9221029C4221029E006C6C6C007272722F70707066F3F3F3FFECEC - ECFFECECECFFECECECFFECECECFFECECECFFCECECEFFD0D0D0FF9F8EE3FF2102 - 9B9521029A4321029C0021029E006B6B6B2F69696966F1F1F1FFE9E9E9FFE9E9 - E9FFE9E9E9FFE9E9E9FFE9E9E9FFCACACAFFCCCCCCFFDCDCDCFF363636662003 - 98452102990021029C0021029E0063636366F0F0F0FFE6E6E6FFE6E6E6FFE6E6 - E6FFE6E6E6FFE6E6E6FFC6C6C6FFC8C8C8FFD8D8D8FF272727662323232F2003 - 9700210299001902750011014F0058585866F0F0F0FFE3E3E3FFE3E3E3FFE3E3 - E3FFE3E3E3FFC2C2C2FFC4C4C4FFD4D4D4FF1A1A1A661616162F202020001803 - 71000801260000000000000000004848482F3D3D3D66F0F0F0FFE1E1E1FFE1E1 - E1FFBFBFBFFFC0C0C0FFD1D1D1FF0F0F0F660C0C0C2F0F0F0F00080808000000 - 0000000000000000000000000000101010001E1E1E2F20202066DFDFDFFFCECE - CEFFCECECEFFCECECEFF050505660202022F0202020000000000000000000000 - 00000000000000000000000000000000001100000026090909480A0A0A660505 - 05660202026601010166000000400000001E00000019000000130000000E0000 - 000000000005000000020000000000000000000000130000001A000000190000 - 00180000001600000014000000120000000F0000000D0000000A000000070000 - 0005000000030000000100000000000000000000000000000000000000002222 - 2200696969002502B0002502B2002502B3002602B5372602B47B2502B47C2502 - B3382502AF002402AC002302A80000000000000000001F1F1F00616161008686 - 86008B8B8B002502B0002502B2002502B3382502B37CC9B8FDFFCAB9FEFF2502 - B17E2502AF392402AC002302A8001C1C1C005757570079797900808080008686 - 86008B8B8B002502B0002502B2392502B17EC6B5FCFFB6A5ECFFB8A7ECFFCAB9 - FEFF2402AD812402AC3B2302A8006C6C6C007373730079797900808080008686 - 86008B8B8B002502B0392502B07FC4B3FBFFB3A2EAFFB5A4EBFFB6A5ECFFB8A7 - ECFFCAB9FEFF2402A9862302A83D6C6C6C007373730079797900808080008686 - 86008A8A8A2F88888866C1B0F9FFB09FE9FFB2A1E9FFB3A2EAFFB5A4EBFFB6A5 - ECFF9887DCFFAA99EEFF2302A58A6C6C6C007373730079797900808080008585 - 852F83838366F8F8F8FFF5F5F5FFAE9DE8FFB09FE9FFB2A1E9FFB3A2EAFF9584 - D9FF9786DBFFA998EDFF2202A18D6C6C6C0073737300797979007F7F7F2F7D7D - 7D66F6F6F6FFF2F2F2FFF2F2F2FFF2F2F2FFAE9DE8FFB09FE9FF9281D6FF9483 - D8FFA695EAFF22029F9022029F416C6C6C00737373007878782F76767666F4F4 - F4FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFF8E7DD2FF907FD4FFA392 - E7FF21029D9221029C4221029E006C6C6C007272722F70707066F3F3F3FFECEC - ECFFECECECFFECECECFFECECECFFECECECFFCECECEFFD0D0D0FF9F8EE3FF2102 - 9B9521029A4321029C0021029E006B6B6B2F69696966F1F1F1FFE9E9E9FFE9E9 - E9FFE9E9E9FFE9E9E9FFE9E9E9FFCACACAFFCCCCCCFFDCDCDCFF363636662003 - 984519029D000901A7000000A70063636366F0F0F0FFE6E6E6FFE6E6E6FFE6E6 - E6FFE6E6E6FFE6E6E6FFC6C6C6FFC8C8C8FFD8D8D8FF272727661A1A452F0801 - A5000000AA000000AA000000A70058585866F0F0F0FFE3E3E3FFE3E3E3FFE3E3 - E3FFE3E3E3FFC2C2C2FFC4C4C4FFD4D4D4FF0A0A7BC20202A1D50000A7CC0000 - A7CC0000A7CC0000A7CC0000A6994848482F3D3D3D66F0F0F0FFE1E1E1FFE1E1 - E1FFBFBFBFFFC0C0C0FFD1D1D1FF0F0F0F66010192D55E5EF7FF5E5EF7FF5E5E - F7FF5E5EF7FF5E5EF7FF000098CC101010001E1E1E2F20202066DFDFDFFFCECE - CEFFCECECEFFCECECEFF050505660202022F00006299000080CC000080CC0000 - 80CC000080CC000080CC000084990000001100000026090909480A0A0A660505 - 05660202026601010166000000400000001E00000019000000130000000E0000 - 000000000005000000020000400000000000000000130000001A000000190000 - 00180000001600000014000000120000000F0000000D0000000A000000070000 - 0005000000030000000100000000FFFFFF00E99E3F00E99E3F00E99E3F00EA9F - 4099EA9F40CCEA9F4099EA9F4000EA9F40CCEA9F4000E59A3D00E3983B00E398 - 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E69B3D00E69B3D00E69B3D00E69B - 3DCCFFE195FFE69B3DCCE4993C00E69B3D00E4993C00E3983B00E3983B00E398 - 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E3983B00E3983B00E3983B00E398 - 3B99E2973ACCE2973ACCE2973ACCE2973A99E2973A00E2973ACCE2973A00E297 - 3A00E2973A00FFFFFF00FFFFFF00FFFFFF00DD923600DD923600DD923600DD92 - 3600DD923600DD9236CCFEDC90FFDD9236CCDB903400DD923600DC913500DC91 - 3500DC913500FFFFFF00FFFFFF00FFFFFF00D68B3100D68B3100D68B3100D78C - 3299D88D32CCD88D32CCD88D32CCD88D32CCD88D32CCD78C3299D68B3100D68B - 3100D68B3100FFFFFF00FFFFFF00FFFFFF00D2872E00D2872E00D2872E00D287 - 2ECCFBD589FFD38930CEFAD488FFD2872ECCFAD286FFD2872ECCD2872E00D287 - 2E00D2872E00FFFFFF00FFFFFF00FFFFFF00B86D1A00C97E2700C97E2700CA7F - 2899D58E39D7D58E39D7D08731D2CB8029CCCB8029CCCA7F2899C97E2700C97E - 2700B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00BD721E00C57A2400C57A - 24CCF7CC80FFDA9645E3F6CA7EFFC87E29CFF6C97DFFC57A24CCC57A2400BD72 - 1E00B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00B96E1B00BB701D00BE73 - 1FCCEDB96CF8E1A153EFDB9949E8D4903FE1D4903FE1BD721F99B96E1B00B96E - 1B00B86D1A00FFFFFF00FFFFFF00FFFFFF00B76C1A99B86D1ACCB86D1ACCB86D - 1ACCF3C074FFE9AC60FAEEB266FFE4A659F5F2BD71FFB86D1ACCB86D1ACCB86D - 1ACCB76C1A99FFFFFF00FFFFFF00FFFFFF00B267165CB16615CCF7CB7FFFF2BF - 73FFF0B86CFFE9AD61FFDFA357FFD5994DFFD49B4FFFD6A054FFDDAB5FFFB166 - 15CCB267165CFFFFFF00FFFFFF00FFFFFF00B1661500AC61115CAB6010CCF2C3 - 77FFDB9E4CFFD09341FFCF9240FFCF9240FFCF9240FFDCA858FFAB6010CCAC61 - 115CB1661500FFFFFF00FFFFFF00FFFFFF00B1661500AB601000A65B0D5CA55A - 0CCCEAB44BFFE09E29FFE09E29FFE09E29FFE8AE43FFA55A0CCCA65B0D5CAB60 - 1000B1661500FFFFFF00FFFFFF00FFFFFF000000000000000000532D0600A156 - 095CA05508CCF7B92EFFF5AB0EFFF7B629FFA05508CCA156095C532D06000000 - 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 - 00196D39046E9B5005CCFFBB19FF9B5005CC6D39046E0000001A000000110000 - 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 - 00320000003363320274974C02CC633202740000003300000033000000220000 - 000800000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000013A2000014A5000014A5000014A6000015A8000015A9001F15AA - 00CC15AA004814A70000FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000013A2000014A5001014A700B077EE - 66FF14A700CC14A70048FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000013A2000614A3009E43C631E56BE2 - 5AFF70E95FFB14A300CCFFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000113A0008533B820DE61D850FF5CD5 - 4BFA1EA80CD213A1004CFFFFFF00FFFFFF0011970000129B0048129B00CC129B - 0048119700000F93000011970000129B006924AA13D857CF46FE55CD44FD21A7 - 10D6129C006313A00000FFFFFF00FFFFFF0011960048119700CC73EA62FD1197 - 00CC119600480F9300001196004C189D08D33DB62CFB37AF26FE1FA00EDA1197 - 007B11980000129B0000FFFFFF00FFFFFF000F9200CC6DE55CFA59D048FF69E1 - 58FC0F9200CC0F92006D139504CB34B423F832B221FF1F9F0FDF0F92008C1094 - 00021095000010950000FFFFFF00FFFFFF000E8E00480E8D00CC5FD94FF933BC - 22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA20FE40E8D009E0F8F00081094 - 000010950000084B0000FFFFFF00FFFFFF000E8D00000D8800480D8700CC43CA - 33F629C318FF39CC28FF28C217FF1EAA0FEA0D8700AE0D8A00100F8F0000084A - 00000000000000000000FFFFFF00FFFFFF00074700000A6500000B8300480B82 - 00CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85001B07450000000000000000 - 00000000000000000000FFFFFF00FFFFFF000000000000000000032000000657 - 0048077200CC16A60AE8087601C406570029021E000000000000000000000000 - 00000000000000000000FFFFFF00FFFFFF00000000020000000F0000001F0000 - 002D02330066025F00CC012B005500000029000000220000001A000000130000 - 000C0000000600000001FFFFFF00FFFFFF000000000100000008000000100000 - 00170000001A000000190000001700000015000000110000000D0000000A0000 - 00060000000300000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 - A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 - A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 - AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 - A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B - E8F65F5FE7FF5B5BE3FF4949D1FF4949D1FF5B5BE3FF5F5FE7FF5858E4F60F0F - B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 - D9FF4F4FD7FF4040C8FFFFFFFFFFFFFFFFFF4040C8FF4F4FD7FF5050D8FF4F4F - DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 - CAFF4242CAFF3636BEFFFFFFFFFFFFFFFFFF3636BEFF4242CAFF4242CAFF4747 - CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 - BFFF3737BFFF2A2AB2FFE8E8E8FFDADADAFF15159EFF12129CFF12129CFF1616 - A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E - B8FF1D1DABFF1212A1FFCCCCCCFFD1D1D1FF1111A0FF1111A1FF1111A1FF1111 - A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414 - ABFF1111AAFF1111A6FFD1D1D1FFDCDCDCFF1111A6FF1111AAFF1111AAFF1111 - AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 - B4FF1111B4FF1111B4FF1111A8FF1111A8FF1111B4FF1111B4FF1111B4FF1111 - B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 - BEFF1111BEFF1111B5FFE8E8E8FFEEEEEEFF1111B5FF1111BEFF1111BEFF1111 - BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 - C8FF1111C8FF1111BCFFEEEEEEFFEEEEEEFF1111BCFF1111C8FF1111C8FF0F0F - BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 - C4F61212D1FF1111D1FF1111B6FF1111B6FF1111D1FF1111D1FF0F0FC2F60303 - 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 - 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 - 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 - 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 - 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 00170000000C00000002FFFFFF00 + 4C7A070000001000000010000000A70B00000000000078DAED987B5454E516C0 + F71C7C0C84CC0C20E1F07EF8C0170A859A51E6E38A29699A4A4A1A7A9D16892D + 53B3AC14BBBE35BD46F91815144D40343550C2EB032432C40F450505A5145103 + 231FE02068B8EFB70F6786C30C965EFBE3AE75EF59EBB7BEFDEDBD7F6786D1EF + 3C3E44047C4AFA460740DB1DD09464D0739884DEBC6E1D0A265FB301C07E3380 + 635213D88C8A087CBFFC6DA4585EA35E72E4BE6623CFC7F1FA76132CF2721812 + 141BF3D443BDCDF9E23962011CB68AB049C5AF6344D108A498725433F63DCA17 + CFB149FC1C36EEF4107C333F0429A69CBCC7CCD77398396F9C1880238FBF82CD + D5C831FAEAB5C0261486E2683610C91995DB5FF48666BD80AF1EED83C38FBD84 + AFFD108CA1D92FE2B0EFFB8A3139465F15038CBEE7881F5F16A17EF2FAA676C6 + 9E3B3C45BA6E77C12EDBB4D86DBB2B06EEF446728CBEDD2AD0DBAD04664EB7DD + AED86597169BAB9163F25702D87D2E6305409B65C0FCD29CB1E33E27A498724D + 7A5636FE7E4DFCE500B60B4558FB4C47F4CD74408A2947B5E6FCD683C1745879 + 02D8CC15613E79F6E8CD344831E5A8263F8CBEF921B801B49A06CCBB488304C5 + 94333FCCFC161C174E0F4EA030181284B7B847F098729C9E1C0F4EAB667C8163 + C771E6681F413B8E9AFE4CB9FF5700934F024CC907F8FB2980C80280770B4338 + 4C4227E6A8463DBCF711BE56ECD19D0678E70CEB7DB4B6AEF78FB5F53C3E2EE6 + 1A7CED237C1D87715261525E28C52FE4D4A27FE69D7A592E55EAD159F8137359 + 9F2C033E975E55A7F9F87C31CD7B1FBD8B9DF754D4F1F83BF59C73C50169B7EB + 8232AA916A16FEB81F58C7AFCBEABA7EF30BF64CAD44F507678B9F3F701B7DE3 + 4A0DAA59678A7BA4FC8A54A31EEAB5F0C71C7D094667A6AA67E55DD62E29ACEC + 967C1DBBEDB88E9DB6958A23E5A8463DD46BE18FF817E72011C261AE2BCE55FB + 6EFA19098A2927D5C45E0B7F48EA4B30747FAAE32C76D965C9B94A4FFD4F48F8 + C4958AA3F3C2B395EAE9C72F530FF55AF883F630DFF8AB75AEB1A5A8DD70095B + 8F3B58DC76C5798367FC3531A69CCBC6CBE8BAEE521DF55AF8C149CC21F60A6A + 624AEA5ABE9156CCE7DF69BE2AA973DE7A1DA94639AA510FCD2DFC80581DF4D8 + C838A91018174AA36DDCB57AD5D71528E6A59C18F35E0BDFF9357E637A550BCF + 0EE38BBF3D80EFAAE3CAADE5F54AFD953A1E33314735EAE1BD167EC3D186E3C5 + E9080E13E640972F4E8BA887468839001F69FD291EE12B394E7FB07E9FE5D834 + E7FFC7EB5676787979C194295360C58A15D05ED8CB49E1A44207617FAF0EC2BE + 4FDA0BFB3EE5F3DEED853DE02BEC021F2149F4DCDCDC203C3C1CE6CF9F0F8B17 + 2F36F7797FEAA7C7D3EB31F7C0436C2F7C3B8FFB7D8CFEC8912361E6CC993067 + CE9CE6FC3ED47F6CFFEF98B6BD12D3132BC573F80ADF7CC6FDBEE44745453DCA + E7EEDEE8ECD40798BAF506EEFFFA57B373EC58CCFDE0E6FCE5CB97FB2F5DBA54 + 77746F1DEEDD5C8129F1154DCEB17E490926EB6FA28FB07DB9B9BF68D122FF05 + 0B16E86A6B6BD16030E0EED8F226E758B3B018D72DBE883BD6FF86DE42FC4AB9 + 1F1D1DED3F77EE5C5D4D4D0D56555599309E23E6B373F8D582224C587383BB9B + 57735E31FA1F7DF491FFECD9B37577EFDEC55BB76E59B06AEE195C1D5D80DB62 + 7E412F2136C64BD8D4DF4B88137FBF193366F84F9F3E5D575D5D8D959595169C + 3C7912F3F3F371F3AA32EE6E5CE3256C18C07D207FEAD4A9FE919191BA3B77EE + 6045458505B9B9B9C818C39292120C0A0AD2795AAD1FE425E8C1E84F9E3C5977 + FBF66DBC7EFDBA05C78E1DC39C9C1C2C2A2AC28E1D3BEA7C7C7CFC3DADD601F9 + ED840F40A3180E616161A25F5656D684ACAC2CCCCECEC6828202D46AB53A2727 + 277F4F4F4F70B67A1F948A0EA6FFF3212121FEC1C1C1E2394A4B4B4532323230 + 3333134F9F3E8D2A954A676B6BEBCF47502A9516F770B55A0DEEEEEE746EDDA5 + 4B97C4DFCA48CB962D758220F873E00F0E0DA783B5B575888D8D8D4E72740A85 + 42C7F3FD38EED27DDB41BABFD3D152BADF1B0F07D9FDDD59BA863872EC392AE9 + BA44D78DD6924BF77F45735FC6DBDB1BF8BFE713AD7F3A3C3C3C202222E289D7 + BFABAB2B8C1D3BF6FFEBFF7F68FDB71362C15A91C8FFD7243ED1FAD76A07F92B + 15FC250E9225121F6BFDDBD87C922508F185BC9F352541FF38EB5FA188299C30 + E11E9A03B09E3DCEFA0798A40798CF2C59A87FBAF5DFEFA9D73F3D0354C4BD6C + E2C6E67E7A0E93469062B8B62118CAD6F735217F86B8BE31580EC3D23548E355 + FD8B628E46B96BEE9BD5F457D6BDC064D01CA4188CC8FD9F62829A833D2C598D + 345E5CFD9C982BF9E2791372FFDC8A9E26CE7F1EA02F5A19C0CCA1BCBC4FEE9F + 59D25D0E7B50B80CCF2EEB71F27EC152A4F9FD338BC551DE27F7D3A769E1F8BC + 8E22B9D19DF485ABFA9C27F297F43C7362BE1F23286FECA17E73FFF00C77F8E1 + 635F82DD63F3F1C2DA416535B9F330679EDFA99AE37391F254A7BEE6FC03EFB9 + C0C1E96E7064A607FBED40546D69FCA85B17F543CA0B56BF5C4A1C9EE1A1A71E + C2DCFF2E4AABE73966A43A731656EC7AFBFECD141D5E4D78D35075F87D94D7A9 + 5FEEA7BCE314FEADAE2DBB77221AAB3266E2EDF428ACF826022F6D1B8B85FA50 + 2CD8381CCF6D79037FDA3911A98FFAE53ECFC1AE084DF8CEB7D5ACEAFB0FF162 + DC30CCFFF2153C15D3CF44495218529DFAA8DFDCE7354818DF267CFB385B7663 + DF50BC1CE767A27CF700A43CD5A9CFDC371EA3BAB582F831D6E15B462BD9BD03 + DDD1B0D30EEFA5F921CD294F75F3777F996F25ADD576D3FAB4786FE388960C0F + B6431A692EAD6F8DB44FD09C4FEB9A76190268AF607280306BDD3081D128ED1D + 10DED23BC65FFAEEFFB468D6F10B9571DF8CF6C6D635ECC199F6F212F86B5792 + B86FE821ED27863826C21FFA1A7DC33E21219D4BCD9DBD1FDED4211F1927E409 + FC568EDB206EC0B19ED7A65E1987D32B263EE073F698BEC2610B2C0A4CF7FC99 + F612C30B87DE774FB23DE3100FC3CCFC100EA391E6AA2FC1988FF44D76281A7B + EA6F0F47E70DACF74A549FE39F33999FB3F1EF5F2B3A6CE68D49F534D25CF4D7 + C230E758E5D9E0B4AE0F7AEDE9F0D0638BDD055EFF44B3BEE17BCAF7FFA65D0B + BF4F7B8091A561BFD39C33CD614D8B13CFEDF3A90D48F1428FCDAA4B3CF7B9FA + 2B10D46BF873EF1AD9FEDB2A08A13DBD89C5C3EB020F79E388FC7EB534EF9CA2 + ADEE9AEE82EE5B5557F93C4EF54F50725F7495439BEEDFB5590A216D96001B90 + 1B58E3F7BD33F6619DB053D6B3E89EACBAC1F3BBDB2C0735F741F9AAE5FE19ED + DFD94C01786601843CF30FFEB9992E777DF31CD02DCDEE96ED02C541DB45E0D2 + 7AD09FEEBF89FB7BADC64248EB19C09C126CCA95B315D97CEE27B837FFE02EF3 + 0569EDD2DE5C37211074C244608A2E309ACFFDA475A795EED3B6D2FE9D42E62B + A475A996DEF18DF7728ADB4AEBDE780F6F65BC7FFFB7AC5F00BEC0809ECBE87D + 6007FFEEC9511CBE6A93B325121A72544B927AB736E7875A5BEFCEE8D52BBF2C + 3CFC86E1DD77ABEB2323ABEAC78FAF3004059D2AA31AF53CC20F55ABBFCD1B3F + BEBC66E2C45F70FCF8321C32E4B408C5940B0BBB5AA352EDCDA3DEA67EBC56A9 + 4CCA1833E64ACDEBAF17E3F0E1E7B15FBF1C341E14536EC488223E96D4B46E9D + 98414EA31F17151070AC8C3EAB7FFF5C91A0A023269F62637EF0E053D8B9F3E1 + 32721AFD0D8983079F35F4EA9581463A774EC1F2F272BC70E102B66D1B87F6F6 + 9B449C9CB6F067E17D06721AFDB5D9FCB3EB03030F62F7EEE9E8E6B693F7C68B + CFDDF40CABD16CE1C49B7073DB554F4EA31F933D70605E7D870EFBD1D17127EF + 49E624882E3DB753DC906BC0D9794F3D398DFECAC4EEDD330DF6F6FB785D4E92 + 44D3BCBDFD1E03398DFEB22827A7E42B4E4E4779FD88C47EF1EFBF79F3A61837 + E68FA0B5757C19398DFE22AD95D5F20C67E7A335F6F639BC873824BA0DFE2129 + 97C39FE70FD508C2B20C721AFD059CE8D0162D96E6D9DB67F373D06F46A44934 + CC55AAAC1A2BABA579D44B4ED3EB072DFD51A182302B43A98C2DB3B3CB366834 + 05F504C594A31AF534F436B97EB490D67A17BEF407000C9C0F306E27C05BD90D + 504C39AA4137E919BF85D9F5C7F64FF60EE57B88D42B90FB6FD788967A } end object tmRepaintList: TTimer diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index d9d18b1c8..2cf9f9cee 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, Menus, ExtCtrls, VirtualTrees, synautil, httpsendthread, BaseThread, - XQueryEngineHTML, fpjson, jsonparser, jsonscanner, dateutils; + XQueryEngineHTML, GitHubRepo, fpjson, jsonparser, jsonscanner, dateutils; type @@ -22,14 +22,13 @@ interface TLuaModuleRepo = class name: String; sha: String; - size: Integer; - download_url: String; last_modified: TDateTime; last_message: String; flag: TLuaModuleRepoFlag; oflag: TLuaModuleRepoFlag; function Clone: TLuaModuleRepo; function SyncTo(const t: TLuaModuleRepo): Boolean; + constructor Create; end; { TLuaModulesRepos } @@ -39,6 +38,7 @@ TLuaModulesRepos = class function GetCount: Integer; inline; function GetRepo(const AIndex: Integer): TLuaModuleRepo; inline; public + last_commit: String; Items: TStringList; constructor Create; @@ -47,8 +47,6 @@ TLuaModulesRepos = class procedure Clear; inline; function Add(const AName: String): TLuaModuleRepo; overload; procedure Add(const I: TLuaModuleRepo); overload; - procedure LoadFromRemote(const AHTTP: THTTPSendThread); - procedure LoadFromRemoteHTML(const AHTTP: THTTPSendThread); procedure LoadFromFile(const AFileName: String); procedure SaveToFile(const AFileName: String); procedure Sort; @@ -116,8 +114,8 @@ TDownloadThread = class(TBaseThread) TCheckUpdateThread = class(TBaseThread) private + FGitHubRepo: TGitHubRepo; FOwner: TLuaModulesUpdaterForm; - FHTTP: THTTPSendThread; FReposUp: TLuaModulesRepos; FRepos: TLuaModulesRepos; FMainRepos: TLuaModulesRepos; @@ -126,6 +124,7 @@ TCheckUpdateThread = class(TBaseThread) FDownloadedCount: Integer; FProceed: Boolean; FStatusList: TStringList; + Flast_commit: String; procedure RemoveThread(const T: TDownloadThread); procedure AddThread(const T: TDownloadThread); protected @@ -137,6 +136,7 @@ TCheckUpdateThread = class(TBaseThread) procedure SyncFinal; function SyncRepos(const ARepos, AReposUp: TLuaModulesRepos): Boolean; procedure Download; + procedure DoSync; procedure Execute; override; public constructor Create(const AOwner: TLuaModulesUpdaterForm); @@ -165,7 +165,7 @@ TCheckUpdateThread = class(TBaseThread) implementation -uses frmCustomColor, FMDOptions; +uses frmCustomColor, frmDialogYesNo, FMDOptions, LazFileUtils; const // RFC 3339 - ISO 8601 @@ -193,9 +193,6 @@ function TLuaModuleRepo.Clone: TLuaModuleRepo; Result := TLuaModuleRepo.Create; Result.name := name; Result.sha := sha; - Result.sha := sha; - Result.size := size; - Result.download_url := download_url; Result.last_modified := last_modified; Result.last_message := last_message; Result.flag := flag; @@ -210,7 +207,6 @@ function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean; if sha <> t.sha then begin t.sha := sha; - t.download_url := download_url; t.last_modified := last_modified; t.last_message := last_message; t.oflag := t.flag; @@ -218,6 +214,11 @@ function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean; end; end; +constructor TLuaModuleRepo.Create; +begin + last_modified := Now; +end; + { TLuaModulesRepos } function TLuaModulesRepos.GetCount: Integer; @@ -261,106 +262,51 @@ procedure TLuaModulesRepos.Add(const I: TLuaModuleRepo); Items.AddObject(I.name, I); end; -procedure TLuaModulesRepos.LoadFromRemote(const AHTTP: THTTPSendThread); -var - j: TJSONParser; - a: TJSONArray; - i: Integer; - o: TJSONObject; - m: TLuaModuleRepo; -begin - Clear; - - a := nil; - j := TJSONParser.Create(AHTTP.Document, [joUTF8]); - try - a := TJSONArray(j.Parse); - finally - j.Free; - end; - if a = nil then - Exit; - - try - for i := 0 to a.Count - 1 do - begin - o := TJSONObject(a.Items[i]); - m := Add(o.Get('name', '')); - m.sha := o.Get('sha', ''); - m.download_url := o.Get('download_url', ''); - m.size := o.Get('size', 0); - end; - finally - a.Free; - end; -end; - -procedure TLuaModulesRepos.LoadFromRemoteHTML(const AHTTP: THTTPSendThread); -var - v: IXQValue; - i: Integer; -begin - with TXQueryEngineHTML.Create(AHTTP.Document) do - try - v := XPath('//table[starts-with(@class,"files")]//tr[@class="js-navigation-item"]'); - if v.Count = Count then - for i := 1 to v.Count do - with Repo[i - 1] do - begin - last_message := XPathString('./td[@class="message"]/span/a/@title', v.get(i)); - last_modified := JSONToDateTime( - XPathString('./td[@class="age"]/span/time-ago/@datetime', v.get(i))); - end; - finally - Free; - end; - Sort; -end; - procedure TLuaModulesRepos.LoadFromFile(const AFileName: String); var f: TFileStream; j: TJSONParser; a: TJSONArray; - o: TJSONObject; + d, o: TJSONObject; i: Integer; m: TLuaModuleRepo; begin if not FileExists(AFileName) then Exit; - a := nil; + d := nil; f := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); try j := TJSONParser.Create(f, [joUTF8]); try - a := TJSONArray(j.Parse); + d := TJSONObject(j.Parse); finally j.Free; end; finally f.Free; end; - if a = nil then - Exit; + + if d = nil then Exit; try Self.Clear; - for i := 0 to a.Count - 1 do - begin - o := TJSONObject(a.Items[i]); - m := Add(o.Get('name', '')); - m.sha := o.Get('sha', ''); - m.download_url := o.Get('download_url', ''); - m.size := o.Get('size', 0); - m.last_modified := JSONToDateTime(o.Get('last_modified', '')); - m.last_message := o.Get('last_message', ''); - m.flag := TLuaModuleRepoFlag(o.Get('flag', 0)); - if (m.flag <> fFailedDownload) and - (not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name)) then - m.flag := fFailedDownload; - end; + last_commit := d.Get('last_commit', ''); + a:=d.Get('files', TJSONArray(nil)); + if Assigned(a) then + for i := 0 to a.Count - 1 do + begin + o := TJSONObject(a.Items[i]); + m := Add(o.Get('name', '')); + m.sha := o.Get('sha', ''); + m.last_modified := JSONToDateTime(o.Get('last_modified', '')); + m.last_message := o.Get('last_message', ''); + m.flag := TLuaModuleRepoFlag(o.Get('flag', 0)); + if (m.flag <> fFailedDownload) and + (not FileExists(LUA_REPO_FOLDER + TrimFilename(m.name))) then + m.flag := fFailedDownload; + end; finally - a.Free; + d.Free; end; Sort; end; @@ -368,38 +314,39 @@ procedure TLuaModulesRepos.LoadFromFile(const AFileName: String); procedure TLuaModulesRepos.SaveToFile(const AFileName: String); var a: TJSONArray; - o: TJSONObject; + d, o: TJSONObject; i: Integer; m: TLuaModuleRepo; f: TMemoryStream; begin - a := TJSONArray.Create; + d := TJSONObject.Create; try + d.Add('last_commit', last_commit); + a := TJSONArray.Create; for i := 0 to Items.Count - 1 do begin o := TJSONObject.Create; m := Repo[i]; o.Add('name', m.name); o.Add('sha', m.sha); - o.Add('download_url', m.download_url); - o.Add('size', m.size); o.Add('last_modified', DateTimeToJSON(m.last_modified)); o.Add('last_message', m.last_message); o.Add('flag', Integer(m.flag)); a.Add(o); end; + d.Add('files', a); if FileExists(AFileName) then DeleteFile(AFileName); f := TMemoryStream.Create; try - a.DumpJSON(f); + d.DumpJSON(f); f.SaveToFile(AFileName); finally f.Free; end; finally - a.Free; + d.Free; end; end; @@ -414,6 +361,7 @@ function TLuaModulesRepos.Clone: TLuaModulesRepos; i: Integer; begin Result := TLuaModulesRepos.Create; + Result.last_commit := last_commit; for i := 0 to Items.Count - 1 do Result.Items.AddObject(Items[i], Repo[i].Clone); end; @@ -428,17 +376,20 @@ procedure TDownloadThread.Execute; FModule.oflag := FModule.flag; FModule.flag := fDownloading; FOwner.FOwner.ListDirty; - if FHTTP.GET(FModule.download_url) then + //if FHTTP.GET(FModule.download_url) then + if FHTTP.GET(FOwner.FGitHubRepo.GetDownloadURL(FModule.name)) then begin - if ForceDirectories(LUA_WEBSITEMODULE_FOLDER) then + if ForceDirectories(LUA_REPO_FOLDER) then begin - f := LUA_WEBSITEMODULE_FOLDER + FModule.name; + f := LUA_REPO_FOLDER + TrimFilename(FModule.name); c := True; if FileExists(f) then c := DeleteFile(f); + c := ForceDirectories(ExtractFileDir(f)); if c then begin FHTTP.SaveDocumentToFile(f, False, FModule.last_modified); + //FHTTP.SaveDocumentToFile(f); if FileExists(f) then begin case FModule.oflag of @@ -520,9 +471,14 @@ procedure TCheckUpdateThread.SyncFinishChecking; procedure TCheckUpdateThread.SyncAskToProceed; begin - FProceed := MessageDlg(RS_NewUpdateFoundTitle, - Format(RS_NewUpdateFoundLostChanges, [Trim(FStatusList.Text)]), - mtWarning, mbYesNo, 0) = mrYes; + with TfrmDialogYN.Create(nil) do + try + Caption := RS_NewUpdateFoundTitle; + mMessages.Lines.Text := Format(RS_NewUpdateFoundLostChanges, [Trim(FStatusList.Text)]); + FProceed := ShowModal = mrYes; + finally + free; + end; end; procedure TCheckUpdateThread.SyncStartDownload; @@ -536,6 +492,8 @@ procedure TCheckUpdateThread.SyncFinishDownload; end; procedure TCheckUpdateThread.SyncFinal; +var + yesRestart: Boolean; begin FOwner.btCheckUpdateTerminate.Visible := False; FOwner.btCheckUpdate.Caption := RS_CheckUpdate; @@ -546,10 +504,29 @@ procedure TCheckUpdateThread.SyncFinal; FOwner.vtLuaModulesRepos.BeginUpdate; FOwner.Repos := FMainRepos; FOwner.ReinitList; - FMainRepos.SaveToFile(LUA_WEBSITEMODULE_FILE); + FMainRepos.SaveToFile(LUA_REPO_FILE); finally FOwner.vtLuaModulesRepos.EndUpdate; end; + + if not Terminated then + begin + if (FDownloadedCount <> 0) then + begin + yesRestart := OptionModulesUpdaterAutoRestart; + if not yesRestart then + with TfrmDialogYN.Create(FOwner) do + try + Caption := RS_ModulesUpdatedTitle; + mMessages.Lines.Text := Format(RS_ModulesUpdatedRestart, [Trim(FStatusList.Text)]); + yesRestart := ShowModal = mrYes; + finally + free; + end; + if yesRestart then + RestartFMD; + end; + end; end; function TCheckUpdateThread.SyncRepos(const ARepos, AReposUp: TLuaModulesRepos): Boolean; @@ -630,6 +607,7 @@ function TCheckUpdateThread.SyncRepos(const ARepos, AReposUp: TLuaModulesRepos): Inc(i); end; end; + ARepos.last_commit := AReposUp.last_commit; if inew <> 0 then ARepos.Items.Sort; Result := inew + iupdate <> 0; @@ -644,21 +622,27 @@ procedure TCheckUpdateThread.Download; Synchronize(@SyncStartDownload); FStatusList.Clear; + + // do delete first + for i:=0 to FRepos.Items.Count-1 do + begin + if FRepos[i].flag=fDelete then + begin + m:=FRepos[i]; + f := LUA_REPO_FOLDER + TrimFilename(m.name); + if FileExists(f) and DeleteFile(f) then + begin + AddStatus(Format(RS_StatusDelete, [m.name])); + m.flag := fDeleted; + end; + end; + end; + i := 0; imax := FRepos.Items.Count; while i < imax do begin m := FRepos[i]; - if m.flag = fDelete then - begin - f := LUA_WEBSITEMODULE_FOLDER + m.name; - if FileExists(f) then - DeleteFile(f); - AddStatus(Format(RS_StatusDelete, [m.name])); - m.flag := fDeleted; - Inc(i); - end - else if not (m.flag in [fNew, fUpdate, fFailedDownload]) then Inc(i) else @@ -694,101 +678,167 @@ procedure TCheckUpdateThread.Download; Synchronize(@SyncFinishDownload); end; -procedure TCheckUpdateThread.Execute; +procedure TCheckUpdateThread.DoSync; var foundupdate: Boolean; i, imax: Integer; m: TLuaModuleRepo; trepos: TLuaModulesRepos; -begin - Synchronize(@SyncStartChecking); - FReposUp := TLuaModulesRepos.Create; - if FHTTP.GET(MODULES_URL) then + tree: TJSONArray; + + procedure LoadReposUp(const ATree: TJSONArray; const APath: String); + var + treeItem: Integer; + treeObject: TJSONObject; + treeArray: TJSONArray; + aItem: TLuaModuleRepo; begin - FReposUp.LoadFromRemote(FHTTP); - if FHTTP.GET(MODULES_URL2) then + for treeItem:=0 to ATree.Count-1 do begin - FReposUp.LoadFromRemoteHTML(FHTTP); - - if (FReposUp.Count<>0) and not Terminated then + treeObject:= TJSONObject(ATree[treeItem]); + treeArray := nil; + try + treeArray := TJSONArray(treeObject.GetPath('object.entries')); + except + end; + if Assigned(treeArray) then + begin + LoadReposUp(treeArray, APath+treeObject.Get('name','')+'/'); + end + else begin - // check - FRepos := FOwner.Repos.Clone; - foundupdate := SyncRepos(FRepos, FReposUp); + aItem := FReposUp.Add(APath+treeObject.Get('name', '')); + aitem.sha := treeObject.Get('oid', ''); + end; + end; + end; - // look for missing local files and previously failed download - for i := 0 to FRepos.Items.Count - 1 do + procedure LoadReposProps; + var + ulist: TStringList; + aItem: Integer; + props: TJSONObject; + d: TJSONArray; + begin + ulist:=TStringList.Create; + try + for aItem:=0 to FRepos.Items.Count-1 do + if FRepos[aItem].flag in [fNew, fUpdate, fFailedDownload] then + ulist.AddObject(FRepos[aItem].name, FRepos[aItem]); + props:=FGitHubRepo.GetProps(ulist); + if Assigned(props) then + begin + for aItem:=0 to ulist.Count-1 do begin - m := FRepos[i]; - if m.flag = fFailedDownload then - foundupdate := True - else - if (not (m.flag in [fNew, fUpdate])) and - (not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name)) then - begin - m.flag := fFailedDownload; - foundupdate := True; - end; - case m.flag of - fNew: FStatusList.Add(Format(RS_StatusNew, [m.name])); - fUpdate: FStatusList.Add(Format(RS_StatusUpdate, [m.name])); - fDelete: FStatusList.Add(Format(RS_StatusDelete, [m.name])); - fFailedDownload: FStatusList.Add(Format(RS_StatusFailed, [m.name])); + m := TLuaModuleRepo(ulist.Objects[aItem]); + try + d:=TJSONArray(props.GetPath('p'+IntToStr(aItem)+'.nodes')); + m.last_message := TJSONObject(d[0]).Get('message',''); + m.last_modified := JSONToDateTime(TJSONObject(d[0]).Get('committedDate','')); + except end; end; + end; + finally + ulist.free; + end; + end; - Synchronize(@SyncFinishChecking); +begin + FRepos := FOwner.Repos.Clone; + Flast_commit:=FGitHubRepo.GetLastCommit; + if (Flast_commit<>'') and (Flast_commit<>FRepos.last_commit) then + begin + // only load new tree with different last_commit + tree:=FGitHubRepo.GetTree; + if Assigned(tree) then + begin + FReposUp := TLuaModulesRepos.Create; + FReposUp.last_commit := Flast_commit; + LoadReposUp(tree,''); + FReposUp.Sort; + end; + end; - if foundupdate and (not Terminated) then - begin - if OptionModulesUpdaterShowUpdateWarning then - Synchronize(@SyncAskToProceed) - else - begin - FProceed := True; - Sleep(1500); // delay to show the update status - end; - if FProceed then - Download; - end; + if FReposUp=nil then FReposUp:=FRepos.Clone; + if (FReposUp.Count<>0) and not Terminated then + begin + // check + foundupdate := SyncRepos(FRepos, FReposUp); - // cleanup - i := 0; - imax := FRepos.Items.Count; - while i < imax do - begin - m := FRepos[i]; - if m.flag = fDeleted then - begin - FRepos.Items.Delete(i); - Dec(imax); - end - else - begin - if m.flag in [fNew, fUpdate, fFailedDownload] then - m.flag := fFailedDownload - else - m.flag := fNone; - Inc(i); - end; - end; - trepos := FMainRepos; - FMainRepos := FRepos; - FRepos := trepos; + // look for missing local files and previously failed download + for i := 0 to FRepos.Items.Count - 1 do + begin + m := FRepos[i]; + if m.flag = fFailedDownload then + foundupdate := True + else + if (not (m.flag in [fNew, fUpdate])) and + (not FileExists(LUA_REPO_FOLDER + TrimFilename(m.name))) then + begin + m.flag := fFailedDownload; + if not foundupdate then foundupdate := True; + end; + case m.flag of + fNew: FStatusList.Add(Format(RS_StatusNew, [m.name])); + fUpdate: FStatusList.Add(Format(RS_StatusUpdate, [m.name])); + fDelete: FStatusList.Add(Format(RS_StatusDelete, [m.name])); + fFailedDownload: FStatusList.Add(Format(RS_StatusFailed, [m.name])); + end; + end; + + // get properties + if foundupdate and (not Terminated) then + LoadReposProps; + + Synchronize(@SyncFinishChecking); + + if foundupdate and (not Terminated) then + begin + if OptionModulesUpdaterShowUpdateWarning then + Synchronize(@SyncAskToProceed) + else + begin + FProceed := True; + Sleep(1500); // delay to show the update status + end; + if FProceed then + Download; + end; + + // cleanup + i := 0; + imax := FRepos.Items.Count; + while i < imax do + begin + m := FRepos[i]; + if m.flag = fDeleted then + begin + FRepos.Items.Delete(i); + Dec(imax); + end + else + begin + if m.flag in [fNew, fUpdate, fFailedDownload] then + m.flag := fFailedDownload + else + m.flag := fNone; + Inc(i); end; end; + trepos := FMainRepos; + FMainRepos := FRepos; + FRepos := trepos; end; +end; +procedure TCheckUpdateThread.Execute; +begin + Synchronize(@SyncStartChecking); + DoSync; if not Terminated then Sleep(1000); Synchronize(@SyncFinal); - - if not Terminated then - if (FDownloadedCount <> 0) and (OptionModulesUpdaterAutoRestart or - (MessageDlg(RS_ModulesUpdatedTitle, - Format(RS_ModulesUpdatedRestart, [Trim(FStatusList.Text)]), - mtConfirmation, mbYesNo, 0) = mrYes)) then - RestartFMD; end; constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm); @@ -796,10 +846,10 @@ constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm); inherited Create(False); InitCriticalSection(FThreadsCS); FOwner := AOwner; - FHTTP := THTTPSendThread.Create(Self); FThreads := TFPList.Create; FDownloadedCount := 0; FStatusList := TStringList.Create; + FGitHubRepo := TGitHubRepo.Create(BASE_FILE, Self); end; destructor TCheckUpdateThread.Destroy; @@ -810,7 +860,7 @@ destructor TCheckUpdateThread.Destroy; FReposUp.Free; FStatusList.Free; FThreads.Free; - FHTTP.Free; + FGitHubRepo.Free; DoneCriticalsection(FThreadsCS); inherited Destroy; end; @@ -922,15 +972,17 @@ procedure TLuaModulesUpdaterForm.vtLuaModulesReposGetImageIndex(Sender: TBaseVir procedure TLuaModulesUpdaterForm.vtLuaModulesReposGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + xNode: PLuaModuleRepo; begin - with PLuaModuleRepo(Sender.GetNodeData(Node))^ do - begin - case Column of - 0: CellText := name; - 1: CellText := DateTimeToStr(last_modified); - 2: CellText := last_message; - end; - end; + xNode := Sender.GetNodeData(Node); + if Assigned(xNode) then + with xNode^ do + case Column of + 0: CellText := name; + 1: CellText := DateTimeToStr(last_modified); + 2: CellText := last_message; + end; end; procedure TLuaModulesUpdaterForm.vtLuaModulesReposHeaderClick(Sender: TVTHeader; @@ -958,7 +1010,7 @@ procedure TLuaModulesUpdaterForm.ListDirty; procedure TLuaModulesUpdaterForm.LoadLocalRepos; begin - Repos.LoadFromFile(LUA_WEBSITEMODULE_FILE); + Repos.LoadFromFile(LUA_REPO_FILE); ReinitList(False); end; @@ -980,3 +1032,4 @@ procedure TLuaModulesUpdaterForm.SortList; end; end. + diff --git a/mangadownloader/forms/uBackupSettings.pas b/mangadownloader/forms/uBackupSettings.pas index 59cb66065..42aac28ed 100644 --- a/mangadownloader/forms/uBackupSettings.pas +++ b/mangadownloader/forms/uBackupSettings.pas @@ -68,7 +68,7 @@ procedure WriteBackupToFile(const AFileName:String); Parameters.Add(CleanPath(CONFIG_FILE)); Parameters.Add(CleanPath(ACCOUNTS_FILE)); Parameters.Add(CleanPath(MODULES_FILE)); - Parameters.Add(CleanPath(LUA_WEBSITEMODULE_FILE)); + Parameters.Add(CleanPath(LUA_REPO_FILE)); Parameters.Add(CleanPath(WORK_FILEDB)); Parameters.Add(CleanPath(DOWNLOADEDCHAPTERSDB_FILE)); Parameters.Add(CleanPath(FAVORITESDB_FILE)); diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 05e3d75bf..46cc5ff5e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -23,11 +23,8 @@ - - - - + @@ -308,7 +305,7 @@ - + @@ -430,6 +427,13 @@ + + + + + + + diff --git a/update b/update index 27d236360..252f1c6b9 100644 --- a/update +++ b/update @@ -1,3 +1,4 @@ -VERSION=1.1.4.0 -WIN32=https://github.com/fmd-project-team/FMD/releases/download/1.1.4.0/fmd_1.1.4.0_Win32.7z -WIN64=https://github.com/fmd-project-team/FMD/releases/download/1.1.4.0/fmd_1.1.4.0_Win64.7z +; automatically build with make_release_win.bat +WIN32=https://github.com/fmd-project-team/FMD/releases/download/1.2.0.0/fmd_1.2.0.0_i386-win32.7z +WIN64=https://github.com/fmd-project-team/FMD/releases/download/1.2.0.0/fmd_1.2.0.0_x86_64-win64.7z +VERSION=1.2.0.0