Jaka jest najwyższa wartość całkowita JavaScript, do której liczba może przejść bez utraty precyzji?

Czy jest to zdefiniowane przez język? Czy istnieje określone maksimum? Czy jest inaczej w różnych przeglądarkach?

Author: Peter Mortensen, 2008-11-20

21 answers

JavaScript ma dwa typy liczbowe: Number oraz BigInt.

Najczęściej używany typ liczby, Number, jest 64-bitową liczbą zmiennoprzecinkową IEEE 754.

Największą dokładną wartością całkową tego typu jest Number.MAX_SAFE_INTEGER, czyli:

  • 253-1, lub
  • +/- 9,007,199,254,740,991, lub
  • dziewięć kwadrylionów siedem bilionów sto dziewięćdziesiąt dziewięć miliardów dwieście pięćdziesiąt cztery miliony siedemset czterdzieści tysiąc dziewięćset dziewięćdziesiąt jeden

Ujmując to w perspektywie: jeden kwadrylion bajtów to petabajt (lub tysiąc terabajtów).

"bezpieczny" w tym kontekście odnosi się do możliwości dokładnego reprezentowania liczb całkowitych i poprawnego ich porównywania.

Od spec:

Zauważ, że wszystkie dodatnie i ujemne liczby całkowite, których wielkość nie większe niż 253 są reprezentowalne w typie Number (rzeczywiście, liczba całkowita 0 ma dwa reprezentacje, +0 i -0).

Aby bezpiecznie używać liczb całkowitych większych niż ta, należy użyć BigInt, który nie ma górnej granicy.

Zauważ, że operatory bitowe i operatory przesunięcia działają na 32-bitowych liczbach całkowitych, więc w takim przypadku maksymalna bezpieczna liczba całkowita wynosi 231-1, lub 2 147 483 647.

const log = console.log
var x = 9007199254740992
var y = -x
log(x == x + 1) // true !
log(y == y - 1) // also true !

// Arithmetic operators work, but bitwise/shifts only operate on int32:
log(x / 2)      // 4503599627370496
log(x >> 1)     // 0
log(x | 1)      // 1

Uwaga techniczna na temat liczby 9,007,199,254,740,992: istnieje dokładna reprezentacja IEEE-754 tej wartości, oraz możesz przypisać i odczytać tę wartość ze zmiennej, więc dla bardzo starannie wybranych aplikacji w domenie liczb całkowitych mniejszych lub równych tej wartości, możesz traktować ją jako wartość maksymalną.

W ogólnym przypadku należy traktować tę wartość IEEE-754 jako niedokładną, ponieważ jest niejednoznaczne, czy koduje wartość logiczną 9,007,199,254,740,992 czy 9,007,199,254,740,993.

 905
Author: Jimmy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-22 14:37:53

>= ES6:

Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;

From the reference :

Number.MAX_VALUE;
Number.MIN_VALUE;

console.log('MIN_VALUE', Number.MIN_VALUE);
console.log('MAX_VALUE', Number.MAX_VALUE);

console.log('MIN_SAFE_INTEGER', Number.MIN_SAFE_INTEGER); //ES6
console.log('MAX_SAFE_INTEGER', Number.MAX_SAFE_INTEGER); //ES6
 467
Author: Peter Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-26 15:04:15

Jest 253 == 9 007 199 254 740 992. Dzieje się tak dlatego, że NumberS są przechowywane jako zmiennoprzecinkowe w 52-bitowej mantissie.

Wartość min wynosi -253.

To sprawia, że niektóre zabawne rzeczy się dzieją

Math.pow(2, 53) == Math.pow(2, 53) + 1
>> true

I też może być niebezpiecznie :)

var MAX_INT = Math.pow(2, 53); // 9 007 199 254 740 992
for (var i = MAX_INT; i < MAX_INT + 2; ++i) {
    // infinite loop
}

czytaj dalej: http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html

 114
Author: Vjeux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-15 07:10:22

W JavaScript istnieje Liczba o nazwie Infinity.

Przykłady:

(Infinity>100)
=> true

// Also worth noting
Infinity - 1 == Infinity
=> true

Math.pow(2,1024) === Infinity
=> true

To może być wystarczające dla niektórych pytań dotyczących tego tematu.

 63
Author: BananaNeil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-06 22:25:27

Odpowiedź Jimmy'ego poprawnie przedstawia ciągłą liczbę całkowitą JavaScript jako -9007199254740992 na 9007199254740992 inclusive (sorry 9007199254740993, możesz myśleć, że jesteś 9007199254740993, ale mylisz się! demonstracja poniżej lub w jsfiddle).

console.log(9007199254740993);

Nie ma jednak odpowiedzi, która znalazłaby / udowadniałaby to programowo (poza tą, do której nawiązał CoolAJ86 w jego odpowiedź , która finish za 28,56 lat;), więc tutaj jest nieco bardziej efektywny sposób, aby to zrobić (dokładniej, jest bardziej wydajny o około 28,559999999968312 lat :), wraz z test fiddle:

/**
 * Checks if adding/subtracting one to/from a number yields the correct result.
 *
 * @param number The number to test
 * @return true if you can add/subtract 1, false otherwise.
 */
var canAddSubtractOneFromNumber = function(number) {
    var numMinusOne = number - 1;
    var numPlusOne = number + 1;
    
    return ((number - numMinusOne) === 1) && ((number - numPlusOne) === -1);
}

//Find the highest number
var highestNumber = 3; //Start with an integer 1 or higher

//Get a number higher than the valid integer range
while (canAddSubtractOneFromNumber(highestNumber)) {
    highestNumber *= 2;
}

//Find the lowest number you can't add/subtract 1 from
var numToSubtract = highestNumber / 4;
while (numToSubtract >= 1) {
    while (!canAddSubtractOneFromNumber(highestNumber - numToSubtract)) {
        highestNumber = highestNumber - numToSubtract;
    }
    
    numToSubtract /= 2;
}        

//And there was much rejoicing.  Yay.    
console.log('HighestNumber = ' + highestNumber);
 41
Author: Briguy37,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-14 02:37:31

To be safe

var MAX_INT = 4294967295;

Rozumowanie

Myślałem, że będę mądry i znajdę wartość, przy której x + 1 === x z bardziej pragmatycznym podejściem.

Moja maszyna może liczyć tylko 10 milionów na sekundę... więc napiszę z ostateczną odpowiedzią za 28,56 lat.

Jeśli nie możesz czekać tak długo, jestem gotów się założyć, że

  • Większość pętli nie działa przez 28,56 lat
  • 9007199254740992 === Math.pow(2, 53) + 1 jest wystarczającym dowodem
  • powinieneś trzymać się 4294967295 czyli Math.pow(2,32) - 1 aby uniknąć oczekiwanych problemów z przesunięciem bitów

x + 1 === x:

(function () {
  "use strict";

  var x = 0
    , start = new Date().valueOf()
    ;

  while (x + 1 != x) {
    if (!(x % 10000000)) {
      console.log(x);
    }

    x += 1
  }

  console.log(x, new Date().valueOf() - start);
}());
 32
Author: coolaj86,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-25 02:57:21

Krótka odpowiedź brzmi: "to zależy."

Jeśli używasz operatorów bitowych w dowolnym miejscu (lub jeśli odnosisz się do długości tablicy), zakresy są następujące:

Unsigned: 0…(-1>>>0)

Signed: (-(-1>>>1)-1)…(-1>>>1)

(tak się składa, że operatory bitowe i maksymalna długość tablicy są ograniczone do 32-bitowych liczb całkowitych.)

Jeśli nie używasz operatorów bitowych lub nie pracujesz z długościami tablic:

Signed: (-Math.pow(2,53))…(+Math.pow(2,53))

Ograniczenia te są narzucane przez wewnętrzna reprezentacja typu" Number", która zasadniczo odpowiada podwójnej precyzji reprezentacji zmiennoprzecinkowej IEEE 754. (Zauważ, że w przeciwieństwie do typowych podpisanych liczb całkowitych, wielkość granicy ujemnej jest taka sama jak wielkość granicy dodatniej, ze względu na cechy reprezentacji wewnętrznej, która w rzeczywistości zawiera ujemne 0!)

 30
Author: danorton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-17 07:13:26

ECMAScript 6:

Number.MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
Number.MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;
 29
Author: WaiKit Kung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-31 05:52:35

Wiele wcześniejszych odpowiedzi pokazało, że 9007199254740992 === 9007199254740992 + 1 === true aby zweryfikować, że 9,007,199,254,740,991 jest maksymalną i bezpieczną liczbą całkowitą.

Ale co jeśli będziemy dalej robić:

input: 9007199254740992 + 1   output: 9007199254740992      expected: 9007199254740993
input: 9007199254740992 + 2   output: 9007199254740994      expected: 9007199254740994
input: 9007199254740992 + 3   output: 9007199254740996      expected: 9007199254740995
input: 9007199254740992 + 4   output: 9007199254740996      expected: 9007199254740996

Możemy się dowiedzieć, że wśród liczb większych niż 9,007,199,254,740,992, tylko liczby parzyste są reprezentowalne.

To wstęp do wyjaśnienia, jak działa 64-bitowy format podwójnej precyzji. Zobaczmy, jak 9,007,199,254,740,992 jest reprezentowany przy użyciu tego formatu binarnego.

Po pierwsze, oto 4,503,599,627,370,496:

  1 . 0000 ----- 0000  *  2^52             =>  1 0000 ----- 0000.
      | - 52 bits - |     |exponent part|        | - 52 bits - |.

Po lewej stronie strzałki mamy wartość bitową 1 , sąsiadujący punkt radix i część ułamkowa składająca się z 52 bitów . Liczba ta pomnożona przez 2^52, która przesuwa punkt radix o 52 kroki w prawo. Punkt radix kończy się na końcu i otrzymujemy 4503599627370496 w systemie binarnym.

Kontynuujmy zwiększanie części ułamkowej o 1, aż wszystkie bity zostaną ustawione na 1, co jest równe 9,007,199,254,740,991.

  1 . 0000 ----- 0000  *  2^52  =>  1 0000 ----- 0000. (like above)

      (+1)

  1 . 0000 ----- 0001  *  2^52  =>  1 0000 ----- 0001.

      (+1)

  1 . 0000 ----- 0010  *  2^52  =>  1 0000 ----- 0010.

      .
      .
      .

  1 . 1111 ----- 1111  *  2^52  =>  1 1111 ----- 1111.

Ponieważ 64-bitowy format podwójnej precyzji ściśle przydziela 52 bity dla części ułamkowej, nie ma więcej bitów, które mogłyby przenosić kolejne 1, więc możemy ustawić wszystkie bity z powrotem na 0 i manipulować częścią wykładniczą (która technicznie może iść tak wysoko, jak 2^1023):

  ┏━━▶ This bit is implicit and persistent.
  ┃
  1 . 1111 ----- 1111  *  2^52      =>  1 1111 ----- 1111.

      (+1) (radix point won't have anywhere to go)

  1 . 0000 ----- 0000  *  2^52 * 2  =>  1 0000 ----- 0000. * 2

  =>

  1 . 0000 ----- 0000  *  2^53 (exponent has increased)

Teraz mamy osiągnęliśmy nasz limit 9,007,199,254,740,992. Ponieważ wykładnik wzrósł do 2 do potęgi 53, a nasza część ułamkowa to tylko 52 bitów długości, format może obsługiwać tylko przyrosty 2: dla każdego przyrostu o 1 Na części ułamkowej otrzymana liczba dziesiętna jest większa o 2.

                          Consume 2^52 to move radix point to
                          the end again, you end up with:

  1 . 0000 ----- 0000  *  2^53  =>  1 0000 ----- 0000.  *  2  <--- we're left with a multiplication of 2 here
      | - 52 bits - |                 | - 52 bits - |.

Dlatego 64-bitowy format podwójnej precyzji Nie może zawierać liczb nieparzystych, gdy liczba jest większa niż 9,007,199,254,740,992 i dlaczego ludzie lubią zwracać uwagę, że 9007199254740992 === 9007199254740992 + 1 === true:

Po tym wzorze, gdy liczba jest większa niż 9,007,199,254,740,992 * 2 = 18,014,398,509,481,984 tylko 4 razy ułamek może być utrzymany:

input: 18014398509481984 + 1   output: 18014398509481984    expected: 18014398509481985
input: 18014398509481984 + 2   output: 18014398509481984    expected: 18014398509481986
input: 18014398509481984 + 3   output: 18014398509481984    expected: 18014398509481987
input: 18014398509481984 + 4   output: 18014398509481988    expected: 18014398509481988

A może liczby 2,251,799,813,685,248 przez 4,503,599,627,370,495?

Widzieliśmy, że możemy technicznie wyjść poza to, co lubimy traktować jako największa możliwa liczba (jest to raczej największa bezpieczna liczba; nazywa się to MAX_SAFE_NUMBER nie bez powodu), ale wtedy ograniczamy się do przyrostów o 2, Później 4, potem 8, itd.

Poniżej tych liczb są jednak inne ograniczenia. Ponownie, zgodnie z tym samym wzorem.

 1 . 0000 ----- 0001  *  2^51  =>  1 0000 ----- 000 . 1
     | - 52 bits - |                 | - 52 bits    - |

Wartość 0.1 w binarnym jest dokładnie 2^-1 (=1/2) (=0.5). Więc gdy liczba znajduje się w wyżej wymienionym zakresie, najmniej znaczący bit reprezentuje 1/2:

input: 4503599627370495.5      output: 4503599627370495.5
input: 4503599627370495.7      output: 4503599627370495.5
[[17]}większa precyzja to niemożliwe.

Mniej niż 2,251,799,813,685,248 (2^51):

input: 2251799813685246.3      output: 2251799813685246.25
input: 2251799813685246.5      output: 2251799813685246.5
input: 2251799813685246.75     output: 2251799813685246.75

// Please note that if you try this yourself and, say, log these numbers to the console,
// they will get rounded. JavaScript rounds if the number of digits exceed 17. The value
// is internally held correctly:

input: 2251799813685246.25.toString(2)
output: "111111111111111111111111111111111111111111111111110.01"
input: 2251799813685246.75.toString(2)
output: "111111111111111111111111111111111111111111111111110.11"
input: 2251799813685246.78.toString(2)
output: "111111111111111111111111111111111111111111111111110.11"

Część wykładnicza mA 11 bitów przydzielonych jej przez format.
Z Wikipedii (po więcej szczegółów wejdź tam):

IEEE 754 Double Floating Point Format.svg

Wzór

Więc aby część wykładnicza była 2^52, dokładnie musimy ustawić e = 1075.

 26
Author: Carr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-20 16:22:50

Inni mogli już podać ogólną odpowiedź, ale pomyślałem, że dobrym pomysłem będzie podanie szybkiego sposobu jej określenia:

for (var x = 2; x + 1 !== x; x *= 2);
console.log(x);
Co daje mi 9007199254740992 w ciągu mniej niż milisekundy w Chrome 30.

Sprawdzi moc 2, aby znaleźć, która z nich, po dodaniu 1, równa się jemu.

 13
Author: Philippe97,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-19 23:14:06

Cokolwiek chcesz użyć do operacji bitowych musi być między 0x800000000 (-2147483648 lub -2^31) i 0x7fffffff (2147483647 lub 2^31 - 1).

Konsola powie Ci, że 0x80000000 równa się + 2147483648, ale 0x80000000 & 0x80000000 równa się -2147483648.

 9
Author: Scato,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-06 22:25:53

Try:

maxInt = -1 >>> 1

W Firefoksie 3.6 jest 2^31 - 1.

 7
Author: Martin Naatz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-06 22:24:29

W momencie zapisu JavaScript otrzymuje nowy typ danych: BigInt. Jest to propozycja TC39 na etapie 4, która ma zostać uwzględniona w EcmaScript 2020. BigInt jest dostępny w Chrome 67+, FireFox 68+, Opera 54 i Node 10.4.0. Trwa w Safari, i in... Wprowadza literały numeryczne posiadające przyrostek " n " i pozwala na dowolną precyzję:

var a = 123456789012345678901012345678901n;

Precyzja nadal zostanie oczywiście utracona, gdy taka liczba zostanie (może nieumyślnie) zmuszona do danych liczbowych Typ.

I, oczywiście, zawsze będą ograniczenia precyzji ze względu na skończoną pamięć i koszt w kategoriach czasu w celu przydzielenia niezbędnej pamięci i do wykonywania arytmetyki na tak dużych liczbach.

Na przykład, generowanie liczby o stu tysiącach cyfr dziesiętnych, będzie wymagało zauważalnego opóźnienia przed zakończeniem:

console.log(BigInt("1".padEnd(100000,"0")) + 1n)

...ale to działa.

 6
Author: trincot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-21 10:36:08

Zrobiłem prosty test ze wzorem, X - (X+1)=-1, a największa wartość X mogę dostać się do pracy na Safari, Opera i Firefox (testowane na OS X) jest 9e15. Oto kod, którego użyłem do testowania:

javascript: alert(9e15-(9e15+1));
 4
Author: Raynet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-06 22:23:59

Piszę to tak:

var max_int = 0x20000000000000;
var min_int = -0x20000000000000;
(max_int + 1) === 0x20000000000000;  //true
(max_int - 1) < 0x20000000000000;    //true

To samo dla int32

var max_int32 =  0x80000000;
var min_int32 = -0x80000000;
 3
Author: jerome,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-25 14:29:12

Przejdźmy do źródeł

Opis

Stała MAX_SAFE_INTEGER ma wartość 9007199254740991 (9,007,199,254,740,991 lub ~9 kwadrylionów). Rozumowanie tej liczby jest takie, że JavaScript używa podwójnej precyzji liczb zmiennoprzecinkowych , jak określono w IEEE 754 i może bezpiecznie reprezentować tylko liczby między -(2^53 - 1) i 2^53 - 1.

Bezpieczny w tym kontekście odnosi się do możliwości dokładnego reprezentowania liczb całkowitych i poprawnego ich porównywania. Na przykład Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 będzie oceniać na true, co jest matematycznie niepoprawne. Patrz Liczba.isSafeInteger () aby uzyskać więcej informacji.

Ponieważ MAX_SAFE_INTEGER jest statyczną właściwością Number , zawsze używasz jej jako Number.MAX_SAFE_INTEGER, a nie jako właściwości obiektu Number, który utworzyłeś.

Zgodność przeglądarki

Tutaj wpisz opis obrazka

 3
Author: simhumileco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

W Google Chrome wbudowany javascript, można przejść do około 2^1024 zanim liczba nazywa się nieskończoność.

 0
Author: Tommy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-10 01:05:22
 0
Author: Marwen Trabelsi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-19 21:47:10

Scato wrotes:

Wszystko, czego chcesz użyć do operacji bitowych, musi być pomiędzy 0x80000000 (-2147483648 lub -2^31) i 0x7fffffff (2147483647 lub 2^31 - 1).

Konsola powie Ci, że 0x80000000 równa się + 2147483648, ale 0x80000000 & 0x80000000 równa się -2147483648

Hex-Decimals są niepodpisanymi dodatnimi wartościami, więc 0x80000000 = 2147483648-to matematycznie poprawne. Jeśli chcesz, aby była to wartość podpisana, musisz prawy shift: 0x80000000 > > 0 = -2147483648. Możesz zamiast tego napisać 1

 -1
Author: SammieFox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-24 18:34:55

Firefox 3 chyba nie ma problemu z wielkimi liczbami.

1E+200 * 1E+100 obliczy grzywnę do 1E+300.

Safari też nie ma z tym problemu. (Dla przypomnienia, jest to na komputerze Mac, jeśli ktoś inny zdecyduje się to przetestować.)

O ile nie straciłem mózgu o tej porze dnia, to jest o wiele większe niż 64-bitowa liczba całkowita.

 -7
Author: jishi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-06 22:23:03

Węzeł.wydaje się, że js i Google Chrome używają 1024-bitowych wartości zmiennoprzecinkowych, więc: {]}

Number.MAX_VALUE = 1.7976931348623157e+308
 -7
Author: TinyTimZamboni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-06 22:26:22