diff --git a/Bin/Light/Tera-light.zip b/Bin/Light/Tera-light.zip index e3dbca4..62f3054 100644 Binary files a/Bin/Light/Tera-light.zip and b/Bin/Light/Tera-light.zip differ diff --git a/Bin/Light/tera_light_setup.exe b/Bin/Light/tera_light_setup.exe index a1a4270..9ae4dc8 100644 Binary files a/Bin/Light/tera_light_setup.exe and b/Bin/Light/tera_light_setup.exe differ diff --git a/Doc/Eng/API.md b/Doc/Eng/API.md index 9bdc919..5a76d0b 100644 --- a/Doc/Eng/API.md +++ b/Doc/Eng/API.md @@ -2,6 +2,31 @@ This API is available if the node is running public http-access. Set the constant HTTP_HOSTING_PORT. +DappStaticCall - call static method +Example (GET) +```js +http://dappsgate.com:88/api/v1/DappStaticCall?MethodName=Test&Account=540 +``` + +Example (POST) +```js +http://dappsgate.com:88/api/v1/DappStaticCall +{ + "MethodName": "Test", + "Account":540 + +}``` + +return value: +```js +{"result":1,"RetValue":"Test-ok"} +``` + +see smart code of this example: +http://dappsgate.com:88/smart/200 + + + #### Getting the current status of the blockchain http://194.1.237.94/api/v1/GetCurrentInfo diff --git a/Doc/Eng/API2.md b/Doc/Eng/API2.md index 10dc701..5ba4d2f 100644 --- a/Doc/Eng/API2.md +++ b/Doc/Eng/API2.md @@ -1,5 +1,5 @@ # API v2 (for exchanges) -Works with update version 0.901 +Works with update version 0.991 The API is designed to make it easier to write third-party applications. Server-side cryptography and POW operations are performed. Therefore, it is not recommended for public access, because it is not protected from DDOS attacks. Use it if applications such as the exchange server are on the same private network. @@ -12,6 +12,10 @@ This API is available if server is running http and hosting included constant US Although the API is designed for use in POST requests, it can be used for GET requests in a limited mode. + +Warning: the Tera blockchain has a high rate of block confirmation (starting from 4 seconds), but since it uses PoW, it is possible to get into local orphan chains. Therefore, for a reliable transfer of value, we recommend that exchanges wait for additional time, such as 100 seconds, to interpret the finality of the transaction. + + Call format: ```js {{Server}}/api/v2/{{MethodName}} @@ -231,6 +235,7 @@ return: #### Parameters: * AccountID - account (account) number) * Count - maximum number of rows returned - history depth (default 100) +* Confirm - min confirm for return tx (default 8) option to set parameters for organizing page navigation: * NextPos - history line ID number (this value is taken from the last line of the previous result) diff --git a/Doc/Rus/API.md b/Doc/Rus/API.md index b4d913d..e6b562d 100644 --- a/Doc/Rus/API.md +++ b/Doc/Rus/API.md @@ -2,6 +2,32 @@ Данный API доступен если на ноде запущен публичный http-доступ. Т.е. задана константа HTTP_HOSTING_PORT +DappStaticCall - статический вызов метода смарт-контракта +Example (GET) +```js +http://dappsgate.com:88/api/v1/DappStaticCall?MethodName=Test&Account=540 +``` + +Example (POST) +```js +http://dappsgate.com:88/api/v1/DappStaticCall +{ + "MethodName": "Test", + "Account":540 + +}``` + +return value: +```js +{"result":1,"RetValue":"Test-ok"} +``` + + +see smart code of this example: +http://dappsgate.com:88/smart/200 + + + #### Получение текущего статуса блокчейна http://194.1.237.94/GetCurrentInfo?Diagram=0 diff --git a/Doc/Rus/API2.md b/Doc/Rus/API2.md index 4dbe0e0..f430653 100644 --- a/Doc/Rus/API2.md +++ b/Doc/Rus/API2.md @@ -1,5 +1,5 @@ # API v2 (для бирж и обменников) -Работает с версии обновления 0.901 +Работает с версии обновления 0.991 API предназначено для облегчения написания сторонних приложений. На стороне сервера выполняется криптография и операции POW. Поэтому оно не рекомендуется для публичного доступа, т.к. нет защиты от DDOS атак. Используйте его, если приложения такие как сервер биржи находятся в одной приватной сети. @@ -12,6 +12,10 @@ API предназначено для облегчения написания с Несмотря на то что API разработано для использования в POST запросах, в ограниченном режиме его можно использовать для GET запросов. + +Предупреждение: блокчейн Тера имеет высокую скорость подтверждения блока (начиная от 4 сек), но т.к. он использует PoW, то возможно попадание в локальные орфан цепочки. Поэтому для надежной передачи ценности мы рекомендуем биржам выжидать дополнительное время, например 100 секунд, для интерпретации финальности транзакции. + + Формат вызова ```js {{Server}}/api/v2/{{MethodName}} @@ -239,6 +243,7 @@ return: #### Параметры: * AccountID - номер счета (аккаунта) * Count - максимальное число возвращаемых строк - глубина истории (по умолчанию 100) +* Confirm - min число подтверждений требуемых, чтобы транзакция попала в результат выдачи (по умолчанию 8) вариант задания параметров для организации постраничной навигации: * NextPos - номер ид строки истории (это значение берется из последней строки предыдущего результата) diff --git a/Source/HTML/CSS/style.css b/Source/HTML/CSS/style.css index db39d33..649e8ae 100644 --- a/Source/HTML/CSS/style.css +++ b/Source/HTML/CSS/style.css @@ -20,7 +20,6 @@ body body.styleBrown { - --colorText:#FFF; --color0:#503F13; --color1:#86754A; --color2:#F5E5BB; diff --git a/Source/HTML/JS/client.js b/Source/HTML/JS/client.js index 66a2d43..1db5032 100644 --- a/Source/HTML/JS/client.js +++ b/Source/HTML/JS/client.js @@ -940,16 +940,21 @@ function RetChangeSmart(Item) return '
' + Name + '' + State + '
'; }; -function RetHistoryAccount(Item) +function RetHistoryAccount(Item,Name) { - if(Item.Num < 16) - return "" + Item.Num; - return "" + Item.Num + ""; + var Num; + if(Name) + Num = Item[Name]; + else + Num = Item.Num; + if(Num < 16) + return "" + Num; + return "" + Num + ""; }; function RetBaseAccount(Item) { - var Str = "" + Item.Account; + var Str = RetHistoryAccount(Item, "Account"); if(Item.AccountLength > 1) Str += "-" + (Item.Account + Item.AccountLength - 1); return Str; @@ -972,7 +977,7 @@ function formatDate(now) "0") + ":" + String(minute).padStart(2, "0") + ":" + String(second).padStart(2, "0"); }; -function DateFromBlock(BlockNum,bAddEnter) +function DateFromBlock(BlockNum) { var Str; if(window.FIRST_TIME_BLOCK) diff --git a/Source/HTML/JS/diagram.js b/Source/HTML/JS/diagram.js index 8aa0b25..ba05bde 100644 --- a/Source/HTML/JS/diagram.js +++ b/Source/HTML/JS/diagram.js @@ -12,6 +12,14 @@ var DiagramMap = {}; var DiagramMapId = {}; var LMouseOn = false; +function Rigth(Str,Count) +{ + if(Str.length < Count) + return Str; + else + return Str.substr(Str.length - Count); +}; + function SetHTMLDiagramItem(Item,width) { Item.mouseX = width - 50; @@ -87,11 +95,15 @@ function DrawDiagram(Item) var arr = Item.arr; if(!arr) arr = Item.ArrList; + var arrX = Item.arrX; var GreenValue = Item.value; var StepTime = Item.steptime; var StartNumber = Item.startnumber; var StartServer = Item.starttime; var mouseX = Item.mouseX; + var KPrecision = Item.KPrecision; + if(!KPrecision) + KPrecision = 1; if(!arr) return ; var obj = document.getElementById(Item.id); @@ -166,6 +178,7 @@ function DrawDiagram(Item) function DrawLines(arr,mode,color) { + var WasMove0 = 0; ctx.beginPath(); ctx.moveTo(Left, obj.height - Button); ctx.strokeStyle = color; @@ -198,7 +211,15 @@ function DrawLines(arr,mode,color) var x = StartX + ctx.lineWidth / 2 + (i) * KX; if(bLine) { - ctx.lineTo(x, StartY - VX2); + if(!WasMove0) + { + WasMove0 = 1; + ctx.moveTo(x, StartY - VX2); + } + else + { + ctx.lineTo(x, StartY - VX2); + } } else { @@ -255,8 +276,8 @@ function DrawLines(arr,mode,color) if(mouseValue !== undefined) { ctx.fillStyle = mouseColor; - var Str = "" + Math.floor(mouseValue + 0.5); - ctx.fillText(Str, mouseX - 3, Top - 2); + var Val = Math.floor(KPrecision * mouseValue + 0.5) / KPrecision; + ctx.fillText("" + Val, mouseX - 3, Top - 2); } } ctx.fillStyle = "#000"; @@ -285,28 +306,32 @@ function DrawLines(arr,mode,color) var KDelitel = 1; var Step = arr.length / CountNameX; var StartTime, bNumber; - if(StartNumber !== undefined) + if(arrX) { - bNumber = 1; - StartTime = StartNumber; } else - if(StartServer) + if(StartNumber !== undefined) { bNumber = 1; - StartTime = Math.floor(((Date.now() - StartServer) - StepTime * arr.length * 1000) / 1000); - if(StartTime < 0) - StartTime = 0; - var KDelitel = Math.floor(Step / 10) * 10; - if(KDelitel == 0) - KDelitel = 1; + StartTime = StartNumber; } else - { - bNumber = 0; - StartTime = Date.now() - StepTime * arr.length * 1000; - StartX = StartX - 16; - } + if(StartServer) + { + bNumber = 1; + StartTime = Math.floor(((Date.now() - StartServer) - StepTime * arr.length * 1000) / 1000); + if(StartTime < 0) + StartTime = 0; + var KDelitel = Math.floor(Step / 10) * 10; + if(KDelitel == 0) + KDelitel = 1; + } + else + { + bNumber = 0; + StartTime = Date.now() - StepTime * arr.length * 1000; + StartX = StartX - 16; + } for(i = 0; i <= CountNameX; i++) { var Val; @@ -321,18 +346,26 @@ function DrawLines(arr,mode,color) else Val = i * Step * StepTime; var Str; - if(bNumber) + if(arrX) { - Val = Math.floor((StartTime + Val) / KDelitel) * KDelitel; - Str = Val; + Val = Math.floor(Val); + Str = arrX[Val]; + if(Str === undefined) + Str = ""; } else - { - var Time = new Date(StartTime + Val * 1000); - Str = "" + Time.getHours(); - Str += ":" + Rigth("0" + Time.getMinutes(), 2); - Str += ":" + Rigth("0" + Time.getSeconds(), 2); - } + if(bNumber) + { + Val = Math.floor((StartTime + Val) / KDelitel) * KDelitel; + Str = Val; + } + else + { + var Time = new Date(StartTime + Val * 1000); + Str = "" + Time.getHours(); + Str += ":" + Rigth("0" + Time.getMinutes(), 2); + Str += ":" + Rigth("0" + Time.getSeconds(), 2); + } ctx.fillText(Str, StartX + i * KX3, StartY + 10); } }; diff --git a/Source/HTML/JS/wallet-lib.js b/Source/HTML/JS/wallet-lib.js index bb55d6c..1f209a3 100644 --- a/Source/HTML/JS/wallet-lib.js +++ b/Source/HTML/JS/wallet-lib.js @@ -304,8 +304,10 @@ function SendMoneyBefore() var StrTo = " to " + GetAccountText(Item, ToID); $("idWhiteOnSend").checked = 0; $("idOnSendText").innerHTML = "" + SumSend + " " + $("idCoinName").innerText + StrTo; - if(SumSend >= 100000) + if($("idSumSend").value >= 100000) + { $("idOnSendText").innerHTML += "
WARNING: You are about to send a very large amount!
"; + } SetVisibleBlock("idBlockOnSend", 1); SetImg(this, 'idBlockOnSend'); } @@ -594,6 +596,19 @@ function OpenAttach() alert("DATA:\n" + JSON.stringify(Data2, "", 4)); } }; +var CURRENCY, PUBKEY, NAME, SMART; + +function SendTrCreateAccWait(Currency,PubKey,Name,Smart) +{ + CURRENCY = Currency; + PUBKEY = PubKey; + NAME = Name; + SMART = Smart; + setTimeout(function () + { + SendTrCreateAcc(CURRENCY, PUBKEY, NAME, 0, SMART, 0, 0); + }, 50); +}; function SendTrCreateAcc(Currency,PubKey,Description,Adviser,Smart,bFindAcc,bAddToPay) { @@ -625,25 +640,47 @@ function ChangeSmart(NumAccount,WasSmart) if(Result !== null && Result != WasSmart) { var Smart = parseInt(Result); - var OperationID = 0; - var Item = MapAccounts[NumAccount]; - if(Item) + if(Smart) { - OperationID = Item.Value.OperationID; + GetData("GetDappList", {StartNum:Smart, CountNum:1}, function (Data) + { + if(Data && Data.result && Data.arr.length === 1) + { + SetSmartToAccount(NumAccount, Smart); + } + else + { + SetError("Error smart number"); + } + }); + } + else + { + SetSmartToAccount(NumAccount, Smart); } - OperationID++; - var TR = {Type:140, Account:NumAccount, Smart:Smart, FromNum:NumAccount, Reserve:[], OperationID:OperationID, Sign:"", }; - var Body = []; - WriteByte(Body, TR.Type); - WriteUint(Body, TR.Account); - WriteUint32(Body, TR.Smart); - WriteArr(Body, TR.Reserve, 10); - WriteUint(Body, TR.FromNum); - WriteUint(Body, TR.OperationID); - SendTrArrayWithSign(Body, TR.Account, TR); } }; +function SetSmartToAccount(NumAccount,Smart) +{ + var OperationID = 0; + var Item = MapAccounts[NumAccount]; + if(Item) + { + OperationID = Item.Value.OperationID; + } + OperationID++; + var TR = {Type:140, Account:NumAccount, Smart:Smart, FromNum:NumAccount, Reserve:[], OperationID:OperationID, Sign:"", }; + var Body = []; + WriteByte(Body, TR.Type); + WriteUint(Body, TR.Account); + WriteUint32(Body, TR.Smart); + WriteArr(Body, TR.Reserve, 10); + WriteUint(Body, TR.FromNum); + WriteUint(Body, TR.OperationID); + SendTrArrayWithSign(Body, TR.Account, TR); +}; + function CheckLengthAccDesription(name,Length) { var Str = $(name).value.substr(0, Length + 1); diff --git a/Source/HTML/JS/wallet-web.js b/Source/HTML/JS/wallet-web.js index ce3709d..0f2e7f5 100644 --- a/Source/HTML/JS/wallet-web.js +++ b/Source/HTML/JS/wallet-web.js @@ -226,7 +226,7 @@ function FindLider() var Item = Arr[i]; if(Item.SumPower === MaxKey) { - SetStatus("Find " + Item.ip + ":" + Item.port + " with pow=" + Item.SumPower + " " + Max + " ping=" + Item.DeltaTime); + SetStatus("Find " + Item.ip + ":" + Item.port + " with pow=" + Item.SumPower + "/" + MaxKey + " ping=" + Item.DeltaTime); MainServer = Item; SaveServerMap(); break; diff --git a/Source/HTML/dapp-edit.html b/Source/HTML/dapp-edit.html index 167a981..9faf7ff 100644 --- a/Source/HTML/dapp-edit.html +++ b/Source/HTML/dapp-edit.html @@ -528,7 +528,6 @@ { var bDisabled=(CurProjectValue!=$("idProjectList").value); - var Arr=["idName","idShortName","idISIN","idCode","idHTML","idDescription","idTokenGenerate","idStartValue","idOwnerPubKey","idAccountLength","idStateFormat","idCategory1","idCategory2","idCategory3","idIcon","idBtIcon","idBtSendSmart"]; for(var i=0;i"+Url+""; + } + $("idRefHTML").innerHTML=Str; //SetSmartToDialog(Smart,1); } else @@ -610,11 +620,11 @@ function SetCurrentSmart() { CurProjectValue=undefined; - SetDialogEnabled(); var SmartValue=$("idSmartList").value; if(SmartValue) LoadSmart(SmartValue); + SetDialogEnabled(); } function FillSmart() { @@ -840,7 +850,7 @@ - UI (HTML): +
UI (HTML):
----
diff --git a/Source/HTML/dapp-frame.html b/Source/HTML/dapp-frame.html index 35dc84c..b0750bf 100644 --- a/Source/HTML/dapp-frame.html +++ b/Source/HTML/dapp-frame.html @@ -157,6 +157,8 @@ Data.WalletIsOpen=IsPrivateMode(localStorage["idPrivKey"]); Data.WalletCanSign=Data.WalletIsOpen; } + CONFIG_DATA.WalletCanSign=Data.WalletCanSign; + CONFIG_DATA.PubKey=Data.PubKey; } SendMessage(Data); @@ -397,31 +399,31 @@ } - var WasCheckInstall=0; + var idInstallApp=0; function CheckInstall() { - if(WasCheckInstall) - return; - setInterval(function () + if(!idInstallApp) + idInstallApp=setInterval(RunCheckInstall,2000); + } + function RunCheckInstall() + { + if(CONFIG_DATA && CONFIG_DATA.ArrWallet && CONFIG_DATA.ArrWallet.length===0) { - if(CONFIG_DATA && CONFIG_DATA.ArrWallet && CONFIG_DATA.ArrWallet.length===0) + var StrRef; + if(MainServer) + StrRef='Accounts'; + else { - WasCheckInstall=1; - var StrRef; - if(MainServer) - StrRef='ACCOUNTS'; + if(localStorage["BIGWALLET"]) + StrRef='Config' else - { - if(localStorage["BIGWALLET"]) - StrRef='CONFIG' - else - StrRef='ACCOUNTS'; - } - - SetStatus('
For install this application goto '+StrRef+' tab, select your account, press "Set" and enter smart number: '+SMART.Num+'
'); + StrRef='Accounts'; } - },2000); + var Str='
For install this app press: or goto '+StrRef+' tab and Set smart number '+SMART.Num+' to your account
'; + SetStatus(Str); + } + } //LIB @@ -472,8 +474,45 @@ SetStatus("
"+Str+"
"); } + + function CreateNewWebKeys() + { + var arr = new Uint8Array(32); + window.crypto.getRandomValues(arr); + var PrivKey=GetHexFromArr(sha3(arr)); + localStorage["idPrivKey"]=PrivKey; + localStorage["idPubKey"]=GetHexFromArr(SignLib.publicKeyCreate(PrivKey,1)); + CONFIG_DATA.PubKey=localStorage["idPubKey"]; + + console.log("CreateNewWebKeys: "+CONFIG_DATA.PubKey); + } + + function InstallApp() { + if(!CONFIG_DATA.WalletCanSign) + { + if(localStorage["BIGWALLET"]) + { + SetError("Pls, open wallet"); + return; + } + CreateNewWebKeys(); + } + SetStatus("Calculate Tx, wait pls ..."); + //SendTrCreateAccWait(0,SMART.Name,SMART.Num); + + //console.log("PubKey: "+CONFIG_DATA.PubKey); + + var TR=GetTrCreateAcc(0,CONFIG_DATA.PubKey,SMART.Name,0,SMART.Num); + var Body=GetBodyCreateAcc(TR); + SendTransaction(Body,TR); + + if(idInstallApp) + { + clearInterval(idInstallApp); + idInstallApp=setInterval(RunCheckInstall,30000); + } } @@ -499,6 +538,17 @@ margin: 0; background-color:white; } + .btcreate + { + height:20px; + background-color: #347867; + color: white; + cursor: pointer; + border-radius: 3px; + padding: 2px; + text-decoration: none; + border: 1px solid gray; + } diff --git a/Source/HTML/history.html b/Source/HTML/history.html index a805b61..c067992 100644 --- a/Source/HTML/history.html +++ b/Source/HTML/history.html @@ -154,7 +154,7 @@ { var Str; if(Item.Direct===Direct) - Str=RetHistoryAccount({Num:Item.CorrID}); + Str=RetHistoryAccount(Item,"CorrID"); else Str=AccountID; diff --git a/Source/HTML/wallet.html b/Source/HTML/wallet.html index 9231a85..8ab5f59 100644 --- a/Source/HTML/wallet.html +++ b/Source/HTML/wallet.html @@ -1549,12 +1549,16 @@ Description Category - Base Account - Owner + Base Account + + Owner + Token generate Block Num + + @@ -1721,8 +1725,11 @@ Num Block Date - Hash + AccHash SumHash + AccountMax + SmartCount + SmartHash @@ -1809,8 +1816,7 @@ +
+
@@ -65,4 +66,4 @@ - \ No newline at end of file + diff --git a/Source/SITE/header_index.html b/Source/SITE/header_index.html index 0194897..25a8512 100644 --- a/Source/SITE/header_index.html +++ b/Source/SITE/header_index.html @@ -18,31 +18,9 @@ - - - - - - - @@ -78,7 +56,7 @@

- +

{{Edit=./SITE/CONTENT/en-index-about-text.md}}

@@ -113,51 +113,6 @@ -

- - -
- - -
- - -
-

Latest News

-
-
-
- Rewarding authors of articles for the TERA Content Fund -

11-March-2019

- Rewarding authors of articles for the TERA Content Fund -

We are pleased to inform you that we are rewarding two authors of articles...

-
-

-
- -
-
- TERA Blockchain News -

10-March-2019

- TERA Blockchain News -

With the large amounts of data that will inevitably occur at 1000 tps, new users should be able to quickly download the blockchain to validate it and start working with it.

-
-

-
- -
-
- TERA Frequently Asked Questions Section -

07-March-2019

- TERA Frequently Asked Questions Section -

Today, the community receives many questions from various user groups, and in this regard, it was decided to create an Frequently Asked Questions section on the site.

-
-

-
-
- -
-
@@ -169,8 +124,8 @@
-
-

Technology

+
+

Specification

@@ -230,6 +185,25 @@
+ +
+ + +
+ + +
+ + +
+ {{Edit=./SITE/CONTENT/en-index-lastnews.md}} +
+
+ +
+
+ +
@@ -239,14 +213,9 @@
- -
-

Updates

-
- {{Edit=./SITE/CONTENT/en-index-changelog.md5}} -

Full Changelog

+ {{Edit=./SITE/CONTENT/en-index-changelog.md}}
@@ -350,20 +319,23 @@
- Q1 2019 + 2019
  • Android/iOS wallets
  • +
  • Create and promote TERA Dapps
- - + + + +
@@ -393,13 +365,9 @@

FOR DEVELOPERS

- 1. TERA Source Code.
- 2. TERA DApp PAPER (ENG).
- 3. TERA DApp PAPER (RUS).
- 4. TERA DApp FAQ.
- 5. TERA API.
- е. TERA API-2 (for Exchanges).
- + {{Edit=./SITE/CONTENT/en-index-link-1.md}} + +
@@ -407,12 +375,8 @@

FOR INVESTORS

- 1. TERA on QBTC Exchange.
- 2. TERA on Bitalong Exchange.
- 3. TERA on Bitmesh Exchange.
- 4. TERA on CHAOEX Exchange.
- 5. TERA on CITEX Exchange.
- 6. TERA Roadmap. + {{Edit=./SITE/CONTENT/en-index-link-2.md}} +
@@ -421,9 +385,9 @@

FOR MINERS

- 1. TERA Mining Documentation.
- 2. TERA HAASH. - + {{Edit=./SITE/CONTENT/en-index-link-3.md}} + +
@@ -431,15 +395,9 @@

TERA INFORMATION

- 1. TERA Website.
- 2. TERA EXPLORER.
- 3. TERA WALLET.
- 4. TERA NETWORK MAP.
- 5. TERA WHITE PAPER (EN).
- 6. TERA WHITE PAPER (RU).
- 7. TERA WHITE PAPER (DE).
- 8. TERA WHITE PAPER (CN).
-
+ {{Edit=./SITE/CONTENT/en-index-link-4.md}} + +
@@ -447,12 +405,8 @@

TERA COMMUNITY

- 1. TERA on BitcoinTalk.
- 2. TERA on Twitter.
- 3. TERA on Reddit.
- 4. TERA on Discord.
- 5. TERA Telegram Chanel.
- 6. TERA on QQ. + {{Edit=./SITE/CONTENT/en-index-link-5.md}} +
@@ -461,7 +415,8 @@

OTHER

- 1. FMessenger. + {{Edit=./SITE/CONTENT/en-index-link-6.md}} + diff --git a/Source/SITE/links.html b/Source/SITE/links.html index 81786ea..a3c2095 100644 --- a/Source/SITE/links.html +++ b/Source/SITE/links.html @@ -82,7 +82,7 @@