1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674: 675: 676: 677: 678: 679: 680: 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696: 697: 698: 699: 700: 701: 702: 703: 704: 705: 706: 707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782: 783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828: 829: 830: 831: 832: 833: 834: 835: 836: 837: 838: 839: 840: 841: 842: 843: 844: 845: 846: 847: 848: 849: 850: 851: 852: 853: 854: 855: 856: 857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875: 876: 877: 878: 879: 880: 881: 882: 883: 884: 885: 886: 887: 888: 889: 890: 891: 892: 893: 894: 895: 896: 897: 898: 899: 900: 901: 902: 903: 904: 905: 906: 907: 908: 909: 910: 911: 912: 913: 914: 915: 916: 917: 918: 919: 920: 921: 922: 923: 924: 925: 926: 927: 928: 929: 930: 931: 932: 933: 934: 935: 936: 937: 938: 939: 940: 941: 942: 943: 944: 945: 946: 947: 948: 949: 950: 951: 952: 953: 954: 955: 956: 957: 958: 959: 960: 961: 962: 963: 964: 965: 966: 967: 968: 969: 970: 971: 972: 973: 974: 975: 976: 977: 978: 979: 980: 981: 982: 983: 984: 985: 986: 987: 988: 989: 990: 991: 992: 993: 994: 995: 996: 997: 998: 999: 1000: 1001: 1002: 1003: 1004: 1005: 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025: 1026: 1027: 1028: 1029: 1030: 1031: 1032: 1033: 1034: 1035: 1036: 1037: 1038: 1039: 1040: 1041: 1042: 1043: 1044: 1045: 1046: 1047: 1048: 1049: 1050: 1051: 1052: 1053: 1054: 1055: 1056: 1057: 1058: 1059: 1060: 1061: 1062: 1063: 1064: 1065: 1066: 1067: 1068: 1069: 1070: 1071: 1072: 1073: 1074: 1075: 1076: 1077: 1078: 1079: 1080: 1081: 1082: 1083: 1084: 1085: 1086: 1087: 1088: 1089: 1090: 1091: 1092: 1093: 1094: 1095: 1096: 1097: 1098: 1099: 1100: 1101: 1102: 1103: 1104: 1105: 1106: 1107: 1108: 1109: 1110: 1111: 1112: 1113: 1114: 1115: 1116: 1117: 1118: 1119: 1120: 1121: 1122: 1123: 1124: 1125: 1126: 1127: 1128: 1129: 1130: 1131: 1132: 1133: 1134: 1135: 1136: 1137: 1138: 1139: 1140: 1141: 1142: 1143: 1144: 1145: 1146: 1147: 1148: 1149: 1150: 1151: 1152: 1153: 1154: 1155: 1156: 1157: 1158: 1159: 1160: 1161: 1162: 1163: 1164: 1165: 1166: 1167: 1168: 1169: 1170: 1171: 1172: 1173: 1174: 1175: 1176: 1177: 1178: 1179: 1180: 1181: 1182: 1183: 1184: 1185: 1186: 1187: 1188: 1189: 1190: 1191: 1192: 1193: 1194: 1195: 1196: 1197: 1198: 1199: 1200: 1201: 1202: 1203: 1204: 1205: 1206: 1207: 1208: 1209: 1210: 1211: 1212: 1213: 1214: 1215: 1216: 1217: 1218: 1219: 1220: 1221: 1222: 1223: 1224: 1225: 1226: 1227: 1228: 1229: 1230: 1231: 1232: 1233: 1234: 1235: 1236: 1237: 1238: 1239: 1240: 1241: 1242: 1243: 1244: 1245: 1246: 1247: 1248: 1249: 1250: 1251: 1252: 1253: 1254: 1255: 1256: 1257: 1258: 1259: 1260: 1261: 1262: 1263: 1264: 1265: 1266: 1267: 1268: 1269: 1270: 1271: 1272: 1273: 1274: 1275: 1276: 1277: 1278: 1279: 1280: 1281: 1282: 1283: 1284: 1285: 1286: 1287: 1288: 1289: 1290: 1291: 1292: 1293: 1294: 1295: 1296: 1297: 1298: 1299: 1300: 1301: 1302: 1303: 1304: 1305: 1306: 1307: 1308: 1309: 1310: 1311: 1312: 1313: 1314: 1315: 1316: 1317: 1318: 1319: 1320: 1321: 1322: 1323: 1324: 1325: 1326: 1327: 1328: 1329: 1330: 1331: 1332: 1333: 1334: 1335: 1336: 1337: 1338: 1339: 1340: 1341: 1342: 1343: 1344: 1345: 1346: 1347: 1348: 1349: 1350: 1351: 1352: 1353: 1354: 1355: 1356: 1357: 1358: 1359: 1360: 1361: 1362: 1363: 1364: 1365: 1366: 1367: 1368: 1369: 1370: 1371: 1372: 1373: 1374: 1375: 1376: 1377: 1378: 1379: 1380: 1381: 1382: 1383: 1384: 1385: 1386: 1387: 1388: 1389: 1390: 1391: 1392: 1393: 1394: 1395: 1396: 1397: 1398: 1399: 1400: 1401: 1402: 1403: 1404: 1405: 1406: 1407: 1408: 1409: 1410: 1411: 1412: 1413: 1414: 1415: 1416: 1417: 1418: 1419: 1420: 1421: 1422: 1423: 1424: 1425: 1426: 1427: 1428: 1429: 1430: 1431: 1432: 1433: 1434: 1435: 1436: 1437: 1438: 1439: 1440: 1441: 1442: 1443: 1444: 1445: 1446: 1447: 1448: 1449: 1450: 1451: 1452: 1453: 1454: 1455: 1456: 1457: 1458: 1459: 1460: 1461: 1462: 1463: 1464: 1465: 1466: 1467: 1468: 1469: 1470: 1471: 1472: 1473: 1474: 1475: 1476: 1477: 1478: 1479: 1480: 1481: 1482: 1483: 1484: 1485: 1486: 1487: 1488: 1489: 1490: 1491: 1492: 1493: 1494: 1495: 1496: 1497: 1498: 1499: 1500: 1501: 1502: 1503: 1504: 1505: 1506: 1507: 1508: 1509: 1510: 1511: 1512: 1513: 1514: 1515: 1516: 1517: 1518: 1519: 1520: 1521: 1522: 1523: 1524: 1525: 1526: 1527: 1528: 1529: 1530: 1531: 1532: 1533: 1534: 1535: 1536: 1537: 1538: 1539: 1540: 1541: 1542: 1543: 1544: 1545: 1546: 1547: 1548: 1549: 1550: 1551: 1552: 1553: 1554: 1555: 1556: 1557: 1558: 1559: 1560: 1561: 1562: 1563: 1564: 1565: 1566: 1567: 1568: 1569: 1570: 1571: 1572: 1573: 1574: 1575: 1576: 1577: 1578: 1579: 1580: 1581: 1582: 1583: 1584: 1585: 1586: 1587: 1588: 1589: 1590: 1591: 1592: 1593: 1594: 1595: 1596: 1597: 1598: 1599: 1600: 1601: 1602: 1603: 1604: 1605: 1606: 1607: 1608: 1609: 1610: 1611: 1612: 1613: 1614: 1615: 1616: 1617: 1618: 1619: 1620: 1621: 1622: 1623: 1624: 1625: 1626: 1627: 1628: 1629: 1630: 1631: 1632: 1633: 1634: 1635: 1636: 1637: 1638: 1639: 1640: 1641: 1642: 1643: 1644: 1645: 1646: 1647: 1648: 1649: 1650: 1651: 1652: 1653: 1654: 1655: 1656: 1657: 1658: 1659: 1660: 1661: 1662: 1663: 1664: 1665: 1666: 1667: 1668: 1669: 1670: 1671: 1672: 1673: 1674: 1675: 1676: 1677: 1678: 1679: 1680: 1681: 1682: 1683: 1684: 1685: 1686: 1687: 1688: 1689: 1690: 1691: 1692: 1693: 1694: 1695: 1696: 1697: 1698: 1699: 1700: 1701: 1702: 1703: 1704: 1705: 1706: 1707: 1708: 1709: 1710: 1711: 1712: 1713: 1714: 1715: 1716: 1717: 1718: 1719: 1720: 1721: 1722: 1723: 1724: 1725: 1726: 1727: 1728: 1729: 1730: 1731: 1732: 1733: 1734: 1735: 1736: 1737: 1738: 1739: 1740: 1741: 1742: 1743: 1744: 1745: 1746: 1747: 1748: 1749: 1750: 1751: 1752: 1753: 1754: 1755: 1756: 1757: 1758: 1759: 1760: 1761: 1762: 1763: 1764: 1765: 1766: 1767: 1768: 1769: 1770: 1771: 1772: 1773: 1774: 1775: 1776: 1777: 1778: 1779: 1780: 1781: 1782: 1783: 1784: 1785: 1786: 1787: 1788: 1789: 1790: 1791: 1792: 1793: 1794: 1795: 1796: 1797: 1798: 1799: 1800: 1801: 1802: 1803: 1804: 1805: 1806: 1807: 1808: 1809: 1810: 1811: 1812: 1813: 1814: 1815: 1816: 1817: 1818: 1819: 1820: 1821: 1822: 1823: 1824: 1825: 1826: 1827: 1828: 1829: 1830: 1831: 1832: 1833: 1834: 1835: 1836: 1837: 1838: 1839: 1840: 1841: 1842: 1843: 1844: 1845: 1846: 1847: 1848: 1849: 1850: 1851: 1852: 1853: 1854: 1855: 1856: 1857: 1858: 1859: 1860: 1861: 1862: 1863: 1864: 1865: 1866: 1867: 1868: 1869: 1870: 1871: 1872: 1873: 1874: 1875: 1876: 1877: 1878: 1879: 1880: 1881: 1882: 1883: 1884: 1885: 1886: 1887: 1888: 1889: 1890: 1891: 1892: 1893: 1894: 1895: 1896: 1897: 1898: 1899: 1900: 1901: 1902: 1903: 1904: 1905: 1906: 1907: 1908: 1909: 1910: 1911: 1912: 1913: 1914: 1915: 1916: 1917: 1918: 1919: 1920: 1921: 1922: 1923: 1924: 1925: 1926: 1927: 1928: 1929: 1930: 1931: 1932: 1933: 1934: 1935: 1936: 1937: 1938: 1939: 1940: 1941: 1942: 1943: 1944: 1945: 1946: 1947: 1948: 1949: 1950: 1951: 1952: 1953: 1954: 1955: 1956: 1957: 1958: 1959: 1960: 1961: 1962: 1963: 1964: 1965: 1966: 1967: 1968: 1969: 1970: 1971: 1972: 1973: 1974: 1975: 1976: 1977: 1978: 1979: 1980: 1981: 1982: 1983: 1984: 1985: 1986: 1987: 1988: 1989: 1990: 1991: 1992: 1993: 1994: 1995: 1996: 1997: 1998: 1999: 2000: 2001: 2002: 2003: 2004: 2005: 2006: 2007: 2008: 2009: 2010: 2011: 2012: 2013: 2014: 2015: 2016: 2017: 2018: 2019: 2020: 2021: 2022: 2023: 2024: 2025: 2026: 2027: 2028: 2029: 2030: 2031: 2032: 2033: 2034: 2035: 2036: 2037: 2038: 2039: 2040: 2041: 2042: 2043: 2044: 2045: 2046: 2047: 2048: 2049: 2050: 2051: 2052: 2053: 2054: 2055: 2056: 2057: 2058: 2059: 2060: 2061: 2062: 2063: 2064: 2065: 2066: 2067: 2068: 2069: 2070: 2071: 2072: 2073: 2074: 2075: 2076: 2077: 2078: 2079: 2080: 2081: 2082: 2083: 2084: 2085: 2086: 2087: 2088: 2089: 2090: 2091: 2092: 2093: 2094: 2095: 2096: 2097: 2098: 2099: 2100: 2101: 2102: 2103: 2104: 2105: 2106: 2107: 2108: 2109: 2110: 2111: 2112: 2113: 2114: 2115: 2116: 2117: 2118: 2119: 2120: 2121: 2122: 2123: 2124: 2125: 2126: 2127: 2128: 2129: 2130: 2131: 2132: 2133: 2134: 2135: 2136: 2137: 2138: 2139: 2140: 2141: 2142: 2143: 2144: 2145: 2146: 2147: 2148: 2149: 2150: 2151: 2152: 2153: 2154: 2155: 2156: 2157: 2158: 2159: 2160: 2161: 2162: 2163: 2164: 2165: 2166: 2167: 2168: 2169: 2170: 2171: 2172: 2173: 2174: 2175: 2176: 2177: 2178: 2179: 2180: 2181: 2182: 2183: 2184: 2185: 2186: 2187: 2188: 2189: 2190: 2191: 2192: 2193: 2194: 2195: 2196: 2197: 2198: 2199: 2200: 2201: 2202: 2203: 2204: 2205: 2206: 2207: 2208: 2209: 2210: 2211: 2212: 2213: 2214: 2215: 2216: 2217: 2218: 2219: 2220: 2221: 2222: 2223: 2224: 2225: 2226: 2227: 2228: 2229: 2230: 2231: 2232: 2233: 2234: 2235: 2236: 2237: 2238: 2239: 2240: 2241: 2242: 2243: 2244: 2245: 2246: 2247: 2248: 2249: 2250: 2251: 2252: 2253: 2254: 2255: 2256: 2257: 2258: 2259: 2260: 2261: 2262: 2263: 2264: 2265: 2266: 2267: 2268: 2269: 2270: 2271: 2272: 2273: 2274: 2275: 2276: 2277: 2278: 2279: 2280: 2281: 2282: 2283: 2284: 2285: 2286: 2287: 2288: 2289: 2290: 2291: 2292: 2293: 2294: 2295: 2296: 2297: 2298: 2299: 2300: 2301: 2302: 2303: 2304: 2305: 2306: 2307: 2308: 2309: 2310: 2311: 2312: 2313: 2314: 2315: 2316: 2317: 2318: 2319: 2320: 2321: 2322: 2323: 2324: 2325: 2326: 2327: 2328: 2329: 2330: 2331: 2332: 2333: 2334: 2335: 2336: 2337: 2338: 2339: 2340: 2341: 2342: 2343: 2344: 2345: 2346: 2347: 2348: 2349: 2350: 2351: 2352: 2353: 2354: 2355: 2356: 2357: 2358: 2359: 2360: 2361: 2362: 2363: 2364: 2365: 2366: 2367: 2368: 2369: 2370: 2371: 2372: 2373: 2374: 2375: 2376: 2377: 2378: 2379: 2380: 2381: 2382: 2383: 2384: 2385: 2386: 2387: 2388: 2389: 2390: 2391: 2392: 2393: 2394: 2395: 2396: 2397: 2398: 2399: 2400: 2401: 2402: 2403: 2404: 2405: 2406: 2407: 2408: 2409: 2410: 2411: 2412: 2413: 2414: 2415: 2416: 2417: 2418: 2419: 2420: 2421: 2422: 2423: 2424: 2425: 2426: 2427: 2428: 2429: 2430: 2431: 2432: 2433: 2434: 2435: 2436: 2437: 2438: 2439: 2440: 2441: 2442: 2443: 2444: 2445: 2446: 2447: 2448: 2449: 2450: 2451: 2452: 2453: 2454: 2455: 2456: 2457: 2458: 2459: 2460: 2461: 2462: 2463: 2464: 2465: 2466: 2467: 2468: 2469: 2470: 2471: 2472: 2473: 2474: 2475: 2476: 2477: 2478: 2479: 2480: 2481: 2482: 2483: 2484: 2485: 2486: 2487: 2488: 2489: 2490: 2491: 2492: 2493: 2494: 2495: 2496: 2497: 2498: 2499: 2500: 2501: 2502: 2503: 2504: 2505: 2506: 2507: 2508: 2509: 2510: 2511: 2512: 2513: 2514: 2515: 2516: 2517: 2518: 2519: 2520: 2521: 2522: 2523: 2524: 2525: 2526: 2527: 2528: 2529: 2530: 2531: 2532: 2533: 2534: 2535: 2536: 2537: 2538: 2539: 2540: 2541: 2542: 2543: 2544: 2545: 2546: 2547: 2548: 2549: 2550: 2551: 2552: 2553: 2554: 2555: 2556: 2557: 2558: 2559: 2560: 2561: 2562: 2563: 2564: 2565: 2566: 2567: 2568: 2569: 2570: 2571: 2572: 2573: 2574: 2575: 2576: 2577: 2578: 2579: 2580: 2581: 2582: 2583: 2584: 2585: 2586: 2587: 2588: 2589: 2590: 2591: 2592: 2593: 2594: 2595: 2596: 2597: 2598: 2599: 2600: 2601: 2602: 2603: 2604: 2605: 2606: 2607: 2608: 2609: 2610: 2611: 2612: 2613: 2614: 2615: 2616: 2617: 2618: 2619: 2620: 2621: 2622: 2623: 2624: 2625: 2626: 2627: 2628: 2629: 2630: 2631: 2632: 2633: 2634: 2635: 2636: 2637: 2638: 2639: 2640: 2641: 2642: 2643: 2644: 2645: 2646: 2647: 2648: 2649: 2650: 2651: 2652: 2653: 2654: 2655: 2656: 2657: 2658: 2659: 2660: 2661: 2662: 2663: 2664: 2665: 2666: 2667: 2668: 2669: 2670: 2671: 2672: 2673: 2674: 2675: 2676: 2677: 2678: 2679: 2680: 2681: 2682: 2683: 2684: 2685: 2686: 2687: 2688: 2689: 2690: 2691: 2692: 2693: 2694: 2695: 2696: 2697: 2698: 2699: 2700: 2701: 2702: 2703: 2704: 2705: 2706: 2707: 2708: 2709: 2710: 2711: 2712: 2713: 2714: 2715: 2716: 2717: 2718: 2719: 2720: 2721: 2722: 2723: 2724: 2725: 2726: 2727: 2728: 2729: 2730: 2731: 2732: 2733: 2734: 2735: 2736: 2737: 2738: 2739: 2740: 2741: 2742: 2743: 2744: 2745: 2746: 2747: 2748: 2749: 2750: 2751: 2752: 2753: 2754: 2755: 2756: 2757: 2758: 2759: 2760: 2761: 2762: 2763: 2764: 2765: 2766: 2767: 2768: 2769: 2770: 2771: 2772: 2773: 2774: 2775: 2776: 2777: 2778: 2779: 2780: 2781: 2782: 2783: 2784: 2785: 2786: 2787: 2788: 2789: 2790: 2791: 2792: 2793: 2794: 2795: 2796: 2797: 2798: 2799: 2800: 2801: 2802: 2803: 2804: 2805: 2806: 2807: 2808: 2809: 2810: 2811: 2812: 2813: 2814: 2815: 2816: 2817: 2818: 2819: 2820: 2821: 2822: 2823: 2824: 2825: 2826: 2827: 2828: 2829: 2830: 2831: 2832: 2833: 2834: 2835: 2836: 2837: 2838: 2839: 2840: 2841: 2842: 2843: 2844: 2845: 2846: 2847: 2848: 2849: 2850: 2851: 2852: 2853: 2854: 2855: 2856: 2857: 2858: 2859: 2860: 2861: 2862: 2863: 2864: 2865: 2866: 2867: 2868: 2869: 2870:
<?php
namespace FlexiPeeHP;
class FlexiBeeRO extends \Ease\Sand
{
public static $infoDir = __DIR__.'/../../static';
public static $libVersion = '1.30';
public $nameSpace = 'winstrom';
public $apiURL = null;
public $resultField = 'results';
public $protoVersion = '1.0';
public $evidence = null;
public $evidenceInfo = [];
public $format = 'json';
public $responseFormat = 'json';
public $curl = null;
public $company = null;
public $url = null;
public $user = null;
public $password = null;
public $defaultHttpHeaders = ['User-Agent' => 'FlexiPeeHP'];
public $defaultUrlParams = ['limit' => 0];
public $init = null;
public $nameColumn = 'nazev';
public $myCreateColumn = 'false';
public $myLastModifiedColumn = 'lastUpdate';
public $fbKeyColumn = 'id';
public $curlInfo;
public $lastCurlError = null;
public $codes = null;
public $lastInsertedID = null;
public $prefix = '/c/';
public $lastCurlResponse;
public $lastResponseCode = null;
protected $postFields = null;
public $lastResult = null;
public $rowCount = null;
public $globalVersion = null;
public $filter;
protected $action;
public $actionsAvailable = null;
public $urlParams = [
'add-global-version',
'add-row-count',
'as-gui',
'auth',
'authSessionId',
'code-as-id',
'code-in-response',
'delimeter',
'detail',
'dir',
'dry-run',
'encoding',
'export-settings',
'fail-on-warning',
'filter',
'format',
'idUcetniObdobi',
'includes',
'inDesktopApp',
'limit',
'mode',
'no-ext-ids',
'no-http-errors',
'no-ids',
'only-ext-ids',
'order',
'relations',
'report-lang',
'report-name',
'report-sign',
'skupina-stitku',
'sort',
'start',
'stitky-as-ids',
'use-ext-id',
'use-internal-id',
'xpath',
];
public $authSessionId = null;
public $refreshToken = null;
protected $ignoreNotFound = false;
private $errors = [];
private $reports = [];
public $reportRecipient = 'podpora@flexibee.eu';
static public $DateTimeFormat = 'Y-m-d\TH:i:s.u+P';
static public $DateFormat = 'Y-m-d';
protected $responseStats = null;
public $chained = [];
public $offline = false;
public $timeout = null;
private $columnsInfo = [];
public function __construct($init = null, $options = [])
{
$this->init = $init;
parent::__construct();
$this->setUp($options);
$this->curlInit();
if (!empty($init)) {
$this->processInit($init);
}
}
public function setObjectName($objectName = null)
{
return parent::setObjectName(is_null($objectName) ? ( empty($this->getRecordIdent())
? $this->getObjectName() : $this->getRecordIdent().'@'.$this->getObjectName() )
: $objectName);
}
public function setUp($options = [])
{
if (array_key_exists('ver', $options)) {
$this->protoVersion = $options['ver'];
$this->prefix = 'v'.round($this->protoVersion).'/c/';
}
if (array_key_exists('companyUrl', $options)) {
$options = array_merge(self::companyUrlToOptions($options['companyUrl']),
$options);
}
$this->setupProperty($options, 'company', 'FLEXIBEE_COMPANY');
$this->setupProperty($options, 'url', 'FLEXIBEE_URL');
$this->setupProperty($options, 'user', 'FLEXIBEE_LOGIN');
$this->setupProperty($options, 'password', 'FLEXIBEE_PASSWORD');
$this->setupProperty($options, 'authSessionId', 'FLEXIBEE_AUTHSESSID');
$this->setupProperty($options, 'timeout', 'FLEXIBEE_TIMEOUT');
if (!empty($this->authSessionId)) {
$this->defaultHttpHeaders['X-authSessionId'] = $this->authSessionId;
}
if (isset($options['evidence'])) {
$this->setEvidence($options['evidence']);
}
$this->setupProperty($options, 'defaultUrlParams');
if (isset($options['prefix'])) {
$this->setPrefix($options['prefix']);
}
if (array_key_exists('detail', $options)) {
$this->defaultUrlParams['detail'] = $options['detail'];
}
$this->setupProperty($options, 'filter');
if (array_key_exists('offline', $options)) {
$this->offline = (boolean) $options['offline'];
}
if (array_key_exists('ignore404', $options)) {
$this->ignore404($options['ignore404']);
}
$this->setupProperty($options, 'debug');
$this->updateApiURL();
}
public function setupProperty($options, $name, $constant = null)
{
if (array_key_exists($name, $options)) {
$this->$name = $options[$name];
} elseif (array_key_exists($constant, $options)) {
$this->$name = $options[$constant];
} else {
if (property_exists($this, $name) && !empty($constant) && defined($constant)) {
$this->$name = constant($constant);
}
}
}
public static function companyUrlToOptions($companyUrl)
{
$urlParts = parse_url($companyUrl);
$scheme = isset($urlParts['scheme']) ? $urlParts['scheme'].'://' : '';
$host = isset($urlParts['host']) ? $urlParts['host'] : '';
$port = isset($urlParts['port']) ? ':'.$urlParts['port'] : '';
$path = isset($urlParts['path']) ? $urlParts['path'] : '';
$options['company'] = basename($path);
$options['url'] = $scheme.$host.$port;
return $options;
}
public function getConnectionOptions()
{
$conOpts = ['url' => $this->url];
if (empty($this->authSessionId)) {
$conOpts ['user'] = $this->user;
$conOpts['password'] = $this->password;
} else {
$conOpts['authSessionId'] = $this->authSessionId;
}
$company = $this->getCompany();
if (!empty($company)) {
$conOpts['company'] = $company;
}
if (!is_null($this->timeout)) {
$conOpts['timeout'] = $this->timeout;
}
return $conOpts;
}
public function curlInit()
{
if ($this->offline === false) {
$this->curl = \curl_init();
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($this->curl, CURLOPT_HTTPAUTH, true);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($this->curl, CURLOPT_VERBOSE, ($this->debug === true));
if (empty($this->authSessionId)) {
curl_setopt($this->curl, CURLOPT_USERPWD,
$this->user.':'.$this->password);
}
if (!is_null($this->timeout)) {
curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
}
}
return !$this->offline;
}
public function processInit($init)
{
if (is_integer($init)) {
$this->loadFromFlexiBee($init);
} elseif (is_array($init)) {
$this->takeData($init);
} elseif (preg_match('/\.(json|xml|csv)/', $init)) {
$this->takeData($this->getFlexiData((($init[0] != '/') ? $this->evidenceUrlWithSuffix($init)
: $init)));
} else {
$this->loadFromFlexiBee($init);
}
}
public function setDataValue($columnName, $value)
{
switch ($columnName) {
case 'kod':
$value = self::uncode($value);
default:
if (is_object($value)) {
switch (get_class($value)) {
case 'DateTime':
$columnInfo = $this->getColumnInfo($columnName);
switch ($columnInfo['type']) {
case 'date':
$value = self::dateToFlexiDate($value);
break;
case 'datetime':
$value = self::dateToFlexiDateTime($value);
break;
}
break;
}
}
$result = parent::setDataValue($columnName, $value);
break;
}
return $result;
}
public static function dateToFlexiDate($date)
{
return $date->format(self::$DateFormat);
}
public static function dateToFlexiDateTime($dateTime)
{
return $dateTime->format(self::$DateTimeFormat);
}
public function setPrefix($prefix)
{
switch ($prefix) {
case 'a':
case 'c':
case 'u':
case 'g':
case 'admin':
case 'status':
case 'login-logout':
$this->prefix = '/'.$prefix.'/';
break;
case null:
case '':
case '/':
$this->prefix = '';
break;
default:
throw new \Exception(sprintf('Unknown prefix %s', $prefix));
}
}
public function setFormat($format)
{
$result = true;
if (($this->debug === true) && !empty($this->evidence) && isset(Formats::$$this->evidence)) {
if (array_key_exists($format, array_flip(Formats::$$this->evidence))
=== false) {
$result = false;
}
}
if ($result === true) {
$this->format = $format;
$this->updateApiURL();
}
return $result;
}
public function setEvidence($evidence)
{
switch ($this->prefix) {
case '/c/':
if ($this->debug === true) {
if (array_key_exists($evidence, EvidenceList::$name)) {
$this->evidence = $evidence;
$result = true;
} else {
throw new \Exception(sprintf('Try to set unsupported evidence %s',
$evidence));
}
} else {
$this->evidence = $evidence;
$result = true;
}
break;
default:
$this->evidence = $evidence;
$result = true;
break;
}
$this->updateApiURL();
$this->evidenceInfo = $this->getEvidenceInfo();
return $result;
}
public function getEvidence()
{
return $this->evidence;
}
public function setCompany($company)
{
$this->company = $company;
}
public function getCompany()
{
return $this->company;
}
public function getResponseEvidence()
{
switch ($this->evidence) {
case 'c':
$evidence = 'company';
break;
case 'evidence-list':
$evidence = 'evidence';
break;
default:
$evidence = $this->getEvidence();
break;
}
return $evidence;
}
public static function object2array($object)
{
$result = null;
if (is_object($object)) {
$objectData = get_object_vars($object);
if (is_array($objectData) && count($objectData)) {
$result = array_map('self::object2array', $objectData);
}
} else {
if (is_array($object)) {
foreach ($object as $item => $value) {
$result[$item] = self::object2array($value);
}
} else {
$result = $object;
}
}
return $result;
}
public static function objectToID($object)
{
$resultID = null;
if (is_object($object) && method_exists($object, '__toString')
) {
$resultID = $object->__toString();
} else {
if (is_array($object)) {
foreach ($object as $item => $value) {
$resultID[$item] = self::objectToID($value);
}
} else {
$resultID = $object;
}
}
return $resultID;
}
public function getEvidenceURL()
{
$evidenceUrl = $this->url.$this->prefix.$this->company;
$evidence = $this->getEvidence();
if (!empty($evidence)) {
$evidenceUrl .= '/'.$evidence;
}
return $evidenceUrl;
}
public function evidenceUrlWithSuffix($urlSuffix)
{
$evidenceUrl = $this->getEvidenceUrl();
if (!empty($urlSuffix)) {
if (($urlSuffix[0] != '/') && ($urlSuffix[0] != ';') && ($urlSuffix[0]
!= '?')) {
$evidenceUrl .= '/';
}
$evidenceUrl .= $urlSuffix;
}
return $evidenceUrl;
}
public function updateApiURL()
{
$this->apiURL = $this->getEvidenceURL();
$rowIdentifier = $this->getRecordID();
if (empty($rowIdentifier)) {
$rowIdentifier = $this->getRecordCode();
if (empty($rowIdentifier)) {
$rowIdentifier = $this->getExternalID();
}
}
if (!empty($rowIdentifier)) {
$this->apiURL .= '/'.self::urlEncode($rowIdentifier);
}
$this->apiURL .= '.'.$this->format;
}
public function addDefaultUrlParams($urlRaw)
{
return \Ease\Shared::addUrlParams($urlRaw, $this->defaultUrlParams,
false);
}
public function performRequest($urlSuffix = null, $method = 'GET',
$format = null)
{
$this->rowCount = null;
$this->responseStats = [];
if (preg_match('/^http/', $urlSuffix)) {
$url = $urlSuffix;
} elseif (strlen($urlSuffix) && ($urlSuffix[0] == '/')) {
$url = $this->url.$urlSuffix;
} else {
$url = $this->evidenceUrlWithSuffix($urlSuffix);
}
$responseCode = $this->doCurlRequest($this->addDefaultUrlParams($url),
$method, $format);
return $this->parseResponse($this->rawResponseToArray($this->lastCurlResponse,
$this->responseFormat), $responseCode);
}
public function rawResponseToArray($responseRaw, $format)
{
$responseDecoded = [];
if (!empty(trim($responseRaw))) {
switch ($format) {
case 'json':
$responseDecoded = $this->rawJsonToArray($responseRaw);
break;
case 'xml':
$responseDecoded = $this->rawXmlToArray($this->lastCurlResponse);
break;
case 'txt':
default:
$responseDecoded = [$this->lastCurlResponse];
break;
}
}
return $responseDecoded;
}
public function rawJsonToArray($rawJson)
{
$responseDecoded = json_decode($rawJson, true, 10);
$decodeError = json_last_error_msg();
if ($decodeError == 'No error') {
if (array_key_exists($this->nameSpace, $responseDecoded)) {
$responseDecoded = $responseDecoded[$this->nameSpace];
}
} else {
if ($this->debug) {
$this->addStatusMessage('JSON Decoder: '.$decodeError, 'error');
$this->addStatusMessage($rawJson, 'debug');
}
}
return $responseDecoded;
}
public function rawXmlToArray($rawXML)
{
return self::xml2array($rawXML);
}
public function parseResponse($responseDecoded, $responseCode)
{
$mainResult = null;
switch ($responseCode) {
case 201:
break;
case 200:
if (is_array($responseDecoded)) {
if (isset($responseDecoded['@rowCount'])) {
$this->rowCount = (int) $responseDecoded['@rowCount'];
}
if (isset($responseDecoded['@globalVersion'])) {
$this->globalVersion = (int) $responseDecoded['@globalVersion'];
}
$mainResult = $this->unifyResponseFormat($responseDecoded);
if (array_key_exists('stats', $responseDecoded)) {
$this->responseStats = $responseDecoded['stats'];
} elseif (!empty($mainResult)) {
if (array_key_exists('success', $mainResult) && ($mainResult['success']
== 'false')) {
$this->responseStats = ['read' => 0];
} elseif (array_key_exists('properties', $mainResult)) {
$this->responseStats = ['read' => 1];
} else {
$responseEvidence = $this->getResponseEvidence();
if (!empty($this->rowCount)) {
$this->responseStats = ['read' => $this->rowCount];
} elseif (array_key_exists($responseEvidence,
$mainResult)) {
$this->responseStats = ['read' => count($mainResult[$responseEvidence])];
} else {
$this->responseStats = ['read' => count($mainResult)];
}
}
}
} else {
$mainResult = $responseDecoded;
}
$this->lastResult = $mainResult;
break;
case 500:
if ($this->debug === true) {
$this->error500Reporter($responseDecoded);
}
case 404:
if ($this->ignoreNotFound === true) {
break;
}
case 400:
default:
$this->addStatusMessage($this->lastResponseCode.': '.$this->curlInfo['url'],
'warning');
if (is_array($responseDecoded)) {
$this->parseError($responseDecoded);
}
$this->logResult($responseDecoded, $this->curlInfo['url']);
break;
}
return $mainResult;
}
public function parseError(array $responseDecoded)
{
if (array_key_exists('results', $responseDecoded)) {
$this->errors = $responseDecoded['results'][0]['errors'];
foreach ($this->errors as $errorInfo) {
$this->addStatusMessage($errorInfo['message'], 'error');
if (array_key_exists('for', $errorInfo)) {
unset($errorInfo['message']);
$this->addStatusMessage(json_encode($errorInfo), 'debug');
}
}
} else {
if (array_key_exists('message', $responseDecoded)) {
$this->errors = [['message' => $responseDecoded['message']]];
}
}
return count($this->errors);
}
public function doCurlRequest($url, $method, $format = null)
{
if (is_null($format)) {
$format = $this->format;
}
curl_setopt($this->curl, CURLOPT_URL, $url);
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->postFields);
$httpHeaders = $this->defaultHttpHeaders;
$formats = Formats::bySuffix();
if (!isset($httpHeaders['Accept'])) {
$httpHeaders['Accept'] = $formats[$format]['content-type'];
}
if (!isset($httpHeaders['Content-Type'])) {
$httpHeaders['Content-Type'] = $formats[$format]['content-type'];
}
$httpHeadersFinal = [];
foreach ($httpHeaders as $key => $value) {
if (($key == 'User-Agent') && ($value == 'FlexiPeeHP')) {
$value .= ' v'.self::$libVersion;
}
$httpHeadersFinal[] = $key.': '.$value;
}
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $httpHeadersFinal);
$this->lastCurlResponse = curl_exec($this->curl);
$this->curlInfo = curl_getinfo($this->curl);
$this->curlInfo['when'] = microtime();
$this->curlInfo['request_headers'] = $httpHeadersFinal;
$this->responseFormat = $this->contentTypeToResponseFormat($this->curlInfo['content_type'],
$url);
$this->lastResponseCode = $this->curlInfo['http_code'];
$this->lastCurlError = curl_error($this->curl);
if (strlen($this->lastCurlError)) {
$this->addStatusMessage(sprintf('Curl Error (HTTP %d): %s',
$this->lastResponseCode, $this->lastCurlError), 'error');
}
if ($this->debug === true) {
$this->saveDebugFiles();
}
return $this->lastResponseCode;
}
public function contentTypeToResponseFormat($contentType, $url = null)
{
if (!empty($url)) {
$url = parse_url($url, PHP_URL_PATH);
}
$contentTypeClean = strstr($contentType, ';') ? substr($contentType, 0,
strpos($contentType, ';')) : $contentType;
switch ($url) {
case '/login-logout/login';
$responseFormat = 'json';
break;
default :
switch ($contentTypeClean) {
case 'text/javascript':
$responseFormat = 'js';
break;
default:
$responseFormat = Formats::contentTypeToSuffix($contentTypeClean);
break;
}
break;
}
return $responseFormat;
}
public function setAction($action)
{
$result = false;
$actionsAvailable = $this->getActionsInfo();
if (is_array($actionsAvailable) && array_key_exists($action,
$actionsAvailable)) {
$this->action = $action;
$result = true;
}
return $result;
}
public static function xml2array($xml)
{
$arr = [];
if (!empty($xml)) {
if (is_string($xml)) {
$xml = simplexml_load_string($xml);
}
foreach ($xml->attributes() as $a) {
$arr['@'.$a->getName()] = strval($a);
}
foreach ($xml->children() as $r) {
if (count($r->children()) == 0) {
$arr[$r->getName()] = strval($r);
} else {
$arr[$r->getName()][] = self::xml2array($r);
}
}
}
return $arr;
}
public function disconnect()
{
if (is_resource($this->curl)) {
curl_close($this->curl);
}
$this->curl = null;
}
public function __destruct()
{
$this->disconnect();
}
public function getFlexiRow($recordID)
{
$record = null;
$response = $this->performRequest($this->evidence.'/'.$recordID.'.json');
if (isset($response[$this->evidence])) {
$record = $response[$this->evidence][0];
}
return $record;
}
public function extractUrlParams(&$conditions, &$urlParams)
{
foreach ($this->urlParams as $urlParam) {
if (isset($conditions[$urlParam])) {
\Ease\Sand::divDataArray($conditions, $urlParams, $urlParam);
}
}
}
public static function urlEncode($urlRaw)
{
return str_replace(['%27', '%3A'], ["'", ':'], rawurlencode($urlRaw));
}
public function getFlexiData($suffix = null, $conditions = null)
{
$finalUrl = '';
$evidenceToRestore = null;
$urlParams = $this->defaultUrlParams;
if (!empty($conditions)) {
if (is_array($conditions)) {
$this->extractUrlParams($conditions, $urlParams);
if (array_key_exists('evidence', $conditions) && is_null($this->getColumnInfo('evidence'))) {
$evidenceToRestore = $this->getEvidence();
$this->setEvidence($conditions['evidence']);
unset($conditions['evidence']);
}
$conditions = $this->flexiUrl($conditions);
}
if (strlen($conditions) && ($conditions[0] != '/')) {
$conditions = '('.self::urlEncode($conditions).')';
}
}
if (strlen($suffix) && ($suffix != '$sum')) {
if (preg_match('/^http/', $suffix) || ($suffix[0] == '/') || is_numeric($suffix)) {
$finalUrl = $suffix;
} else {
if (preg_match('/^(code|ext):(.*)/', $suffix)) {
$finalUrl = self::urlizeId($suffix);
} else {
$finalUrl = $suffix;
}
}
}
$finalUrl .= $conditions;
if ($suffix == '$sum') {
$finalUrl .= '/$sum';
}
if (!empty($urlParams)) {
if (strstr($finalUrl, '?')) {
$finalUrl .= '&';
} else {
$finalUrl .= '?';
}
$finalUrl .= http_build_query(array_map(function($a) {
return is_bool($a) ? ($a ? 'true' : 'false' ) : $a;
}, $urlParams), null, '&', PHP_QUERY_RFC3986);
}
$transactions = $this->performRequest($finalUrl, 'GET');
$responseEvidence = $this->getResponseEvidence();
if (is_array($transactions) && array_key_exists($responseEvidence,
$transactions)) {
$result = $transactions[$responseEvidence];
if ((count($result) == 1) && empty(current($result))) {
$result = [];
}
} else {
$result = $transactions;
}
if (!is_null($evidenceToRestore)) {
$this->setEvidence($evidenceToRestore);
}
return $result;
}
public function loadFromFlexiBee($id = null)
{
$data = [];
if (is_null($id)) {
$id = $this->getMyKey();
}
$flexidata = $this->getFlexiData($this->getEvidenceUrl().'/'.self::urlizeId($id));
if ($this->lastResponseCode == 200) {
$this->apiURL = $this->curlInfo['url'];
if (is_array($flexidata) && (count($flexidata) == 1) && is_array(current($flexidata))) {
$data = current($flexidata);
}
}
return $this->takeData($data);
}
public function reload()
{
$id = $this->getRecordIdent();
$this->dataReset();
$this->loadFromFlexiBee($id);
return $this->lastResponseCode == 200;
}
public function setFilter($filter)
{
return $this->filter = is_array($filter) ? self::flexiUrl($filter) : $filter;
}
public function getJsonizedData($data = null, $options = 0)
{
if (is_null($data)) {
$data = $this->getData();
}
$dataToJsonize = array_merge(['@version' => $this->protoVersion],
$this->getDataForJSON($data));
$jsonRaw = json_encode([$this->nameSpace => $dataToJsonize],
$options);
return $jsonRaw;
}
public function getDataForJSON($data = null)
{
if (is_null($data)) {
$data = $this->getData();
}
$dataForJson = [$this->getEvidence() => $this->objectToID($data)];
if (!is_null($this->action)) {
$dataForJson[$this->evidence.'@action'] = $this->action;
$this->action = null;
}
if (!is_null($this->filter)) {
$dataForJson[$this->evidence.'@filter'] = $this->filter;
}
foreach ($this->chained as $chained) {
$chainedData = $chained->getDataForJSON();
foreach ($chainedData as $chainedItemEvidence => $chainedItemData) {
if (array_key_exists($chainedItemEvidence, $dataForJson)) {
if (is_string(key($dataForJson[$chainedItemEvidence]))) {
$dataBackup = $dataForJson[$chainedItemEvidence];
$dataForJson[$chainedItemEvidence] = [];
$dataForJson[$chainedItemEvidence][] = $dataBackup;
}
if (array_key_exists(0, $chainedItemData)) {
foreach ($chainedItemData as $chainedItem) {
$dataForJson[$chainedItemEvidence][] = $chainedItem;
}
} else {
$dataForJson[$chainedItemEvidence][] = $chainedItemData;
}
} else {
$dataForJson[$chainedItemEvidence] = $chainedItemData;
}
}
}
return $dataForJson;
}
public function join(&$object)
{
$result = true;
if (method_exists($object, 'getDataForJSON')) {
$this->chained[] = $object;
} else {
throw new \Ease\Exception('$object->getDataForJSON() does not exist');
}
return $result;
}
public static function urlizeId($id)
{
if (is_array($id)) {
$id = rawurlencode('('.self::flexiUrl($id).')');
} else if (preg_match('/^ext:/', $id)) {
$id = self::urlEncode($id);
} else if (preg_match('/^code:/', $id)) {
$id = self::code(self::urlEncode(self::uncode($id)));
}
return $id;
}
public function idExists($identifer = null)
{
if (is_null($identifer)) {
$identifer = $this->getMyKey();
}
$ignorestate = $this->ignore404();
$this->ignore404(true);
$cands = $this->getFlexiData(null,
[
'detail' => 'custom:'.$this->getKeyColumn(),
$this->getKeyColumn() => $identifer
]);
$this->ignore404($ignorestate);
return ($this->lastResponseCode == 200) && !empty($cands);
}
public function recordExists($data = [])
{
if (empty($data)) {
$data = $this->getData();
}
$ignorestate = $this->ignore404();
$this->ignore404(true);
$keyColumn = $this->getKeyColumn();
$res = $this->getColumnsFromFlexibee([$keyColumn],
is_array($data) ? $data : [$keyColumn => $data]);
if (empty($res) || (isset($res['success']) && ($res['success'] == 'false'))
|| ((isset($res) && is_array($res)) && !isset($res[0]) )) {
$found = false;
} else {
$found = true;
}
$this->ignore404($ignorestate);
return $found;
}
public function getSubItems()
{
return array_key_exists('polozkyFaktury', $this->getData()) ? $this->getDataValue('polozkyFaktury')
: (array_key_exists('polozkyDokladu', $this->getData()) ? $this->getDataValue('polozkyDokladu')
: null);
}
public function getAllFromFlexibee($conditions = null, $indexBy = null)
{
if (is_int($conditions)) {
$conditions = [$this->getmyKeyColumn() => $conditions];
}
$flexiData = $this->getFlexiData('', $conditions);
if (!is_null($indexBy)) {
$flexiData = $this->reindexArrayBy($flexiData);
}
return $flexiData;
}
public function getColumnsFromFlexibee($columnsList, $conditions = [],
$indexBy = null)
{
$detail = 'full';
switch (gettype($columnsList)) {
case 'integer':
$conditions = [$this->getmyKeyColumn() => $conditions];
case 'array':
if (!is_null($indexBy) && !array_key_exists($indexBy,
$columnsList)) {
$columnsList[] = $indexBy;
}
$columns = implode(',', array_unique($columnsList));
$detail = 'custom:'.$columns;
default:
switch ($columnsList) {
case 'id':
$detail = 'id';
break;
case 'summary':
$detail = 'summary';
break;
default:
break;
}
break;
}
$conditions['detail'] = $detail;
$flexiData = $this->getFlexiData(null, $conditions);
if (is_string($indexBy) && is_array($flexiData) && array_key_exists(0,
$flexiData) && array_key_exists($indexBy, $flexiData[0])) {
$flexiData = $this->reindexArrayBy($flexiData, $indexBy);
}
return $flexiData;
}
public function getKod($data = null, $unique = true)
{
$kod = null;
if (is_null($data)) {
$data = $this->getData();
}
if (is_string($data)) {
$data = [$this->nameColumn => $data];
}
if (isset($data['kod'])) {
$kod = $data['kod'];
} else {
if (isset($data[$this->nameColumn])) {
$kod = preg_replace('/[^a-zA-Z0-9]/', '',
\Ease\Sand::rip($data[$this->nameColumn]));
} else {
if (isset($data[$this->keyColumn])) {
$kod = \Ease\Sand::rip($data[$this->keyColumn]);
}
}
$kod = substr($kod, 0, 20);
}
if (!strlen($kod)) {
$kod = 'NOTSET';
}
if (strlen($kod) > 18) {
$kodfinal = strtoupper(substr($kod, 0, 18));
} else {
$kodfinal = strtoupper($kod);
}
if ($unique) {
$counter = 0;
if (!empty($this->codes) && count($this->codes)) {
foreach ($this->codes as $codesearch => $keystring) {
if (strstr($codesearch, $kodfinal)) {
++$counter;
}
}
}
if ($counter) {
$kodfinal = $kodfinal.$counter;
}
$this->codes[$kodfinal] = $kod;
}
return self::code($kodfinal);
}
public function logResult($resultData = null, $url = null)
{
$logResult = false;
if (isset($resultData['success']) && ($resultData['success'] == 'false')) {
if (isset($resultData['message'])) {
$this->addStatusMessage($resultData['message'], 'warning');
}
$this->addStatusMessage('Error '.$this->lastResponseCode.': '.urldecode($url),
'warning');
unset($url);
}
if (is_null($resultData)) {
$resultData = $this->lastResult;
}
if (isset($url)) {
$this->logger->addStatusMessage($this->lastResponseCode.':'.urldecode($url));
}
if (isset($resultData['results'])) {
if ($resultData['success'] == 'false') {
$status = 'error';
} else {
$status = 'success';
}
foreach ($resultData['results'] as $result) {
if (isset($result['request-id'])) {
$rid = $result['request-id'];
} else {
$rid = '';
}
if (isset($result['errors'])) {
foreach ($result['errors'] as $error) {
$message = $error['message'];
if (isset($error['for'])) {
$message .= ' for: '.$error['for'];
}
if (isset($error['value'])) {
$message .= ' value:'.$error['value'];
}
if (isset($error['code'])) {
$message .= ' code:'.$error['code'];
}
$this->addStatusMessage($rid.': '.$message, $status);
}
}
}
}
return $logResult;
}
public function saveDebugFiles()
{
$tmpdir = sys_get_temp_dir();
$fname = $this->evidence.'-'.$this->curlInfo['when'].'.'.$this->format;
$reqname = $tmpdir.'/request-'.$fname;
$respname = $tmpdir.'/response-'.$fname;
if (file_put_contents($reqname, $this->postFields)) {
$this->addStatusMessage($reqname, 'debug');
}
if (file_put_contents($respname, $this->lastCurlResponse)) {
$this->addStatusMessage($respname, 'debug');
}
}
public function setPostFields($data)
{
$this->postFields = $data;
}
public function getPostFields()
{
return $this->postFields;
}
public static function flexiUrl(array $data, $joiner = 'and', $defop = 'eq')
{
$parts = [];
foreach ($data as $column => $value) {
if (!is_numeric($column)) {
if (is_integer($data[$column]) || is_float($data[$column])) {
$parts[$column] = $column.' eq \''.$data[$column].'\'';
} elseif (is_bool($data[$column])) {
$parts[$column] = $data[$column] ? $column.' eq true' : $column.' eq false';
} elseif (is_null($data[$column])) {
$parts[$column] = $column." is null";
} elseif (is_array($data[$column])) {
$parts[$column] = $column." in (".implode(',',
array_map(function($a) {
return "'$a'";
}, $data[$column])).")";
} elseif (is_object($data[$column])) {
switch (get_class($data[$column])) {
case 'DatePeriod':
$parts[$column] = $column." between '".$data[$column]->getStartDate()->format(self::$DateFormat)."' '".$data[$column]->getEndDate()->format(self::$DateFormat)."'";
break;
case 'DateTime':
$parts[$column] = $column." eq '".$data[$column]->format(self::$DateFormat)."'";
break;
default:
$parts[$column] = $column." $defop '".$data[$column]."'";
break;
}
} else {
switch ($value) {
case '!null':
$parts[$column] = $column." is not null";
break;
case 'is empty':
case 'is not empty':
case 'is true':
case 'is false':
$parts[$column] = $column.' '.$value;
break;
default:
$condParts = explode(' ', trim($value));
switch ($condParts[0]) {
case '<>':
case '!=':
case 'ne':
case 'neq':
case '<':
case 'lt':
case '<=':
case 'lte':
case '>':
case 'gt':
case '>=':
case 'gte':
case 'like':
case 'begins':
case 'between':
case 'ends':
if (count($condParts) == 1) {
$parts[$column] = $column .= ' '.$value;
} else {
$parts[$column] = $column .= ' '.$condParts[0]." '".$condParts[1]."'";
}
break;
default:
if ($column == 'stitky') {
$parts[$column] = $column."='".self::code($data[$column])."'";
} else {
$parts[$column] = $column." $defop '".$data[$column]."'";
}
break;
}
break;
}
}
} else {
$parts[] = $value;
}
}
return implode(' '.$joiner.' ', $parts);
}
public function getRecordID()
{
$id = $this->getDataValue('id');
return is_null($id) ? null : is_numeric($id) ? intval($id) : $id;
}
public function getRecordCode()
{
return empty($this->getDataValue('kod')) ? null : self::code($this->getDataValue('kod'));
}
public function getRecordIdent()
{
$ident = $this->getExternalID();
if (empty($ident)) {
$ident = $this->getRecordCode();
}
if (empty($ident)) {
$ident = $this->getRecordID();
}
return $ident;
}
public function __toString()
{
return strval($this->getRecordIdent());
}
public static function evidenceToClassName($evidence)
{
return str_replace(' ', '', ucwords(str_replace('-', ' ', $evidence)));
}
public function getFirstRecordID()
{
$firstID = null;
$keyColumn = $this->getKeyColumn();
$firstIdRaw = $this->getColumnsFromFlexibee([$keyColumn],
['limit' => 1, 'order' => $keyColumn], $keyColumn);
if (!empty($firstIdRaw) && isset(current($firstIdRaw)[$keyColumn])) {
$firstID = current($firstIdRaw)[$keyColumn];
}
return is_numeric($firstID) ? intval($firstID) : $firstID;
}
public function getNextRecordID($conditions = [])
{
$conditions['order'] = 'id@D';
$conditions['limit'] = 1;
$conditions[] = 'id gt '.$this->getRecordID();
$next = $this->getColumnsFromFlexibee(['id'], $conditions);
return (is_array($next) && array_key_exists(0, $next) && array_key_exists('id',
$next[0])) ? intval($next[0]['id']) : null;
}
public function getPrevRecordID($conditions = [])
{
$conditions['order'] = 'id@A';
$conditions['limit'] = 1;
$conditions[] = 'id lt '.$this->getRecordID();
$prev = $this->getColumnsFromFlexibee(['id'], $conditions);
return (is_array($prev) && array_key_exists(0, $prev) && array_key_exists('id',
$prev[0])) ? intval($prev[0]['id']) : null;
}
public function getExternalID($want = null)
{
$extid = null;
$ids = $this->getExternalIDs();
if (is_null($want)) {
if (!empty($ids)) {
$extid = current($ids);
}
} else {
if (!is_null($ids) && is_array($ids)) {
foreach ($ids as $id) {
if (strstr($id, 'ext:'.$want)) {
if (is_null($extid)) {
$extid = str_replace('ext:'.$want.':', '', $id);
} else {
if (is_array($extid)) {
$extid[] = str_replace('ext:'.$want.':', '', $id);
} else {
$extid = [$extid, str_replace('ext:'.$want.':',
'', $id)];
}
}
}
}
}
}
return $extid;
}
public function getExternalIDs()
{
return $this->getDataValue('external-ids');
}
public function getGlobalVersion()
{
$this->getFlexiData(null, ['add-global-version' => 'true', 'limit' => 1]);
return $this->globalVersion;
}
public function getApiURL($format = null)
{
$apiUrl = str_replace(['.'.$this->format, '?limit=0'], '', $this->apiURL);
return $apiUrl.(empty($format) ? '' : '.'.$format );
}
public function getResponseFormat()
{
return $this->responseFormat;
}
public function unifyResponseFormat($responseBody)
{
if (!is_array($responseBody) || array_key_exists('message',
$responseBody)) {
$response = $responseBody;
} else {
$evidence = $this->getResponseEvidence();
if (array_key_exists($evidence, $responseBody)) {
$response = [];
$evidenceContent = $responseBody[$evidence];
if (array_key_exists(0, $evidenceContent)) {
$response[$evidence] = $evidenceContent;
} else {
$response[$evidence][0] = $evidenceContent;
}
} else {
if (isset($responseBody['priloha'])) {
$response = $responseBody['priloha'];
} else {
if (array_key_exists('results', $responseBody)) {
$response = $responseBody['results'];
} else {
$response = $responseBody;
}
}
}
}
return $response;
}
public function getOfflineColumnsInfo($evidence = null)
{
$columnsInfo = null;
$infoSource = self::$infoDir.'/Properties.'.(empty($evidence) ? $this->getEvidence()
: $evidence).'.json';
if (file_exists($infoSource)) {
$columnsInfo = json_decode(file_get_contents($infoSource), true);
}
return $columnsInfo;
}
public function getOnlineColumnsInfo($evidence = null)
{
$properties = [];
$evidence = is_null($evidence) ? $this->getEvidence() : $evidence;
$flexinfo = $this->performRequest('/c/'.$this->company.'/'.$evidence.'/properties.json');
if (!empty($flexinfo) && array_key_exists('properties', $flexinfo)) {
foreach ($flexinfo['properties']['property'] as $evidenceProperty) {
$key = $evidenceProperty['propertyName'];
$properties[$key] = $evidenceProperty;
$properties[$key]['name'] = $evidenceProperty['name'];
$properties[$key]['type'] = $evidenceProperty['type'];
if (array_key_exists('url', $evidenceProperty)) {
$properties[$key]['url'] = str_replace('?limit=0', '',
$evidenceProperty['url']);
}
}
}
return $properties;
}
public function updateColumnsInfo($columnsInfo = null, $evidence = null)
{
$evidence = is_null($evidence) ? $this->getEvidence() : $evidence;
if (is_null($columnsInfo)) {
$this->columnsInfo[$evidence] = $this->offline ? $this->getOfflineColumnsInfo($evidence)
: $this->getOnlineColumnsInfo($evidence);
} else {
$this->columnsInfo[$evidence] = $columnsInfo;
}
}
public function getColumnsInfo($evidence = null)
{
$evidence = is_null($evidence) ? $this->getEvidence() : $evidence;
if (!array_key_exists($evidence, $this->columnsInfo)) {
$this->updateColumnsInfo($this->getOfflineColumnsInfo($evidence),
$evidence);
}
return $this->columnsInfo[$evidence];
}
public function getColumnInfo($column, $evidence = null)
{
$columnsInfo = $this->getColumnsInfo(empty($evidence) ? $this->getEvidence()
: $evidence);
return (empty($column) || empty($columnsInfo) || !is_array($columnsInfo))
? null : array_key_exists($column, $columnsInfo) ? $columnsInfo[$column]
: null;
}
public function getActionsInfo($evidence = null)
{
$actionsInfo = null;
if (is_null($evidence)) {
$evidence = $this->getEvidence();
}
$propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
if (isset(\FlexiPeeHP\Actions::$$propsName)) {
$actionsInfo = Actions::$$propsName;
}
return $actionsInfo;
}
public function getRelationsInfo($evidence = null)
{
$relationsInfo = null;
if (is_null($evidence)) {
$evidence = $this->getEvidence();
}
$propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
if (isset(\FlexiPeeHP\Relations::$$propsName)) {
$relationsInfo = Relations::$$propsName;
}
return $relationsInfo;
}
public function getEvidenceInfo($evidence = null)
{
$evidencesInfo = null;
if (is_null($evidence)) {
$evidence = $this->getEvidence();
}
if (isset(EvidenceList::$evidences[$evidence])) {
$evidencesInfo = EvidenceList::$evidences[$evidence];
$propsName = lcfirst(FlexiBeeRO::evidenceToClassName($evidence));
if (isset(Formats::$$propsName)) {
$evidencesInfo['formats'] = Formats::$$propsName;
}
}
return $evidencesInfo;
}
public function getEvidenceName($evidence = null)
{
$evidenceName = null;
if (is_null($evidence)) {
$evidence = $this->getEvidence();
}
if (isset(EvidenceList::$name[$evidence])) {
$evidenceName = EvidenceList::$name[$evidence];
}
return $evidenceName;
}
public function saveResponseToFile($destfile)
{
if (strlen($this->lastCurlResponse)) {
$this->doCurlRequest($this->apiURL, 'GET', $this->format);
}
file_put_contents($destfile, $this->lastCurlResponse);
}
public function getVazby($id = null)
{
if (is_null($id)) {
$id = $this->getRecordID();
}
if (!empty($id)) {
$vazbyRaw = $this->getColumnsFromFlexibee(['vazby'],
['relations' => 'vazby', 'id' => $id]);
$vazby = array_key_exists('vazby', $vazbyRaw[0]) ? $vazbyRaw[0]['vazby']
: null;
} else {
throw new \Exception(_('ID requied to get record relations '));
}
return $vazby;
}
public function getFlexiBeeURL()
{
$parsed_url = parse_url(str_replace('.'.$this->format, '', $this->apiURL));
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://'
: '';
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
$port = isset($parsed_url['port']) ? ':'.$parsed_url['port'] : '';
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
$pass = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : '';
$pass = ($user || $pass) ? "$pass@" : '';
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
return $scheme.$user.$pass.$host.$port.$path;
}
public function setMyKey($myKeyValue)
{
if (substr($myKeyValue, 0, 4) == 'ext:') {
if ($this->evidenceInfo['extIdSupported'] == 'false') {
$this->addStatusMessage(sprintf(_('Evidence %s does not support extIDs'),
$this->getEvidence()), 'warning');
$res = false;
} else {
$extIds = $this->getDataValue('external-ids');
if (!empty($extIds) && count($extIds)) {
$extIds = array_combine($extIds, $extIds);
}
$extIds[$myKeyValue] = $myKeyValue;
$res = $this->setDataValue('external-ids',
$extIds);
}
} else {
$res = parent::setMyKey($myKeyValue);
}
$this->updateApiURL();
return $res;
}
public function ignore404($ignore = null)
{
if (!is_null($ignore)) {
$this->ignoreNotFound = $ignore;
}
return $this->ignoreNotFound;
}
public function sendByMail($to, $subject, $body, $cc = null)
{
$this->setPostFields($body);
$this->performRequest(rawurlencode($this->getRecordID()).'/odeslani-dokladu?to='.$to.'&subject='.urlencode($subject).'&cc='.$cc
, 'PUT', 'xml');
return $this->lastResponseCode == 200;
}
public function sendUnsent()
{
return $this->doCurlRequest('automaticky-odeslat-neodeslane', 'PUT',
'xml');
}
public static function flexiDateToDateTime($flexidate)
{
return \DateTime::createFromFormat(strstr($flexidate, '+') ? self::$DateFormat.'O'
: self::$DateFormat, $flexidate)->setTime(0, 0);
}
public static function flexiDateTimeToDateTime($flexidatetime)
{
if (strchr($flexidatetime, '.')) {
$format = self::$DateTimeFormat;
} else {
$format = 'Y-m-d\TH:i:s+P';
}
return \DateTime::createFromFormat($format, $flexidatetime);
}
public function getInFormat($format, $reportName = null, $lang = null,
$sign = false)
{
$response = null;
if ($this->setFormat($format)) {
$urlParams = [];
switch ($format) {
case 'pdf':
switch ($lang) {
case 'cs':
case 'sk':
case 'en':
case 'de':
$urlParams['report-lang'] = $lang;
break;
case null:
case '':
break;
default:
throw new \Ease\Exception('Unknown language '.$lang.' for PDF export');
break;
}
if (boolval($sign) === true) {
$urlParams['report-sign'] = 'true';
}
break;
case 'html':
$urlParams['inDesktopApp'] = 'true';
break;
}
if (!empty($reportName)) {
$urlParams['report-name'] = $reportName;
}
if (($this->doCurlRequest(\Ease\Shared::addUrlParams($this->apiURL,
$urlParams), 'GET') == 200)) {
$response = $this->lastCurlResponse;
}
}
return $response;
}
public function downloadInFormat($format, $destDir = './',
$reportName = null)
{
$fileOnDisk = null;
$formatBackup = $this->format;
if ($this->setFormat($format)) {
$downloadTo = $destDir.$this->getEvidence().'_'.$this->getMyKey().'.'.$format;
if (($this->doCurlRequest(empty($reportName) ? $this->apiURL : \Ease\Shared::addUrlParams($this->apiURL,
['report-name' => $reportName]), 'GET') == 200) && (file_put_contents($downloadTo,
$this->lastCurlResponse) !== false)) {
$fileOnDisk = $downloadTo;
}
$this->setFormat($formatBackup);
}
return $fileOnDisk;
}
public function takeData($data)
{
$keyColumn = $this->getKeyColumn();
if (array_key_exists($keyColumn, $data) && is_array($data[$keyColumn])) {
foreach ($data[$keyColumn] as $recPos => $recordKey) {
if (substr($recordKey, 0, 4) == 'ext:') {
$data['external-ids'][] = $recordKey;
unset($data[$keyColumn][$recPos]);
}
}
if (count($data[$keyColumn]) == 1) {
$data[$keyColumn] = current($data[$keyColumn]);
}
}
$result = parent::takeData($data);
if (array_key_exists($keyColumn, $data) || array_key_exists('kod', $data)) {
$this->updateApiURL();
}
return $result;
}
public function getReportsInfo()
{
$reports = [];
$reportsRaw = $this->getFlexiData($this->getEvidenceURL().'/reports');
if (!empty($reportsRaw) && array_key_exists('reports', $reportsRaw) && !empty($reportsRaw['reports'])
&& array_key_exists('report', $reportsRaw['reports']) &&
!empty($reportsRaw['reports']['report'])) {
if (\Ease\jQuery\Part::isAssoc($reportsRaw['reports']['report'])) {
$reports = [$reportsRaw['reports']['report']['reportId'] => $reportsRaw['reports']['report']];
} else {
$reports = self::reindexArrayBy($reportsRaw['reports']['report'],
'reportId');
}
}
return $reports;
}
public function requestAuthSessionID($username, $password, $otp = null)
{
$this->postFields = http_build_query(is_null($otp) ? ['username' => $username,
'password' => $password] : ['username' => $username, 'password' => $password,
'otp' => $otp]);
$response = $this->performRequest('/login-logout/login', 'POST',
'json');
if (array_key_exists('refreshToken', $response)) {
$this->refreshToken = $response['refreshToken'];
} else {
$this->refreshToken = null;
}
return array_key_exists('authSessionId', $response) ? $response['authSessionId']
: null;
}
public function login()
{
$this->authSessionId = $this->requestAuthSessionID($this->user,
$this->password);
return $this->lastResponseCode == 200;
}
public function logout($username = null)
{
return $this->performRequest('/status/user/'.(is_null($username) ? $this->user
: $username).'/logout', 'POST');
}
public function error500Reporter($errorResponse)
{
$ur = str_replace('/c/'.$this->company, '',
str_replace($this->url, '', $this->curlInfo['url']));
if (!array_key_exists($ur, $this->reports)) {
$tmpdir = sys_get_temp_dir();
$myTime = $this->curlInfo['when'];
$curlname = $tmpdir.'/curl-'.$this->evidence.'-'.$myTime.'.json';
file_put_contents($curlname,
json_encode($this->curlInfo, JSON_PRETTY_PRINT));
$report = new \Ease\Mailer($this->reportRecipient,
'Error report 500 - '.$ur);
$d = dir($tmpdir);
while (false !== ($entry = $d->read())) {
if (strstr($entry, $myTime)) {
$ext = pathinfo($tmpdir.'/'.$entry, PATHINFO_EXTENSION);
$mime = Formats::suffixToContentType($ext);
$report->addFile($tmpdir.'/'.$entry,
empty($mime) ? 'text/plain' : $mime);
}
}
$d->close();
if ((strstr($this->url, '://localhost') || strstr($this->url,
'://127.')) && file_exists('/var/log/flexibee.log')) {
$fl = fopen('/var/log/'.'flexibee.log', 'r');
if ($fl) {
$tracelog = [];
for ($x_pos = 0, $ln = 0, $output = array(); fseek($fl,
$x_pos, SEEK_END) !== -1; $x_pos--) {
$char = fgetc($fl);
if ($char === "\n") {
$tracelog[] = $output[$ln];
if (strstr($output[$ln], $errorResponse['message'])) {
break;
}
$ln++;
continue;
}
$output[$ln] = $char.((array_key_exists($ln, $output)) ? $output[$ln]
: '');
}
$trace = implode("\n", array_reverse($tracelog));
$tracefile = $tmpdir.'/trace-'.$this->evidence.'-'.$myTime.'.log';
file_put_contents($tracefile, $trace);
$report->addItem("\n\n".$trace);
fclose($fl);
}
} else {
$report->addItem($errorResponse['message']);
}
$licenseInfo = $this->performRequest($this->url.'/default-license.json');
$report->addItem("\n\n".json_encode($licenseInfo['license'],
JSON_PRETTY_PRINT));
if ($report->send()) {
$this->reports[$ur] = $myTime;
}
}
}
public static function code($code)
{
return ((substr($code, 0, 4) == 'ext:') ? $code : 'code:'.strtoupper(self::uncode($code)));
}
public static function uncode($code)
{
return str_replace(['code:', 'code%3A'], '', $code);
}
public static function arrayCleanUP($data)
{
return array_filter(
$data,
function ($key) {
return !strchr($key, '@');
}, ARRAY_FILTER_USE_KEY);
}
public function logBanner($additions = null)
{
$this->addStatusMessage('FlexiBee '.str_replace('://',
'://'.$this->user.'@', $this->getApiUrl()).' FlexiPeeHP v'.self::$libVersion.' (FlexiBee '.EvidenceList::$version.') EasePHP Framework v'.\Ease\Atom::$frameworkVersion.' '.$additions,
'debug');
}
public function getLastOperationType()
{
return implode(',', array_keys(array_filter($this->responseStats)));
}
public function __wakeup()
{
parent::__wakeup();
$this->curlInit();
}
}