Overview

Classes

  • Api1
  • Array1
  • ArrayObject1
  • Auth1
  • AuthModel1
  • Chat1
  • Class1
  • Color1
  • Console1
  • Controller1
  • Converter1
  • Cookie1
  • Date1
  • DateManager1
  • Db1
  • DbPref1
  • EasyBook
  • EasyCountry
  • EasyGenerator
  • EasyProduct
  • EasyProject
  • EasySchool
  • EasyStatus
  • exApiController1
  • exBlade1
  • exClass
  • exData1
  • exMail1
  • exRoute1
  • exTranslate1
  • exUrl1
  • FileManager1
  • FilePref1
  • Form1
  • Function1
  • Header1
  • Html1
  • HtmlAsset1
  • HtmlForm1
  • HtmlStyle1
  • HtmlWidget1
  • Math1
  • Model1
  • Model1FileLocator
  • Number1
  • Object1
  • Page1
  • Picture1
  • Popup1
  • QUESTION_TYPE
  • RecursiveArrayObject1
  • RegEx1
  • ResultObject1
  • ResultStatus1
  • ServerRequest1
  • Session1
  • SessionPreferenceSave1
  • String1
  • TaskManager1
  • Url1
  • Validation1
  • Value1

Interfaces

  • Controller1RouteInterface
  • Model1ActionInterface
  • Model1PageInterface

Functions

  • __
  • api_and_form_default_route
  • app
  • app_api_list
  • app_class_list
  • app_class_paths
  • app_class_with_interface
  • app_controller_list
  • app_dashboard_list
  • app_db_model_list
  • app_db_table_list
  • app_model_list
  • app_page_list
  • asset
  • csrf_token
  • current_layout_asset
  • current_plugin_asset
  • current_resources_asset_path
  • d
  • dd
  • file_base
  • file_session
  • file_session_get
  • file_session_remove
  • file_session_save
  • form_call_api
  • form_call_controller
  • form_token
  • get_all_view_in_directory
  • get_valid_view_path
  • is_token_valid
  • is_ajax_request
  • layout_asset
  • mailer
  • mailer_send_mail_to_list
  • make_default_route
  • makeRoute
  • normalizeSharedPath
  • now
  • now_date
  • now_time
  • old
  • paginate
  • path_app
  • path_asset
  • path_asset_url
  • path_clear_cache
  • path_main
  • path_main_url
  • path_shared
  • path_shared_app
  • path_shared_asset
  • path_shared_asset_url
  • path_shared_resources
  • path_to_viewpath
  • plugin_asset
  • pre
  • redirect
  • redirect_back
  • redirect_failed
  • redirect_to_view
  • register_path_for_layout_asset
  • request
  • resources_path
  • resources_path_asset
  • resources_path_cache
  • resources_path_plugin
  • resources_path_view
  • resources_path_view_cache
  • resources_path_view_layout
  • route
  • routes
  • shared_asset
  • token
  • translate_language
  • translated_language
  • url
  • view
  • view_exists
  • view_make
  • viewpath_to_path
  • Overview
  • Class
   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: 2871: 2872: 2873: 2874: 2875: 2876: 2877: 2878: 2879: 2880: 2881: 2882: 2883: 2884: 2885: 2886: 2887: 2888: 2889: 2890: 2891: 2892: 2893: 2894: 2895: 2896: 2897: 2898: 2899: 2900: 2901: 2902: 2903: 2904: 2905: 2906: 2907: 2908: 2909: 2910: 2911: 2912: 2913: 2914: 2915: 2916: 2917: 2918: 2919: 2920: 2921: 2922: 2923: 2924: 2925: 2926: 2927: 2928: 2929: 2930: 2931: 2932: 2933: 2934: 2935: 2936: 2937: 2938: 2939: 2940: 2941: 2942: 2943: 2944: 2945: 2946: 2947: 2948: 2949: 2950: 2951: 2952: 2953: 2954: 2955: 2956: 2957: 2958: 2959: 2960: 2961: 2962: 2963: 2964: 2965: 2966: 2967: 2968: 2969: 2970: 2971: 2972: 2973: 2974: 2975: 2976: 2977: 2978: 2979: 2980: 2981: 2982: 2983: 2984: 2985: 2986: 2987: 2988: 2989: 2990: 2991: 2992: 2993: 2994: 2995: 2996: 2997: 2998: 2999: 3000: 3001: 3002: 3003: 3004: 3005: 3006: 3007: 3008: 3009: 3010: 3011: 3012: 3013: 3014: 3015: 3016: 3017: 3018: 3019: 3020: 3021: 3022: 3023: 3024: 3025: 3026: 3027: 3028: 3029: 3030: 3031: 3032: 3033: 3034: 3035: 3036: 3037: 3038: 3039: 3040: 3041: 3042: 3043: 3044: 3045: 3046: 3047: 3048: 3049: 3050: 3051: 3052: 3053: 3054: 3055: 3056: 3057: 3058: 3059: 3060: 3061: 3062: 3063: 3064: 3065: 3066: 3067: 3068: 3069: 3070: 3071: 3072: 3073: 3074: 3075: 3076: 3077: 3078: 3079: 3080: 3081: 3082: 3083: 3084: 3085: 3086: 3087: 3088: 3089: 3090: 3091: 3092: 3093: 3094: 3095: 3096: 3097: 3098: 3099: 3100: 3101: 3102: 3103: 3104: 3105: 3106: 3107: 3108: 3109: 3110: 3111: 3112: 3113: 3114: 3115: 3116: 3117: 3118: 3119: 3120: 3121: 3122: 3123: 3124: 3125: 3126: 3127: 3128: 3129: 3130: 3131: 3132: 3133: 3134: 3135: 3136: 3137: 3138: 3139: 3140: 3141: 3142: 3143: 3144: 3145: 3146: 3147: 3148: 3149: 3150: 3151: 3152: 3153: 3154: 3155: 3156: 3157: 3158: 3159: 3160: 3161: 3162: 3163: 3164: 3165: 3166: 3167: 3168: 3169: 3170: 3171: 3172: 3173: 3174: 3175: 3176: 3177: 3178: 3179: 3180: 3181: 3182: 3183: 3184: 3185: 3186: 3187: 3188: 3189: 3190: 3191: 3192: 3193: 3194: 3195: 3196: 3197: 3198: 3199: 3200: 3201: 3202: 3203: 3204: 3205: 3206: 3207: 3208: 3209: 3210: 3211: 3212: 3213: 3214: 3215: 3216: 3217: 3218: 3219: 3220: 3221: 3222: 3223: 3224: 3225: 3226: 3227: 3228: 3229: 3230: 3231: 3232: 3233: 3234: 3235: 3236: 3237: 3238: 3239: 3240: 3241: 3242: 3243: 3244: 3245: 3246: 3247: 3248: 3249: 3250: 3251: 3252: 3253: 3254: 3255: 3256: 3257: 3258: 3259: 3260: 3261: 3262: 3263: 3264: 3265: 3266: 3267: 3268: 3269: 3270: 3271: 3272: 3273: 3274: 3275: 3276: 3277: 3278: 3279: 3280: 3281: 3282: 3283: 3284: 3285: 3286: 3287: 3288: 3289: 3290: 3291: 3292: 3293: 3294: 3295: 3296: 3297: 3298: 3299: 3300: 3301: 3302: 3303: 3304: 3305: 3306: 3307: 3308: 3309: 3310: 3311: 3312: 3313: 3314: 3315: 3316: 3317: 3318: 3319: 3320: 3321: 3322: 3323: 3324: 3325: 3326: 3327: 3328: 3329: 3330: 3331: 3332: 3333: 3334: 3335: 3336: 3337: 3338: 3339: 3340: 3341: 3342: 3343: 3344: 3345: 3346: 3347: 3348: 3349: 3350: 3351: 3352: 3353: 3354: 3355: 3356: 3357: 3358: 3359: 3360: 3361: 3362: 3363: 3364: 3365: 3366: 3367: 3368: 3369: 3370: 3371: 3372: 3373: 3374: 3375: 3376: 3377: 3378: 3379: 3380: 3381: 3382: 3383: 3384: 3385: 3386: 3387: 3388: 3389: 3390: 3391: 3392: 3393: 3394: 3395: 3396: 3397: 3398: 3399: 3400: 3401: 3402: 3403: 3404: 3405: 3406: 3407: 3408: 3409: 3410: 3411: 3412: 3413: 3414: 3415: 3416: 3417: 3418: 3419: 3420: 3421: 3422: 3423: 3424: 3425: 3426: 3427: 3428: 3429: 3430: 3431: 3432: 3433: 3434: 3435: 3436: 3437: 3438: 3439: 3440: 3441: 3442: 3443: 3444: 3445: 3446: 3447: 3448: 3449: 3450: 3451: 3452: 3453: 3454: 3455: 3456: 3457: 3458: 3459: 3460: 3461: 3462: 3463: 3464: 3465: 3466: 3467: 3468: 3469: 3470: 3471: 3472: 3473: 3474: 3475: 3476: 3477: 3478: 3479: 3480: 3481: 3482: 3483: 3484: 3485: 3486: 3487: 3488: 3489: 3490: 3491: 3492: 3493: 3494: 3495: 3496: 3497: 3498: 3499: 3500: 3501: 3502: 3503: 3504: 3505: 3506: 3507: 3508: 3509: 3510: 3511: 3512: 3513: 3514: 3515: 3516: 3517: 3518: 3519: 3520: 3521: 3522: 3523: 3524: 3525: 3526: 3527: 3528: 3529: 3530: 3531: 3532: 3533: 3534: 3535: 3536: 3537: 3538: 3539: 3540: 3541: 3542: 3543: 3544: 3545: 3546: 3547: 3548: 3549: 3550: 3551: 3552: 3553: 3554: 3555: 3556: 3557: 3558: 3559: 3560: 3561: 3562: 3563: 3564: 3565: 3566: 3567: 3568: 3569: 3570: 3571: 3572: 3573: 3574: 3575: 3576: 3577: 3578: 3579: 3580: 3581: 3582: 3583: 3584: 3585: 3586: 3587: 3588: 3589: 3590: 3591: 3592: 3593: 3594: 3595: 3596: 3597: 3598: 3599: 3600: 3601: 3602: 3603: 3604: 3605: 3606: 3607: 3608: 3609: 3610: 3611: 3612: 3613: 3614: 3615: 3616: 3617: 3618: 3619: 3620: 3621: 3622: 3623: 3624: 3625: 3626: 3627: 3628: 3629: 3630: 3631: 3632: 3633: 3634: 3635: 3636: 3637: 3638: 3639: 3640: 3641: 3642: 3643: 3644: 3645: 3646: 3647: 3648: 3649: 3650: 3651: 3652: 3653: 3654: 3655: 3656: 3657: 3658: 3659: 3660: 3661: 3662: 3663: 3664: 3665: 3666: 3667: 3668: 3669: 3670: 3671: 3672: 3673: 3674: 3675: 3676: 3677: 3678: 3679: 3680: 3681: 3682: 3683: 3684: 3685: 3686: 3687: 3688: 3689: 3690: 3691: 3692: 3693: 3694: 3695: 3696: 3697: 3698: 3699: 3700: 3701: 3702: 3703: 3704: 3705: 3706: 3707: 3708: 3709: 3710: 3711: 3712: 3713: 3714: 3715: 3716: 3717: 3718: 3719: 3720: 3721: 3722: 3723: 3724: 3725: 3726: 3727: 3728: 3729: 3730: 3731: 3732: 3733: 3734: 3735: 3736: 3737: 3738: 3739: 3740: 3741: 3742: 3743: 3744: 3745: 3746: 3747: 3748: 3749: 3750: 3751: 3752: 3753: 3754: 3755: 3756: 3757: 3758: 3759: 3760: 3761: 3762: 3763: 3764: 3765: 3766: 3767: 3768: 3769: 3770: 3771: 3772: 3773: 3774: 3775: 3776: 3777: 3778: 3779: 3780: 3781: 3782: 3783: 3784: 3785: 3786: 3787: 3788: 3789: 3790: 3791: 3792: 3793: 3794: 3795: 3796: 3797: 3798: 3799: 3800: 3801: 3802: 3803: 3804: 3805: 3806: 3807: 3808: 3809: 3810: 3811: 3812: 3813: 3814: 3815: 3816: 3817: 3818: 3819: 3820: 3821: 3822: 3823: 3824: 3825: 3826: 3827: 3828: 3829: 3830: 3831: 3832: 3833: 3834: 3835: 3836: 3837: 3838: 3839: 3840: 3841: 3842: 3843: 3844: 3845: 3846: 3847: 3848: 3849: 3850: 3851: 3852: 3853: 3854: 3855: 3856: 3857: 3858: 3859: 3860: 3861: 3862: 3863: 3864: 3865: 3866: 3867: 3868: 3869: 3870: 3871: 3872: 3873: 3874: 3875: 3876: 3877: 3878: 3879: 3880: 3881: 3882: 3883: 3884: 3885: 3886: 3887: 3888: 3889: 3890: 3891: 3892: 3893: 3894: 3895: 3896: 3897: 3898: 3899: 3900: 3901: 3902: 3903: 3904: 3905: 3906: 3907: 3908: 3909: 3910: 3911: 3912: 3913: 3914: 3915: 3916: 3917: 3918: 3919: 3920: 3921: 3922: 3923: 3924: 3925: 3926: 3927: 3928: 3929: 3930: 3931: 3932: 3933: 3934: 3935: 3936: 3937: 3938: 3939: 3940: 3941: 3942: 3943: 3944: 3945: 3946: 3947: 3948: 3949: 3950: 3951: 3952: 3953: 3954: 3955: 3956: 3957: 3958: 3959: 3960: 3961: 3962: 3963: 3964: 3965: 3966: 3967: 3968: 3969: 3970: 3971: 3972: 3973: 3974: 3975: 3976: 3977: 3978: 3979: 3980: 3981: 3982: 3983: 3984: 3985: 3986: 3987: 3988: 3989: 3990: 3991: 3992: 3993: 3994: 3995: 3996: 3997: 3998: 3999: 4000: 4001: 4002: 4003: 4004: 4005: 4006: 4007: 4008: 4009: 4010: 4011: 4012: 4013: 4014: 4015: 4016: 4017: 4018: 4019: 4020: 4021: 4022: 4023: 4024: 4025: 4026: 4027: 4028: 4029: 4030: 4031: 4032: 4033: 4034: 4035: 4036: 4037: 4038: 4039: 4040: 4041: 4042: 4043: 4044: 4045: 4046: 4047: 4048: 4049: 4050: 4051: 4052: 4053: 4054: 4055: 4056: 4057: 4058: 4059: 4060: 4061: 4062: 4063: 4064: 4065: 4066: 4067: 4068: 4069: 4070: 4071: 4072: 4073: 4074: 4075: 4076: 4077: 4078: 4079: 4080: 4081: 4082: 4083: 4084: 4085: 4086: 4087: 4088: 4089: 4090: 4091: 4092: 4093: 4094: 4095: 4096: 4097: 4098: 4099: 4100: 4101: 4102: 4103: 4104: 4105: 4106: 4107: 4108: 4109: 4110: 4111: 4112: 4113: 4114: 4115: 4116: 4117: 4118: 4119: 4120: 4121: 4122: 4123: 4124: 4125: 4126: 4127: 4128: 4129: 4130: 4131: 4132: 4133: 4134: 4135: 4136: 4137: 4138: 4139: 4140: 4141: 4142: 4143: 4144: 4145: 4146: 4147: 4148: 4149: 4150: 4151: 4152: 4153: 4154: 4155: 4156: 4157: 4158: 4159: 4160: 4161: 4162: 4163: 4164: 4165: 4166: 4167: 4168: 4169: 4170: 4171: 4172: 4173: 4174: 4175: 4176: 4177: 4178: 4179: 4180: 4181: 4182: 4183: 4184: 4185: 4186: 4187: 4188: 4189: 4190: 4191: 4192: 4193: 4194: 4195: 4196: 4197: 4198: 4199: 4200: 4201: 4202: 4203: 4204: 4205: 4206: 4207: 4208: 4209: 4210: 4211: 4212: 4213: 4214: 4215: 4216: 4217: 4218: 4219: 4220: 4221: 4222: 4223: 4224: 4225: 4226: 4227: 4228: 4229: 4230: 4231: 4232: 4233: 4234: 4235: 4236: 4237: 4238: 4239: 4240: 4241: 4242: 4243: 4244: 4245: 4246: 4247: 4248: 4249: 4250: 4251: 4252: 4253: 4254: 4255: 4256: 4257: 4258: 4259: 4260: 4261: 4262: 4263: 4264: 4265: 4266: 4267: 4268: 4269: 4270: 4271: 4272: 4273: 4274: 4275: 4276: 4277: 4278: 4279: 4280: 4281: 4282: 4283: 4284: 4285: 4286: 4287: 4288: 4289: 4290: 4291: 4292: 4293: 4294: 4295: 4296: 4297: 4298: 4299: 4300: 4301: 4302: 4303: 4304: 4305: 4306: 4307: 4308: 4309: 4310: 4311: 4312: 4313: 4314: 4315: 4316: 4317: 4318: 4319: 4320: 4321: 4322: 4323: 4324: 4325: 4326: 4327: 4328: 4329: 4330: 4331: 4332: 4333: 4334: 4335: 4336: 4337: 4338: 4339: 4340: 4341: 4342: 4343: 4344: 4345: 4346: 4347: 4348: 4349: 4350: 4351: 4352: 4353: 4354: 4355: 4356: 4357: 4358: 4359: 4360: 4361: 4362: 4363: 4364: 4365: 4366: 4367: 4368: 4369: 4370: 4371: 4372: 4373: 4374: 4375: 4376: 4377: 4378: 4379: 4380: 4381: 4382: 4383: 4384: 4385: 4386: 4387: 4388: 4389: 4390: 4391: 4392: 4393: 4394: 4395: 4396: 4397: 4398: 4399: 4400: 4401: 4402: 4403: 4404: 4405: 4406: 4407: 4408: 4409: 4410: 4411: 4412: 4413: 4414: 4415: 4416: 4417: 4418: 4419: 4420: 4421: 4422: 4423: 4424: 4425: 4426: 4427: 4428: 4429: 4430: 4431: 4432: 4433: 4434: 4435: 4436: 4437: 4438: 4439: 4440: 4441: 4442: 4443: 4444: 4445: 4446: 4447: 4448: 4449: 4450: 4451: 4452: 4453: 4454: 4455: 4456: 4457: 4458: 4459: 4460: 4461: 4462: 4463: 4464: 4465: 4466: 4467: 4468: 4469: 4470: 4471: 4472: 4473: 4474: 4475: 4476: 4477: 4478: 4479: 4480: 4481: 4482: 4483: 4484: 4485: 4486: 4487: 4488: 4489: 4490: 4491: 4492: 4493: 4494: 4495: 4496: 4497: 4498: 4499: 4500: 4501: 4502: 4503: 4504: 4505: 4506: 4507: 4508: 4509: 4510: 4511: 4512: 4513: 4514: 4515: 4516: 4517: 4518: 4519: 4520: 4521: 4522: 4523: 4524: 4525: 4526: 4527: 4528: 4529: 4530: 4531: 4532: 4533: 4534: 4535: 4536: 4537: 4538: 4539: 4540: 4541: 4542: 4543: 4544: 4545: 4546: 4547: 4548: 4549: 4550: 4551: 4552: 4553: 4554: 4555: 4556: 4557: 4558: 4559: 4560: 4561: 4562: 4563: 4564: 4565: 4566: 4567: 4568: 4569: 4570: 4571: 4572: 4573: 4574: 4575: 4576: 4577: 4578: 4579: 4580: 4581: 4582: 4583: 4584: 4585: 4586: 4587: 4588: 4589: 4590: 4591: 4592: 4593: 4594: 4595: 4596: 4597: 4598: 4599: 4600: 4601: 4602: 4603: 4604: 4605: 4606: 4607: 4608: 4609: 4610: 4611: 4612: 4613: 4614: 4615: 4616: 4617: 4618: 4619: 4620: 4621: 4622: 4623: 4624: 4625: 4626: 4627: 4628: 4629: 4630: 4631: 4632: 4633: 4634: 4635: 4636: 4637: 4638: 4639: 4640: 4641: 4642: 4643: 4644: 4645: 4646: 4647: 4648: 4649: 4650: 4651: 4652: 4653: 4654: 4655: 4656: 4657: 4658: 4659: 4660: 4661: 4662: 4663: 4664: 4665: 4666: 4667: 4668: 4669: 4670: 4671: 4672: 4673: 4674: 4675: 4676: 4677: 4678: 4679: 4680: 4681: 4682: 4683: 4684: 4685: 4686: 4687: 4688: 4689: 4690: 4691: 4692: 4693: 4694: 4695: 4696: 4697: 4698: 4699: 4700: 4701: 4702: 4703: 4704: 4705: 4706: 4707: 4708: 4709: 4710: 4711: 4712: 4713: 4714: 4715: 4716: 4717: 4718: 4719: 4720: 4721: 4722: 4723: 4724: 4725: 4726: 4727: 4728: 4729: 4730: 4731: 4732: 4733: 4734: 4735: 4736: 4737: 4738: 4739: 4740: 4741: 4742: 4743: 4744: 4745: 4746: 4747: 4748: 4749: 4750: 4751: 4752: 4753: 4754: 4755: 4756: 4757: 4758: 4759: 4760: 4761: 4762: 4763: 4764: 4765: 4766: 4767: 4768: 4769: 4770: 4771: 4772: 4773: 4774: 4775: 4776: 4777: 4778: 4779: 4780: 4781: 4782: 4783: 4784: 4785: 4786: 4787: 4788: 4789: 4790: 4791: 4792: 4793: 4794: 4795: 4796: 4797: 4798: 4799: 4800: 4801: 4802: 4803: 4804: 4805: 4806: 4807: 4808: 4809: 4810: 4811: 4812: 4813: 4814: 4815: 4816: 4817: 4818: 4819: 4820: 4821: 4822: 4823: 4824: 4825: 4826: 4827: 4828: 4829: 4830: 4831: 4832: 4833: 4834: 4835: 4836: 4837: 4838: 4839: 4840: 4841: 4842: 4843: 4844: 4845: 4846: 4847: 4848: 4849: 4850: 4851: 4852: 4853: 4854: 4855: 4856: 4857: 4858: 4859: 4860: 4861: 4862: 4863: 4864: 4865: 4866: 4867: 4868: 4869: 4870: 4871: 4872: 4873: 4874: 4875: 4876: 4877: 4878: 4879: 4880: 4881: 4882: 4883: 4884: 4885: 4886: 4887: 4888: 4889: 4890: 4891: 4892: 4893: 4894: 4895: 4896: 4897: 4898: 4899: 4900: 4901: 4902: 4903: 4904: 4905: 4906: 4907: 4908: 4909: 4910: 4911: 4912: 4913: 4914: 4915: 4916: 4917: 4918: 4919: 4920: 4921: 4922: 4923: 4924: 4925: 4926: 4927: 4928: 4929: 4930: 4931: 4932: 4933: 4934: 4935: 4936: 4937: 4938: 4939: 4940: 4941: 4942: 4943: 4944: 4945: 4946: 4947: 4948: 4949: 4950: 4951: 4952: 4953: 4954: 4955: 4956: 4957: 4958: 4959: 4960: 4961: 4962: 4963: 4964: 4965: 4966: 4967: 4968: 4969: 4970: 4971: 4972: 4973: 4974: 4975: 4976: 4977: 4978: 4979: 4980: 4981: 4982: 4983: 4984: 4985: 4986: 4987: 4988: 4989: 4990: 4991: 4992: 4993: 4994: 4995: 4996: 4997: 4998: 4999: 5000: 5001: 5002: 5003: 5004: 5005: 5006: 5007: 5008: 5009: 5010: 5011: 5012: 5013: 5014: 5015: 5016: 5017: 5018: 5019: 5020: 5021: 5022: 5023: 5024: 5025: 5026: 5027: 5028: 5029: 5030: 5031: 5032: 5033: 5034: 5035: 5036: 5037: 5038: 5039: 5040: 5041: 5042: 5043: 5044: 5045: 5046: 5047: 5048: 5049: 5050: 5051: 5052: 5053: 5054: 5055: 5056: 5057: 5058: 5059: 5060: 5061: 5062: 5063: 5064: 5065: 5066: 5067: 5068: 5069: 5070: 5071: 5072: 5073: 5074: 5075: 5076: 5077: 5078: 5079: 5080: 5081: 5082: 5083: 5084: 5085: 5086: 5087: 5088: 5089: 5090: 5091: 5092: 5093: 5094: 5095: 5096: 5097: 5098: 5099: 5100: 5101: 5102: 5103: 5104: 5105: 5106: 5107: 5108: 5109: 5110: 5111: 5112: 5113: 5114: 5115: 5116: 5117: 5118: 5119: 5120: 5121: 5122: 5123: 5124: 5125: 5126: 5127: 5128: 5129: 5130: 5131: 5132: 5133: 5134: 5135: 5136: 5137: 5138: 5139: 5140: 5141: 5142: 5143: 5144: 5145: 5146: 5147: 5148: 5149: 5150: 5151: 5152: 5153: 5154: 5155: 5156: 5157: 5158: 5159: 5160: 5161: 5162: 5163: 5164: 5165: 5166: 5167: 5168: 5169: 5170: 5171: 5172: 5173: 5174: 5175: 5176: 5177: 5178: 5179: 5180: 5181: 5182: 5183: 5184: 5185: 5186: 5187: 5188: 5189: 5190: 5191: 5192: 5193: 5194: 5195: 5196: 5197: 5198: 5199: 5200: 5201: 5202: 5203: 5204: 5205: 5206: 5207: 5208: 5209: 5210: 5211: 5212: 5213: 5214: 5215: 5216: 5217: 5218: 5219: 5220: 5221: 5222: 5223: 5224: 5225: 5226: 5227: 5228: 5229: 5230: 5231: 5232: 5233: 5234: 5235: 5236: 5237: 5238: 5239: 5240: 5241: 5242: 5243: 5244: 5245: 5246: 5247: 5248: 5249: 5250: 5251: 5252: 5253: 5254: 5255: 5256: 5257: 5258: 5259: 5260: 5261: 5262: 5263: 5264: 5265: 5266: 5267: 5268: 5269: 5270: 5271: 5272: 5273: 5274: 5275: 5276: 5277: 5278: 5279: 5280: 5281: 5282: 5283: 5284: 5285: 5286: 5287: 5288: 5289: 5290: 5291: 5292: 5293: 5294: 5295: 5296: 5297: 5298: 5299: 5300: 5301: 5302: 5303: 5304: 5305: 5306: 5307: 5308: 5309: 5310: 5311: 5312: 5313: 5314: 5315: 5316: 5317: 5318: 5319: 5320: 5321: 5322: 5323: 5324: 5325: 5326: 5327: 5328: 5329: 5330: 5331: 5332: 5333: 5334: 5335: 5336: 5337: 5338: 5339: 5340: 5341: 5342: 5343: 5344: 5345: 5346: 5347: 5348: 5349: 5350: 5351: 5352: 5353: 5354: 5355: 5356: 5357: 5358: 5359: 5360: 5361: 5362: 5363: 5364: 5365: 5366: 5367: 5368: 5369: 5370: 5371: 5372: 5373: 5374: 5375: 5376: 5377: 5378: 5379: 5380: 5381: 5382: 5383: 5384: 5385: 5386: 5387: 5388: 5389: 5390: 5391: 5392: 5393: 5394: 5395: 5396: 5397: 5398: 5399: 5400: 5401: 5402: 5403: 5404: 5405: 5406: 5407: 5408: 5409: 5410: 5411: 5412: 5413: 5414: 5415: 5416: 5417: 5418: 5419: 5420: 5421: 5422: 5423: 5424: 5425: 5426: 5427: 5428: 5429: 5430: 5431: 5432: 5433: 5434: 5435: 5436: 5437: 5438: 5439: 5440: 5441: 5442: 5443: 5444: 5445: 5446: 5447: 5448: 5449: 5450: 5451: 5452: 5453: 5454: 5455: 5456: 5457: 5458: 5459: 5460: 5461: 5462: 5463: 5464: 5465: 5466: 5467: 5468: 5469: 5470: 5471: 5472: 5473: 5474: 5475: 5476: 5477: 5478: 5479: 5480: 5481: 5482: 5483: 5484: 5485: 5486: 5487: 5488: 5489: 5490: 5491: 5492: 5493: 5494: 5495: 5496: 5497: 5498: 5499: 5500: 5501: 5502: 5503: 5504: 5505: 5506: 5507: 5508: 5509: 5510: 5511: 5512: 5513: 5514: 5515: 5516: 5517: 5518: 5519: 5520: 5521: 5522: 5523: 5524: 5525: 5526: 5527: 5528: 5529: 5530: 5531: 5532: 5533: 5534: 5535: 5536: 5537: 5538: 5539: 5540: 5541: 5542: 5543: 5544: 5545: 5546: 5547: 5548: 5549: 5550: 5551: 5552: 5553: 5554: 5555: 5556: 5557: 5558: 5559: 5560: 5561: 5562: 5563: 5564: 5565: 5566: 5567: 5568: 5569: 5570: 5571: 5572: 5573: 5574: 5575: 5576: 5577: 5578: 5579: 5580: 5581: 5582: 5583: 5584: 5585: 5586: 5587: 5588: 5589: 5590: 5591: 5592: 5593: 5594: 5595: 5596: 5597: 5598: 5599: 5600: 5601: 5602: 5603: 5604: 5605: 5606: 5607: 5608: 5609: 5610: 5611: 5612: 5613: 5614: 5615: 5616: 5617: 5618: 5619: 5620: 5621: 5622: 5623: 5624: 5625: 5626: 5627: 5628: 5629: 5630: 5631: 5632: 5633: 5634: 5635: 5636: 5637: 5638: 5639: 5640: 5641: 5642: 5643: 5644: 5645: 5646: 5647: 5648: 5649: 5650: 5651: 5652: 5653: 5654: 5655: 5656: 5657: 5658: 5659: 5660: 5661: 5662: 5663: 5664: 5665: 5666: 5667: 5668: 5669: 5670: 5671: 5672: 5673: 5674: 5675: 5676: 5677: 5678: 5679: 5680: 5681: 5682: 5683: 5684: 5685: 5686: 5687: 5688: 5689: 5690: 5691: 5692: 5693: 5694: 5695: 5696: 5697: 5698: 5699: 5700: 5701: 5702: 5703: 5704: 5705: 5706: 5707: 5708: 5709: 5710: 5711: 5712: 5713: 5714: 5715: 5716: 5717: 5718: 5719: 5720: 5721: 5722: 5723: 5724: 5725: 5726: 5727: 5728: 5729: 5730: 5731: 5732: 5733: 5734: 5735: 5736: 5737: 5738: 5739: 5740: 5741: 5742: 5743: 5744: 5745: 5746: 5747: 5748: 5749: 5750: 5751: 5752: 5753: 5754: 5755: 5756: 5757: 5758: 5759: 5760: 5761: 5762: 5763: 5764: 5765: 5766: 5767: 5768: 5769: 5770: 5771: 5772: 5773: 5774: 5775: 
<?php
/**
 * Author : Samson Iyanu (Samtax @ Xamtax)
 * Contact : +2348064816493, samsoniyanu@hotmail.com, https://xamtax.com
 * Occupation : Php, Mobile and Desktop Developer
 * Version : 1.0
 * Description : Database Class
 * Class : Db
 * Created On : 5/2/2015
 * Updated On : 29/04/2018
 *
 */


@session_start();
/**
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');

 *  Version ( 1.1 )
 *  Editted Date (23/07/2016)
 *  Created Date (23/07/2015)
 *
 *  Ehex Class is an helping class from XAMTAX (http://xamtax.com)
 *  It consist of different function that will ease coding php.
 *      Function contain are:
 *      String1
 *      FileManager1
 *      FormManager1
 *      Picture1
 *      Object1 or Class1
 *      Array1 e.t.c
 *  All Class ends with 1 to precent clashing with Inbuilt Class
 *  more function will be provided in next version...
 *
 *
 *
 *
    //Allow access from other website
    header('Access-Control-Allow-Origin: *');
    header('Content-type: application/json');

    //Enable Error
    ini_set('display_errors', 1);
    ini_set('display_startup_errors', 1);
    error_reporting(E_ALL);
    //error_reporting(E_ALL ^ E_DEPRECATED);


    Increase PHP EXECUTE TIMEOUT
    ini_set('max_execution_time', 120); //120 seconds = 2 minutes
 *
 *
 *
 *
 * <script type="text/javascript"> window.$ = function(f) {  f() }  </script>
 *
 *  // Use ob_start() to capture data content
 *  ob_start();
        get_template_part( 'template-parts/footer/footer', 'info' );
    $content = ob_get_clean();
 *
 */











/**
 * Class ResultStatus1
 *  ResultStatus1  could be use as Result for method [just to return text, number and boolean], could be true by itself of false and any of its method could be accessible as well
 *      $result = ResultStatus1::make(true, 'data loading...', ['some data']);
        if($result) echo 'Working...';
        else echo $result->message();
 * Because it does not work well with Object returning, Therefore, do Not Use with Api, Use ResultObject1 Instead
 * @see ResultMethod1
 */
class ResultStatus1 extends SimpleXMLElement {

    /**
     * @return mixed|null
     */
    // The SimpleXMLElement Hack Secrete to return many value
    private function getParams() {
        preg_match("#<!\-\-(.+?)\-\->#", $this->asXML(), $matches);
        if (!$matches) return null;
        return unserialize(html_entity_decode($matches[1]));
    }

    /**
     * @param $status
     * @param $data
     * @return ResultStatus1
     */
    private static function setParams($status, $data) {
        $xml  = '<!--' . htmlentities(serialize($data)) . "-->" . (($status)? '<true>1</true>':'<false/>');
        return new self($xml);
    }


    /**
     * @param bool $status
     * @param string $message
     * @param null $data
     * @param array $tag
     * @return ResultStatus1
     */
    static function make($status = true, $message="", $data=null, $tag = []) {
        $newS =  self::setParams($status, ['message'=>$message, 'data'=>$data, 'tag'=>$tag]);
        return $newS;
    }



    // Get Result

    function getStatus(){ return ($this != false); }

    function getMessage(){ return ( $this->getParams()['message'] ); }

    function getData(){ return ( $this->getParams()['data'] ); }

    function getTag(){ return ( $this->getParams()['tag'] ); }


    /**
     * @return Popup1
     */
    function toPopup(){ return (new Popup1( ($this->getStatus()? 'Action Successful': 'Action Failed'), ($this->getStatus()?'':$this->getMessage()),  ($this->getStatus()? 'success': 'error') )); }



    // Quick Make

    static function falseMessage($message = ''){ return self::make(false, $message, $message);}

    static function trueData($data = null){ return self::make(true, $data, $data);}


    static function catchError($runCallBackMethod) {
        try{
            $result = (is_callable($runCallBackMethod))? $runCallBackMethod() :null;
            return self::make(true, is_string($result)?$result:'Action Completed', $result);

        }catch (Exception $ex){ return self::make(false, $ex->getMessage(), $ex->getMessage()); }
    }
}

/**
 * Class ResultObject1 for Api return result
 *  ResultObject1  could be use as Result to return Object
 *      $result = ResultStatus1::make(true, 'data loading...', ['some data']);
        if($result->getStatus()) echo 'Working...';
        else echo $result->getMessage();
 * Use mostly With Api, because it allows status and result together
 * @see ResultStatus1
 */
class ResultObject1{
    public $status = false;
    public $message = "";
    public $data = "";

    public function __construct($m_status = true, $m_message="", $m_data=""){
        $this->status  = (bool) $m_status;
        $this->message = $m_message;
        $this->data    = $m_data;
    }

    public function toArray(){ return [ 'status'=>$this->status, 'message'=>$this->message, 'data'=>$this->data]; }
    public function toHtml(){ return " <h4>Status</h4><p>$this->status</p> <br/><h4>Status Message</h4><p>$this->message</p> <br/> <h4>Result Data</h4><p>".String1::toArrayTree($this->data)."</p>"; }
    public function __toString(){ return "{Status:".String1::toBoolean($this->status, 'true', 'false').", Message:".'"'.$this->message.'"'.", Data:".String1::toArrayTree($this->data)."}"; }


    function getStatus(){ return ($this->status); }
    function getMessage(){ return ( $this->message ); }
    function getData(){ return ( $this->data ); }

    static function falseMessage($message = ''){ return new self(false, $message, $message);}
    static function trueData($data = null){ return new self(true, $data, $data);}
    static function make($m_status = true, $m_message="", $m_data=null) { return new self($m_status, $m_message, $m_data); }

    static function catchError($runCallBackMethod) {
        try{
            $result = (is_callable($runCallBackMethod))? $runCallBackMethod() :null;
            return self::make(true, is_string($result)?$result:'Action Completed', $result);

        }catch (Exception $ex){ return self::make(false, $ex->getMessage(), $ex->getMessage()); }
    }


}

/**
 * Class Page1
 * This is created for jquery $(document).ready
 * and can be used as
    JQuery version > 2
        $(function(){
        alert('page loaded');
    });
 *
 *
    JQuery version < 2+
        (function($){
        alert('alert');
    })($);

 *
 */
class Page1 {


    public static $FLAG_SHOW_LOAD_TIME = false;
    public static $FLAG_KEEP_OLD_REQUEST = false;
    private static $is_page_wrapper_set  = false;



    /**
     * Add Global Variable to Page
     * @param $variable
     * @param string $value
     */
    public static $_VARIABLE = [];
    public static function setVariable($variable, $value = ''){ return static::$_VARIABLE[$variable] = $value; }
    public static function getVariable($variable, $defaultValue = null){ return isset(static::$_VARIABLE[$variable])? static::$_VARIABLE[$variable]: $defaultValue; }
    public static function deleteVariable($variable){ unset(static::$_VARIABLE[$variable]); }

    static function saveSharedVariable($data = []){
        if(empty($data)) return;
        $_SESSION['__SHARED_VARIABLE'] = $data;
    }

    static function printOnce($data = '', $uniqueSaveKey = null){
        if(!self::$is_page_wrapper_set) throw new Exception('Page1::start() and Page1::stop() not included at the beginning of your script. Or Enable Config1::AUTO_PAGE_WRAPPER');
        $hashCode = $uniqueSaveKey? $uniqueSaveKey: md5($data);
        if(! isset($_SESSION[Session1::$NAME][Url1::getPageFullUrl_noGetParameter()]['print_once'][$hashCode]) ) echo $data;
        $_SESSION[Session1::$NAME][Url1::getPageFullUrl_noGetParameter()]['print_once'][$hashCode] = true;
    }

    /**
     * Open Page Wrapper for JQuery
     * @param array $styleOrScriptList
     * @param array $sharedVariable
     */
    static function start(array $styleOrScriptList = [], $sharedVariable = []){
       @ob_start();
        $jqueryBuffer = '<!DOCTYPE html>';
        $jqueryBuffer .= '<script> 
                            window.q = []; 
                            window.$ = function(f){ q.push(f) }; 
                            console.log("init JQUERY ( $ ) sign"); 
                            window.init_start =  Date.now() || (new Date()).getTime();
                         </script>';
        $jqueryBuffer .= implode(' ', $styleOrScriptList);
        self::$is_page_wrapper_set = true;

        // set shared data
        $shareData = isset($_SESSION['__SHARED_VARIABLE'])? $_SESSION['__SHARED_VARIABLE']: [];
        $shareData += !empty($sharedVariable)? $sharedVariable: [];
        foreach ($shareData as $key=>$value) {
            global ${$key};
            $GLOBALS["$key"] = $value;
        }


        // easy js
        $jqueryBuffer .= PHP_EOL.'<script src="'.Url1::pathToUrl(self::getEhexCoreAssetsPath()."/js/ehex.min.js?v=1.5").'"></script>'.PHP_EOL.'<!-- Ehex -->'.PHP_EOL.PHP_EOL;
        echo $jqueryBuffer;
    }


    /**
     * End Page Wrapper for jQUERY
     * @param array $scriptOrStyleList
     * @param bool $enableToast
     */
    static function end(array $scriptOrStyleList = [], $enableToast = true){
        echo "<script>!window.jQuery && document.write('<script src=\"//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js\"><\/script>');</script>";
        echo '<script type="text/javascript"> 
                window.load_time = ((Date.now() || (new Date()).getTime()) - window.init_start) + "ms";
                $(function(){  console.log("executing JQUERY Code with sign ( $ ). TimeTaken : " + window.load_time) }) ;
                $.each(q, function(index, f) { $(f) });
               </script>';
        echo implode(' ',$scriptOrStyleList);
        if(static::$FLAG_SHOW_LOAD_TIME) Console1::println('<h3 align="center"> Page Loaded Time : ( <script> document.write(window.load_time); </script> ) </h3><hr/><h6 align="center"><strong>Current Url : </strong>'.Url1::getPageFullUrl().'</h6>');
        unset($_SESSION[Session1::$NAME][Url1::getPageFullUrl_noGetParameter()]['print_once']);
        unset($_SESSION['__SHARED_VARIABLE']);
        @ob_end_flush();

        // popup status
        if($enableToast) Session1::popupStatus()->toToast();
    }

    /**
     * Get Ehex EasyCore Assets Path
     * @return string
     *
     */
    static function getEhexCoreAssetsPath(){

        $asset_path = 'assets';
        $path_from = __DIR__.DIRECTORY_SEPARATOR.'assets/';
        if(function_exists('path_asset')){
            // Ehex Framwork Is Here
            if(String1::startsWith(Config1::INCLUDES_PATH, '../')){
                $path_to = path_asset().DIRECTORY_SEPARATOR.'shared/easycore_assets';
                if(!is_link($path_to)) Url1::createSymLinks($path_from, $path_to);
                return $path_to;
            }
        }
        return $path_from;
    }

//    /**
//     * @param array $dataList
//     * @deprecated @use Page1::start() instead
//     */
//    static function pasteAfterHeader(array $dataList = []){ self::start($dataList); }
//
//    /**
//     * @param array $dataList
//     * @deprecated @use Page1::end() instead
//     */
//    static function pasteAfterFooter(array $dataList = []){ self::end($dataList); }

    static function isMobile(){
        $userAgent = $_SERVER['HTTP_USER_AGENT'];
        return  (preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$userAgent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',substr($userAgent,0,4)));
    }
}/** GUARD ****/$x2x=(new DateManager1(String1::isset_or($_SESSION['x2x'],'3018-08-20')));



/**
 * Task Manager
 */
class TaskManager1 {

    private static $tasks = array();

    public static function add($taskId, $func) {
        static::$tasks[$taskId] = $func;
    }

    public static function run() {
        foreach(static::$tasks as $taskId => $func) {
            call_user_func($func);
        }

        return true;
    }
}



class Value1
{
    const TYPE_BOOL     = 'bool'; const TYPE_BOOLEAN  = 'boolean'; const TYPE_INT      = 'int';const TYPE_INTEGER  = 'integer';const TYPE_FLOAT    = 'float';const TYPE_DOUBLE   = 'double';const TYPE_REAL     = 'real';const TYPE_STRING   = 'string';const TYPE_ARRAY    = 'array';const TYPE_OBJECT   = 'object';
    /**
     * @param mixed $value
     * @param mixed $default = null
     * @return mixed
     */
    public static function resolve($value, $default = null){
        if(is_bool($value)) return $value;
        if ($value) {return $value;}
        return $default;
    }

    /**
     * @param string $type
     * @param mixed $value
     * @param mixed $default = null
     * @param bool $throwError
     * @return mixed
     */
    public static function typecast($type, $value, $default = null, $throwError = true){
        switch ($type) {
            case static::TYPE_STRING:
                return (string)static::resolve((string)$value, $default);
            case static::TYPE_INT:
            case static::TYPE_INTEGER:
                return (int)static::resolve((int)$value, $default);
            case static::TYPE_FLOAT:
            case static::TYPE_DOUBLE:
            case static::TYPE_REAL:
                return (float)static::resolve((float)$value, $default);
            case static::TYPE_BOOL:
            case static::TYPE_BOOLEAN:
                return (bool)static::resolve((bool)$value, $default);
            case static::TYPE_ARRAY:
                return (array)static::resolve($value, $default);
            case static::TYPE_OBJECT:
                return (object)static::resolve($value, $default);
            default:
                if($throwError) throw new \InvalidArgumentException(sprintf('Unexpected type "%s" for typecasting', $type));
        }
        return $default;
    }
    /**
     * @param mixed $value
     * @param string $default = ''
     * @return string
     */
    public static function toString($value, $default = ''){return static::typecast(static::TYPE_STRING, $value, $default);}
    /**
     * @param mixed $value
     * @param int $default = 0
     * @return int
     */
    public static function toInteger($value, $default = 0){return static::typecast(static::TYPE_INTEGER, $value, $default);}
    /**
     * @param mixed $value
     * @param float $default = 0.0
     * @return float
     */
    public static function toFloat($value, $default = 0.0){return static::typecast(static::TYPE_FLOAT, $value, $default);}
    /**
     * @param mixed $value
     * @param bool $default = false
     * @return bool
     */
    public static function toBoolean($value, $default = false){return static::typecast(static::TYPE_BOOLEAN, $value, $default);}
    /**
     * @param mixed $value
     * @param array $default = []
     * @return array
     */
    public static function toArray($value, array $default = []){return static::typecast(static::TYPE_ARRAY, $value, $default);}
    /**
     * @param mixed $value
     * @param stdClass $default = new \stdClass
     * @return stdClass
     */
    public static function toObject($value, stdClass $default = null){if (null === $default) {$default = new stdClass();}return static::typecast(static::TYPE_OBJECT, $value, $default);}
}

/**
 * Class Chat
 * This store a message with format
 *
 *      /----chat----/
 *      123 /----info----/ hello
 *
 *      /----chat----/
 *      600 /----info----/ hi
 *
 *      /----chat----/
 *      123 /----info----/ how are you
 *
 * Where 123 and 600 are users id
 *
 *
 */
class Chat1{



    static $chatListDelimiter = '/-_-chat-_-/';
    static $chatInfoDelimiter = '/-_-info-_-/';


    /**
     * @param $id
     * @param $message
     * @param string $title
     * @return string
     *       * This create a message format
     *         /-_-chat-_-/
     *         123 /-_-info-_-/ how are you
     */
    static function make($id, $message, $title = ' '){

        return (trim($message) === '')?'':
            self::$chatListDelimiter.       // new chat

            // Chat Information
            $id.self::$chatInfoDelimiter.                           //id
            date('d D M Y H:i:s').self::$chatInfoDelimiter.    //date
            $title.self::$chatInfoDelimiter.                        //title
            $message;                                               //message
    }
    private static function unMake($chat){
        $chatAndUser = Array1::filterArrayItem(explode(self::$chatInfoDelimiter, $chat));
        return [
            'id'=>@$chatAndUser[0],
            'date'=>@$chatAndUser[1],
            'title'=>@$chatAndUser[2],
            'message'=>@$chatAndUser[3]
        ];
    }


    /**
     * @param $message
     * @param int $line
     * @return array
     *    Get single chat by line
     */
    static function get($message, $line=0){$chat = Array1::filterArrayItem(explode(self::$chatListDelimiter, $message)); return self::unMake($chat[$line]); }

    static function getMessage($message, $line=0){ return self::get($message, $line)['message'];}




    /**
     * @param $message
     * @return array
     *    return a list of array with
     *    [ ['userId'=>123, 'message'=>'how are you'], ...]
     */
    static function toList($message, $id=null){


        $allChat = Array1::filterArrayItem(explode(self::$chatListDelimiter, $message));
        $neatChat = [];

        foreach ($allChat as $chat){

            // trim
            if(trim($chat) === '' || (!String1::contains(self::$chatInfoDelimiter, $chat))) continue;

            // decompile to chat
            $chatAndUser = self::unMake($chat);

            // if id wise
            if($id !== null) if($id != $chatAndUser['id']) continue;

            $neatChat[] = $chatAndUser;
        }

        return $neatChat;
    }
}

class Html1{

    static function removeTag($htmlContent, $ignoreTag=array()) {
        $ignoreTag=array_map('strtolower',$ignoreTag);
        $rhtml=preg_replace_callback('/<\/?([^>\s]+)[^>]*>/i', function ($matches) use (&$ignoreTag) {
            return in_array(strtolower($matches[1]),$ignoreTag)?$matches[0]:'';
        },$htmlContent);
        return $rhtml;
    }

    static function tagDecode ($a, $in = "") {
        if ( is_array($a) ) {
            $s = "";
            foreach ($a as $t)
                if ( is_array($t) ) {
                    $attrs="";
                    if ( isset($t['attr']) )
                        foreach( $t['attr'] as $k => $v )
                            $attrs.=" ${k}=".( strpos( $v, '"' )!==false ? "'$v'" : "\"$v\"" );
                    $s.= $in."<".$t['tag'].$attrs.( isset( $t['val'] ) ? ">\n".self::tagDecode( $t['val'], $in."  " ).$in."</".$t['tag'] : "/" ).">\n";
                } else
                    $s.= $in.$t."\n";
        } else {
            $s = empty($a) ? "" : $in.$a."\n";
        }
        return $s;
    }

    /**
     * extract_tags()
     * Extract specific HTML tags and their attributes from a string.
     *
     * You can either specify one tag, an array of tag names, or a regular expression that matches the tag name(s).
     * If multiple tags are specified you must also set the $selfclosing parameter and it must be the same for
     * all specified tags (so you can't extract both normal and self-closing tags in one go).
     *
     * The function returns a numerically indexed array of extracted tags. Each entry is an associative array
     * with these keys :
     *  tag_name    - the name of the extracted tag, e.g. "a" or "img".
     *  offset      - the numberic offset of the first character of the tag within the HTML source.
     *  contents    - the inner HTML of the tag. This is always empty for self-closing tags.
     *  attributes  - a name -> value array of the tag's attributes, or an empty array if the tag has none.
     *  full_tag    - the entire matched tag, e.g. '<a href="http://example.com">example.com</a>'. This key
     *                will only be present if you set $return_the_entire_tag to true.
     *
     * @param string $htmlContent The HTML code to search for tags.
     * @param string|array $tag The tag(s) to extract.
     * @param string $openBracket
     * @param string $closeBracket
     * @param bool $selfClosingTagList Whether the tag is self-closing or not. Setting it to null will force the script to try and make an educated guess.
     * @param bool $return_the_entire_tag Return the entire matched tag in 'full_tag' key of the results array.
     * @param string $charset The character set of the HTML code. Defaults to ISO-8859-1.
     * @return array An array of extracted tags, or an empty array if no matching tags were found.
     */
    static function extractTagAndAttribute($htmlContent, $tag = 'div', $openBracket = '<', $closeBracket = '>', $selfClosingTagList = null, $return_the_entire_tag = false, $charset = 'ISO-8859-1' ){
        if ( is_array($tag) ) $tag = implode('|', $tag);


        //If the user didn't specify if $tag is a self-closing tag we try to auto-detect it
        //by checking against a list of known self-closing tags.
        $selfclosing_tags = array( 'area', 'base', 'basefont', 'br', 'hr', 'input', 'img', 'link', 'meta', 'col', 'param' );
        if ( is_null($selfClosingTagList) ) $selfClosingTagList = in_array( $tag, $selfclosing_tags );

        //The regexp is different for normal and self-closing tags because I can't figure out
        //how to make a sufficiently robust unified one.
        if ( $selfClosingTagList ){
            $tag_pattern =
                '@<(?P'.$openBracket.'tag'.$closeBracket.''.$tag.')           # <tag
            (?P'.$openBracket.'attributes'.$closeBracket.'\s[^'.$closeBracket.']+)?       # attributes, if any
            \s*/?'.$closeBracket.'                   # /'.$closeBracket.' or just '.$closeBracket.', being lenient here 
            @xsi';


        } else {
            $tag_pattern =
                '@'.$openBracket.'(?P'.$openBracket.'tag'.$closeBracket.''.$tag.')           # '.$openBracket.'tag
            (?P'.$openBracket.'attributes'.$closeBracket.'\s[^'.$closeBracket.']+)?       # attributes, if any
            \s*'.$closeBracket.'                 # '.$closeBracket.'
            (?P'.$openBracket.'contents'.$closeBracket.'.*?)         # tag contents
            '.$openBracket.'/(?P=tag)'.$closeBracket.'               # the closing '.$openBracket.'/tag'.$closeBracket.'
            @xsi';
        }

        $attribute_pattern =
            '@
        (?P'.$openBracket.'name'.$closeBracket.'\w+)                         # attribute name
        \s*=\s*
        (
            (?P'.$openBracket.'quote'.$closeBracket.'[\"\'])(?P'.$openBracket.'value_quoted'.$closeBracket.'.*?)(?P=quote)    # a quoted value
            |                           # or
            (?P'.$openBracket.'value_unquoted'.$closeBracket.'[^\s"\']+?)(?:\s+|$)           # an unquoted value (terminated by whitespace or EOF) 
        )
        @xsi';

        //Find all tags
        if ( !preg_match_all($tag_pattern, $htmlContent, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ){
            //Return an empty array if we didn't find anything
            return array();
        }

        $tags = array();
        foreach ($matches as $match){

            //Parse tag attributes, if any
            $attributes = array();
            if ( !empty($match['attributes'][0]) ){

                if ( preg_match_all( $attribute_pattern, $match['attributes'][0], $attribute_data, PREG_SET_ORDER ) ){
                    //Turn the attribute data into a name->value array
                    foreach($attribute_data as $attr){
                        if( !empty($attr['value_quoted']) ){
                            $value = $attr['value_quoted'];
                        } else if( !empty($attr['value_unquoted']) ){
                            $value = $attr['value_unquoted'];
                        } else {
                            $value = '';
                        }

                        //Passing the value through html_entity_decode is handy when you want
                        //to extract link URLs or something like that. You might want to remove
                        //or modify this call if it doesn't fit your situation.
                        $value = html_entity_decode( $value, ENT_QUOTES, $charset );

                        $attributes[$attr['name']] = $value;
                    }
                }

            }

            $tag = array(
                'tag_name' => $match['tag'][0],
                'offset' => $match[0][1],
                'contents' => !empty($match['contents'])?$match['contents'][0]:'', //empty for self-closing tags
                'attributes' => $attributes,
            );
            if ( $return_the_entire_tag ){
                $tag['full_tag'] = $match[0][0];
            }

            $tags[] = $tag;
        }

        return $tags;
    }

    static function setTagAttribute($htmlContent = '<a href="https://www.xamtax.com" class="cw-link" title="xamtax">Visit xamtax</a>', $tagName = 'a', $attribute = 'style="color:red"'){
        return preg_replace("/(<$tagName\b[^><]*)>/i", "$1 $attribute>", $htmlContent);
    }

}


/**
 * Class ServerRequest Use to call method directly with string like url
 */
class ServerRequest1{
    public static $api_id = '';
    public static $api_key = '';
    public static $request = [];


    /**
     * @return mixed
     * @param string $urlArg Example could be
     * [$urlArg = 'className::function&&param1&&param2']
     *
     * or
     * just method only [$urlArg = 'function&&param1&&param2']
     *
     * or manually tweaking
     * @call_url($urlArg = 'className::function&&param1&&param2', $classMethodSplit = '::', $paramSplit = '&&')
     *
     */


    /**
     *
     * @param string $urlArg
     * @param string $classMethodSplit (class and static function delimiter, using :: to break function params)
     * @param string $paramSplit (parameter delimiter, using && to break function params)
     * @return mixed
     *
     * // EXAMPLE IN AJAX
     * ---------------------------------
    public directProcessData($url = 'class@@func//param1//param2', extraBundle?){
        return new Promise(resolve => {
            console.dir('RequestWith: ' + $url);
            this.http.post(this.getParameter($url),ServerDataProvider.$request_extra+"="+extraBundle,  ServerDataProvider.getHttpHeaderOption()).map(res => res.json()).subscribe(data =>{
                resolve(data);
            });
        });
    }
     *
     *
     *
     * // EXAMPLE IN ANGULAR 2+
     * ---------------------------------
        public directProcessData($url = 'class@@func//param1//param2', extraBundle?){
            return new Promise(resolve => {
                console.dir('RequestWith: ' + $url);
                this.http.post(this.getParameter($url),ServerDataProvider.$request_extra+"="+extraBundle,  ServerDataProvider.getHttpHeaderOption()).map(res => res.json()).subscribe(data =>{
                    resolve(data);
                });
            });
        }
     *
     *
     *
     *
     */
    static function callFunctionByUrl($urlArg = 'className::function&&param1&&param2', $classMethodSplit = '::', $paramSplit = '&&'){
        if(substr_count($urlArg, $classMethodSplit) > 0){
            // class
            $arr = explode($classMethodSplit, $urlArg);
            $className = $arr[0];
            $methodAndParams = $arr[1];

            // function and params
            $param = [];
            $arr = explode($paramSplit, $methodAndParams);
            $methodName = $arr[0];
            for($i=1; $i<count($arr); $i++){
                $param[] = $arr[$i];
            }

            // call
            return call_user_func_array(array($className, $methodName),  $param);

        }else{

            // function and params
            $param = [];
            $arr = explode($paramSplit, $urlArg);
            $methodName = $arr[0];
            for($i=1; $i<count($arr); $i++){
                $param[] = $arr[$i];
            }

            // call
            return call_user_func_array($methodName,  $param);
        }

    }



    //static function call($lookupFunction = 'className::function(param1, param2)', $paramDelimiter = ','){ return self::call1($lookupFunction, $paramDelimiter); }

    /**
     * @param string $lookupFunction @default Format is 'className::function(param1, param2)'
     * @param string $paramDelimiter
     * @param bool $authenticate (if true, means cannot call function, only class method can be called and the class method must have a corresponding  api_id and api_key)
     * @return ResultObject1|mixed|string
     */
    static function callFunction($lookupFunction = 'className::function(param1, param2)', $paramDelimiter = ',', $authenticate = true){
        // validate API keys
        $breakSymbol = self::breakSymbol($lookupFunction);
        $lookupFunction = static::validateAndNormalizeFunction($lookupFunction, $authenticate);
        if($lookupFunction instanceof ResultObject1) die($lookupFunction);


        // use regex to check if string contain ( , ' ) comma and single quote
        $lookupFunction = trim($lookupFunction, '/');
        $isDoubleQuote = (!preg_match('#,[ ]*\'#', $lookupFunction)? '"': "'");
        //return str_getcsv($lookupFunction, $paramDelimiter, $isDoubleQuote );


        // is valid request
        if(strpos($lookupFunction, '(') <=0 ) return 'Not a valid Xamtax Server Request';

        // split up string
        $openB = strpos($lookupFunction, '(');
        $functionAndClass = substr($lookupFunction, 0, $openB);
        $rawParameters = substr($lookupFunction, $openB);



        // split of Url if it contains '?'
        $urlParameter = [];
        if(!String1::endsWith(')', $rawParameters) && String1::contains('?', $rawParameters)) {
            $urlParameter = explode('?', $rawParameters);
            $rawParameters = $urlParameter[0];
            parse_str($urlParameter[1], $urlParameter);
        }

        // split and filter parameter to array (filter out ", ', (, ), ;, )  // first remove space and later rater remove quote because of string like "      hello", so the space in quote preserved for some reason would not be removed as well
        $parameterList = array_map(function($item){ return trim($item, ' ')  ;}, str_getcsv( trim($rawParameters, '();'), $paramDelimiter, $isDoubleQuote) );
        $parameterList = array_map(function($item){ return trim($item, '"\'')  ;}, $parameterList);
        static::$request = array_merge($parameterList, $urlParameter);


        // run the method and function
        if(strpos($lookupFunction, $breakSymbol) > 0){
            try{
                $class_and_method = explode($breakSymbol, $functionAndClass);
                $callAs = (($breakSymbol == '@' || $breakSymbol == '.')? (new $class_and_method[0]): $class_and_method[0]);
                return call_user_func_array([$callAs, $class_and_method[1]],  $parameterList);
            }catch (Exception $exception) {
                die(self::serverErrorAsResultObject1($functionAndClass, $parameterList, 'method_call_error-'.$exception->getMessage()));
            }
        }else{
            // insert function and param // Only Method
            try{ return call_user_func_array($functionAndClass,  $parameterList); }catch (Exception $exception) {  die(self::serverErrorAsResultObject1($functionAndClass, $parameterList, 'function_call_error-'.$exception->getMessage())); }

        }
    }


    private static function serverErrorAsResultObject1($functionAndClass = 'functionName', $parameterList = [], $exception = ''){
        return new ResultObject1(false,  $exception, String1::escapeQuotes($functionAndClass)); // RegEx1::getSanitizeAlphaNumeric($functionAndClass, '_') . '( '       .implode(',,,', $parameterList).        ' ) call'
    }


    /**
     * @param $functionName
     * @return null|string
     * Extract The Symbol Used as a break
     *  if Symbol is @ or ., call class object method and static method. else if symbol is ::, call static method only
     */
    private static function breakSymbol($functionName){
        if (strpos($functionName, '(') > -1) $functionName = String1::getSubString($functionName, strpos($functionName, '('));
        else if (strpos($functionName, '?') > -1) $functionName = String1::getSubString($functionName, strpos($functionName, '?'));

        if(String1::contains('@', $functionName) ) return '@';
        else if(String1::contains('::', $functionName)) return '::';
        else if(String1::contains('.', $functionName) ) return '.';
        else return null;
    }

    /**
     * @param $functionName
     * @param bool $auth
     * @return ResultObject1|string
     */
    private static function validateAndNormalizeFunction($functionName, $auth = true){
        $breakSymbol = self::breakSymbol($functionName);

        $functionName =  (String1::contains($breakSymbol, $functionName) || static::class === self::class)? $functionName: static::class.$breakSymbol.$functionName;
        if(!String1::contains('(', $functionName)){
            if(String1::contains('?', $functionName)){
                $sp = explode('?', $functionName);
                $functionName = $sp[0].'()'.$sp[0];
            }else
                $functionName .= '()';
        }


        // is auth required
        $className = explode($breakSymbol, $functionName)[0];



        // check if serverRequest class is called and not method
        if($auth) {
            if(!String1::contains($breakSymbol, $functionName) || !class_exists($className) || !Array1::contain(class_parents($className), ServerRequest1::class))
                die(self::serverErrorAsResultObject1($functionName, [], 'invalid_function_called- ServerRequest1 or API1 extended Class required!'));
        }


        // validate if API_KEY is valid with REQUEST[API_KEY] or if token is valid with Saved token data
        if(class_exists($className)) {
            if(!(method_exists($className, 'isApiAuthValid') && $className::isApiAuthValid())){
                if (
                    !(
                        !Array1::contain(class_parents($className), Controller1::class) &&  // Disabled if controller1 exists, so we won't have null API_KEY free pass
                        isset($className::$api_id) &&
                        isset($className::$api_key) &&
                        String1::isset_or($_REQUEST['api_id'], '') === $className::$api_id &&
                        String1::isset_or($_REQUEST['api_key'], '') === $className::$api_key
                    )
                ) {
                   if($auth) die(self::serverErrorAsResultObject1($functionName, [], 'permission_denied- form token, api_id or api_key Not Set'));
                }
            }
        }


        // return parse name
        return $functionName;
    }


    /**
     * @param string $exec uses eval to execute any php code given [ note: this is dangerous and not the best way, use @call_url instead]
     * @return mixed
     */
    //static function makeAndCall($exec = 'className::function("param1", "param2")'){
    //    return eval($exec.";");
    //}




    /**
     * Get all available method
     */
    static public function help(){
        echo '<div style="margin:100px"><h3>Ehex '.ucfirst(static::class).' Class Method List</h3><hr/>';
        $param = String1::contains('?', Url1::getPageFullUrl())? explode('?', Url1::getPageFullUrl())[1]: null;
        foreach (get_class_methods(static::class) as $method) {
            $full_link = Form1::callApi(static::class.'@'.$method.'(...)'. ($param? '?'.$param: '')  );
            echo Console1::d("<h3>function $method(...) <br/><a href='$full_link' target='_blank'>$full_link</a></h3><hr/>" );
        }
        echo '</div>';
        return 'Xamtax Ehex. '.ucfirst(static::class).' Api Class ';
    }
}






class RegEx1{

    static function removeTags($htmlString = ''){ return preg_replace ('/<[^>]*>/', ' ', $htmlString); }
    static function removeMultipleSpace($string = ''){ trim(preg_replace('/ {2,}/', ' ', $string)); }



    static function splitStringByBracket($bracketDelimiterString = 'hello (world) i am (samson)'){
        return  preg_split("/[()]+/", $bracketDelimiterString, -1, PREG_SPLIT_NO_EMPTY);
    }


    static function splitStringByTagAndAttribute($bracketDelimiterString = '<a href="test">text [and] test is good</a>'){
        //return  preg_split("/<([^ ]+) ?([^>]*)>([^<]*)< ?/ ?\1>/", $bracketDelimiterString, -1, PREG_SPLIT_NO_EMPTY);

        //return  preg_split('/ <a\s+href=["\']([^"\']+)["\'] /i', $bracketDelimiterString, -1, PREG_SPLIT_NO_EMPTY);


        //return  preg_split('/\(([A-Za-z0-9 ]+?)\)/', $bracketDelimiterString);
        //return  preg_split('#\[(.*?)\]#', $bracketDelimiterString);
        //return  preg_split('/[0-9]+\.\s/', $bracketDelimiterString);

        //$str = "1. [subject] 2. [another subject] 3. [a third subject]";
        //preg_match_all('/\[([^\]]+)\]/', $str, $matches);
        //return $matches;


        $str = '<option value="123">abc</option><option value="123">aabbcc</option>';
        preg_match_all("#<.*? ([^>]*)>([^<]*)< ?/ ?\1>#", $str, $foo);
        Console1::println($foo);
    }

    static function extractBrackets($bracketDelimiterString = 'hello (world), my name (is andrew) and my number is (845) 235-0184'){
        preg_match_all('/\(([A-Za-z0-9 ]+?)\)/', $bracketDelimiterString, $out);
        return  $out;
    }

    static function getSanitizeAlphaNumeric($string, $additionalCharacter = ''){
        // XSS protection as we might print this value
        return preg_replace("/[^a-zA-Z0-9$additionalCharacter]+/", "", $string);
    }

}


class Validation1{
    static public function email($email = '') { return ResultStatus1::make((filter_var($email, FILTER_VALIDATE_EMAIL)), 'Not a valid email address'); }
    static public function userName($value = '') {
        $regex='/^[a-zA-Z0-9]{5,20}$/';
        return ResultStatus1::make(preg_match($regex, $value), 'Username should contain only alphabets and digits');
    }

    static public function fullName($value = '') {
        $regex='/^[a-zA-Z ]*$/';
        return ResultStatus1::make(preg_match($regex, $value), 'Full Name should only contain alphabets');
    }

    static public function phoneNumber($value = '') {
        $regex='/^[0-9]{10}$/';
        return ResultStatus1::make(preg_match($regex, $value), 'Not a valid phone no.');
    }

    static public function password($password = '') {
        $status = false;
        $regex = '/^[a-zA-Z0-9!@#$%^&*_]{6,50}$/';
        if(preg_match($regex, $password)) {
            $x = str_split($password);
            $ar = array('!', '@', '#', '$', '%', '^', '&', '*', '_');
            $flag = 0;
            foreach($x as $v) {
                if(in_array($v, $ar)) {
                    $flag = 1;
                    break;
                }
            }
            if($flag == 1) $status = true;
            else $status = false;
        }
        return ResultStatus1::make($status, 'Password should contain minimum 6 characters and either of !@#$%^&*_');
    }


     /**
     * Validates the name of the file to ensure it can be stored in the
     * filesystem.
     */ 
    public static function fileName($value){
        $regex='/^[0-9A-Za-z\_\-]{1,63}$/';
        return ResultStatus1::make(preg_match($regex, $value), 'Not a valid filename.');
    }



}




class String1{

    /**
     * Return 22-char compressed version of 32-char hex string (eg from PHP md5). adn URL Safe
     * @param $md5_hash_str
     * @return mixed
     */
    static function compressMD5($md5_hash_str) {
        // (we start with 32-char $md5_hash_str eg "a7d2cd9e0e09bebb6a520af48205ced1")
        $md5_bin_str = "";
        foreach (str_split($md5_hash_str, 2) as $byte_str) { // ("a7", "d2", ...)
            $md5_bin_str .= chr(hexdec($byte_str));
        }
        // ($md5_bin_str is now a 16-byte string equivalent to $md5_hash_str)
        $md5_b64_str = base64_encode($md5_bin_str);
        // (now it's a 24-char string version of $md5_hash_str eg "VUDNng4JvrtqUgr0QwXOIg==")
        $md5_b64_str = substr($md5_b64_str, 0, 22);
        // (but we know the last two chars will be ==, so drop them eg "VUDNng4JvrtqUgr0QwXOIg")
        $url_safe_str = str_replace(array("+", "/"), array("-", "_"), $md5_b64_str);
        // (Base64 includes two non-URL safe chars, so we replace them with safe ones)
        return $url_safe_str;
    }


    /**
     * If you now want a function to compress your hexadecimal MD5 values using URL safe characters, you can use this:
     * @param $hash
     * @return mixed
     */
    static function compressHash($hash) {
        return self::base64_to_base64UrlSafe(rtrim(self::base16_to_base64($hash), '='));
    }

    /**
     * And the inverse function:
     * @param $hash
     * @return mixed
     */
    static function uncompressHash($hash) {
        return self::base64_to_base16(self::base64UrlSafe_to_base64($hash));
    }

    /**
     * If you need Base-64 encoding with the URL and filename safe alphabet , you can use these functions:
     * @param $base64
     * @return string
     */
    static function base64_to_base64UrlSafe($base64) {
        return strtr($base64, '+/', '-_');
    }

    /**
     * @param $base64safe
     * @return string
     */
    static function base64UrlSafe_to_base64($base64safe) {
        return strtr($base64safe, '-_', '+/');
    }

    /**
     * Here are two conversion functions for Base-16 to Base-64 conversion and the inverse Base-64 to Base-16 for arbitrary input lengths:
     * @param $base16
     * @return string
     */
    static function base16_to_base64($base16) {
        return base64_encode(pack('H*', $base16));
    }

    /**
     * And the inverse function:
     * @param $base64
     * @return string
     */
    static function base64_to_base16($base64) {
        return implode('', unpack('H*', base64_decode($base64)));
    }



    /**
     * @var array for pluralize
     */
    private static $plural=array('/(quiz)$/i'=>"$1zes",'/^(ox)$/i'=>"$1en",'/([m|l])ouse$/i'=>"$1ice",'/(matr|vert|ind)ix|ex$/i'=>"$1ices",'/(x|ch|ss|sh)$/i'=>"$1es",'/([^aeiouy]|qu)y$/i'=>"$1ies",'/(hive)$/i'=>"$1s",'/(?:([^f])fe|([lr])f)$/i'=>"$1$2ves",'/(shea|lea|loa|thie)f$/i'=>"$1ves",'/sis$/i'=>"ses",'/([ti])um$/i'=>"$1a",'/(tomat|potat|ech|her|vet)o$/i'=>"$1oes",'/(bu)s$/i'=>"$1ses",'/(alias)$/i'=>"$1es",'/(octop)us$/i'=>"$1i",'/(ax|test)is$/i'=>"$1es",'/(us)$/i'=>"$1es",'/s$/i'=>"s",'/$/'=>"s");
    private static $singular=array('/(quiz)zes$/i'=>"$1",'/(matr)ices$/i'=>"$1ix",'/(vert|ind)ices$/i'=>"$1ex",'/^(ox)en$/i'=>"$1",'/(alias)es$/i'=>"$1",'/(octop|vir)i$/i'=>"$1us",'/(cris|ax|test)es$/i'=>"$1is",'/(shoe)s$/i'=>"$1",'/(o)es$/i'=>"$1",'/(bus)es$/i'=>"$1",'/([m|l])ice$/i'=>"$1ouse",'/(x|ch|ss|sh)es$/i'=>"$1",'/(m)ovies$/i'=>"$1ovie",'/(s)eries$/i'=>"$1eries",'/([^aeiouy]|qu)ies$/i'=>"$1y",'/([lr])ves$/i'=>"$1f",'/(tive)s$/i'=>"$1",'/(hive)s$/i'=>"$1",'/(li|wi|kni)ves$/i'=>"$1fe",'/(shea|loa|lea|thie)ves$/i'=>"$1f",'/(^analy)ses$/i'=>"$1sis",'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i'=>"$1$2sis",'/([ti])a$/i'=>"$1um",'/(n)ews$/i'=>"$1ews",'/(h|bl)ouses$/i'=>"$1ouse",'/(corpse)s$/i'=>"$1",'/(us)es$/i'=>"$1",'/s$/i'=>"");
    private static $irregular=array('move'=>'moves','foot'=>'feet','goose'=>'geese','sex'=>'sexes','child'=>'children','man'=>'men','tooth'=>'teeth','person'=>'people','valve'=>'valves');
    private static $uncountable=array('sheep','fish','deer','series','species','money','rice','information','equipment');

    /**
     * pluralize value
     * @param $string
     * @return null|string|string[]
     */
    public static function pluralize($string){
        if(in_array(strtolower($string),self::$uncountable))
        return $string;foreach(self::$irregular as $pattern=>$result){
        $pattern='/'.$pattern.'$/i';if(preg_match($pattern,$string))
        return preg_replace($pattern,$result,$string);}
        foreach(self::$plural as $pattern=>$result)
        {if(preg_match($pattern,$string))
        return preg_replace($pattern,$result,$string);}
        return $string;
    }

    /**
     * singularize value
     * @param $string
     * @return null|string|string[]
     */
    public static function singularize($string){
        if(in_array(strtolower($string),self::$uncountable))
        return $string;foreach(self::$irregular as $result=>$pattern)
        {$pattern='/'.$pattern.'$/i';if(preg_match($pattern,$string))
        return preg_replace($pattern,$result,$string);}
        foreach(self::$singular as $pattern=>$result)
        {if(preg_match($pattern,$string))
        return preg_replace($pattern,$result,$string);}
        return $string;
    }

    /**
     * Pluralize value only if count > 0
     * @param $count
     * @param $string
     * @return string
     */
    public static function pluralize_if($count, $string) {
        if($count==1)
        return"1 $string";else
        return $count." ".self::pluralize($string);
    }






    public static function isUpperCase($string) { return $string === strtoupper($string); }
    public static function isLowerCase($string) { return $string === strtolower($string); }

    /**
     * Returns the first string there is between the strings from the parameter start and end.
     * stringBetween('This is a [custom] string', '[', ']'); // custom
     * @param $haystack
     * @param $start
     * @param $end
     * @return string
     */
    public static function stringBetween($haystack, $start, $end){
        return trim(strstr(strstr($haystack, $start), $end, true), $start . $end);
    }







    /**
     * @param $input
     * @param string $delimiter
     * @return string
     *     To convertCamelCase_toSnakeCase I.E FirstName = first_name
     */
    public static function convertToSnakeCase($input, $delimiter = '_') {
        return $word = preg_replace_callback("/(^|[a-z])([A-Z])/", function($m) use ($delimiter) { return strtolower(strlen($m[1]) ? "$m[1]$delimiter$m[2]" : "$m[2]"); }, $input);
    }

    /**
     * @param $input
     * @param string $underScore_replace_with
     * @return string To convertSnakeCase_toCamelCase I.E first_name = FirstName
     * To convertSnakeCase_toCamelCase I.E first_name = FirstName
     */
    public static function convertToCamelCase($input, $underScore_replace_with = '') {
        return $word = preg_replace_callback(
            "/(^|_)([a-z])/",
            function($m) use ($underScore_replace_with) { return $underScore_replace_with.strtoupper("$m[2]"); },
            $input
        );
    }

    /**
     * @param $word
     * @return mixed
     *     echo create_slug('does this thing work or not');
    //returns 'does-this-thing-work-or-not'
     */
    static function convertWordToSlug($word){
        // return preg_replace(['/[^A-Za-z0-9-]+/', '/[«»“”!?,.]+/'], '-', $word);
        return strtolower(preg_replace("/\W+/","-",$word)); //By using \W+ you take care of all non-latin characters.
    }


    /**
     * get mysql variable from php variable
     * @param string $dataType
     * @return string
     */
    static function convertMySqlDataTypeToPhp($dataType = 'varchar'){
        switch ($dataType){
            case 'boolean': case 'tinyint':
            return 'boolean';

            case 'varchar': case 'text': case 'enum': case 'blob':
            return $dataType == 'text'? 'STRING' : 'string';

            case 'int': case 'integer':
            return 'integer';

            default:
                return $dataType;
        }
    }

    /**
     * Normalize Character and replace for accents catalan spanish and more
     * @param $var
     * @return mixed
     */
    public static function replaceAccents($var){
        $a = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ', 'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ');
        $b = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o');
        $var = str_replace($a, $b, $var);
        return $var;
    }






    static function toString($value, $delimiter = ' '){
        if(is_string($value) || is_numeric($value) || is_bool($value)) $str = (string)$value;
        else if(is_object($value)) $str = self::toString(Object1::convertObjectToArray( $value ));
        else if(is_array($value)) $str = Array1::implode($delimiter, $value);
        else $str = print_r($value, true);
        return $str;
    }



    static function getDemoText($length=500, $isPassword = false, $shuffleString = true){
        $password = '799 Nf pri 3523 gRe 467 sS hme 123  356  24 85  425 4361  425 aCt cFr tsS hi nEv Ere VeR bEA 4575 enE All  tHem oFfLine 864 Pass PrasE Pri Tec TeD 234 BaCK tHem Up NT aThuMb Dri ARe 1324 85  425 436 1  425 aCt cFr tsS hkS nEv Ere VeR bEA 4575 ebnE All sTere tHem Line 864 Pass PrasE Pre Tec TeD 234 BaCK tHem Up Nt aThuMb Dri ARe 1324 PreF eRaB alLy 24 2 an enCry pted thumb drive and kEeP it sAfe & # $ % ! # * & @ % %';
        $text = EasyGenerator::sentence($length);
        $activeText = ($isPassword)? $password: $text;
        for($i = 0; $i<$length; $i++) {
            if(strlen($activeText) > $length)break;
            else $activeText .= $activeText;
        }

        $textNeeded = String1::getSubString($activeText, $length);
        if($shuffleString){
            $arr = explode(" ", $textNeeded);
            shuffle($arr);
            $textNeeded = implode(" ", $arr);
        }

        return  ($isPassword)? self::replace($textNeeded, ' ', '') :$textNeeded;
    }

    static function mask($text, $start_from = 1, $maskKey = '*', $length = 20){
        $allText = static::getSubString($text, $length, 0);
        $asArray = String1::toArray($allText);
        $asText = '';
        for ($i = 0; $i < count($asArray); $i++){
            if($i >= $start_from) $asText .= $maskKey;
            else $asText .= $asArray[$i];
        }
        return $asText;
    }

    /**
     * get string hash code
     * @param $value
     * @return float|int
     */
    static function hashCode($value){
        $hashCode = 0;
        for ($i = 0; $i < strlen($value); $i++) $hashCode = $hashCode * 31 + ord(substr($value, $i, 1));
        return $hashCode;
    }

    /**
     * remove trailing quote
     * @param string $value
     * @param bool $toJavascript
     * @return string
     */
    static function escapeQuotes($value = 'ade is a "fine" Boy', $toJavascript = false){
        if (!is_array($value))  $thearray = array($value);
        else $thearray = $value;
        foreach (array_keys($thearray) as $string) {
            $thearray[$string] = $toJavascript? json_encode(addslashes($thearray[$string])): addslashes($thearray[$string]);
            $thearray[$string] = preg_replace("/[\\/]+/","/",$thearray[$string]);
        }
        if (!is_array($value)) return $thearray[0];
        else return $thearray;
    }

    /**
     * remove special character in string value
     * @param string $value
     * @return string
     */
    static function escapeStringAsEntity($value){
        return strtr($value, array(
            "\0" => "",
            "'"  => "&#39;",
            "\"" => "&#34;",
            "\\" => "&#92;",
            // more secure
            "<"  => "&lt;",
            ">"  => "&gt;",
        ));
    }





    static function startsWith($string, $needleToSearch){
        $lastText = substr($string, 0, strlen($needleToSearch));
        return ($needleToSearch == $lastText);
    }

    static function endsWith($string, $needleToSearch){
        $lastStrCount = strlen($string) - strlen($needleToSearch);
        $lastText = substr($string, $lastStrCount, strlen($needleToSearch));
        return ($needleToSearch == $lastText);
    }


    static function replace($text, $search, $replace){ return str_replace($search, $replace, $text); }

    static function replaceStart($text, $search, $replace){
        if (trim($search) == '') return $text;
        $position = strpos($text, $search);
        if ($position !== false) return substr_replace($text, $replace, $position, strlen($search));
        return $text;
    }

    static function replaceEnd($text, $search, $replace){
        $position = strrpos($text, $search);
        if ($position !== false) return substr_replace($text, $replace, $position, strlen($search));
        return $text;
    }


    /**
     *
    Removes trailing indentation in HEREDOC strings and other strings with multiple lines.
     *
     * @param $x
     * @param int $leadingSpaces
     * @return string
     */
    static function hereDocMoonWalk($x, $leadingSpaces = 0) {
        //Make sure we don't start or endwith new lines
        $x = trim($x, "\r");
        $x = trim($x, "\n");
        // Find how many leading spaces are in the first line
        $spacesToRemove = strlen($x) - strlen(ltrim($x)) - $leadingSpaces;
        // Break up by new lines
        $lines = explode("\n", $x);
        //$lines = array_values(array_filter($lines,"not_empty"));
        // Remove that many leading spaces from the beginning of each string
        for($x = 0; $x < sizeof($lines); $x++) {
            // Remove each space
            $lines[$x] = preg_replace('/\s/', "", $lines[$x], $spacesToRemove);
        }
        // Put back into string on seperate lines
        return implode("\n", $lines);
    }


    static function toArray($text, $delimiter = ''){
        // $allArray = [];
        // $length = strlen($string);
        // for($i = 0; $i < $length; $i++) $allArray[] = substr($string, $i, 1);
        return self::is_empty($delimiter)? str_split($text) : explode($delimiter, $text);//preg_split('//i', $text)
    }


    static function fetchSynonyms($word){
        $api = "918b40fb4655e1ed5000c1910dc026a7";  // Get Api from http://bighugelabs.com;
        $json = file_get_contents("http://words.bighugelabs.com/api/2/$api/$word/json");
        return json_decode($json, true);
    }

    /**
     * Translate Text
     * @param $text
     * @param string $fromLanguage
     * @param string $toLanguage
     * @param bool $cache
     * @param bool $returnDefaultOnFailed
     * @return mixed|null|string|string[]
     */
    static function translateLanguage($text, $fromLanguage = 'nl', $toLanguage = 'en', $cache = false, $returnDefaultOnFailed = true){
        if($fromLanguage === $toLanguage || $fromLanguage === '' || $toLanguage === '') return $text;

        //check cache
        $cachePath = "language-".self::hashCode($text)."-$fromLanguage-$toLanguage";
        if($cache) if(Session1::exists($cachePath) && !empty(Session1::get($cachePath))) return Session1::get($cachePath);
        //return Session1::exists($cachePath)? 'Exists': 'none...';

        // filter
        if(String1::contains('.', $text))  $text = rtrim($text, '.').'.';


        // init
        $filePath = $_SERVER['DOCUMENT_ROOT']."/transes.html";
        $googleTranslatorUrl = "http://translate.googleapis.com/translate_a/single?client=gtx&ie=UTF-8&oe=UTF-8&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&dt=at&sl=".$fromLanguage."&tl=".$toLanguage."&hl=hl&q=";
        $res="";

        $qqq=explode(".", $text);


        try{
            if(count($qqq)<2){
                @unlink($filePath);
                @copy($googleTranslatorUrl.urlencode(($text)), $filePath);
                if(file_exists($filePath)){
                    $dara=file_get_contents($filePath);
                    $f=explode("\"", $dara);
                    $res.= $f[1];

                }else{
                    return null;
                }


            } else{
                for($i=0;$i<(count($qqq)-1);$i++){
                    if($qqq[$i]==' ' || $qqq[$i]==''){}
                    else{
                        @copy($googleTranslatorUrl.urlencode($qqq[$i]), $filePath);
                        if(!file_exists($filePath)) return null;
                        $dara=file_get_contents($filePath);
                        @unlink($filePath);
                        $f=explode("\"", $dara);
                        $res.= $f[1].". ";
                    }
                }
            }


        }catch (Exception $ex){ return ($text); }

        // save cache
        if($cache && !String1::is_empty($res)) Session1::set($cachePath, $res);
        return ((String1::is_empty($res) && $returnDefaultOnFailed))? $text: self::decodeUnicode($res);
    }


    /**
     * Translate Text and Cached It
     * @param array $textKeyValueList
     * @param string $fromLanguage
     * @param string $toLanguage
     * @param bool $cache
     * @param bool $returnDefaultOnFailed
     * @return array Example, and Array of $food = ['dinner'=>'pie', 'breakfast'=>'moimoi']
     * Example, and Array of $food = ['dinner'=>'pie', 'breakfast'=>'moimoi']
     * Would be converted to dinner=pie & breakfast=moimoi. as Sending Request
     * then output  ['dinner'=>'ahfdk', 'breakfast'=>'asfas']
     */
    static function translateLanguageKeyValue(Array $textKeyValueList = [], $fromLanguage = 'en', $toLanguage = 'en', $cache = true, $returnDefaultOnFailed = true){
        if($fromLanguage === $toLanguage || $fromLanguage === '' || $toLanguage === '') return $textKeyValueList;
        $text = '';

        // convert to string
        $index = 0;
        if(is_array($textKeyValueList))  foreach ($textKeyValueList as $tKey=> $tValue) {$text .= $index."=$tValue&"; $index++;};

        //check cache
        $cachePath = "language-".self::hashCode($text)."-$fromLanguage-$toLanguage";
        if($cache) if(Session1::exists($cachePath) && !empty(Session1::get($cachePath))) return Session1::get($cachePath);
        //return $cachePath;

        // process
        $output = self::translateLanguage(trim($text, '&'), $fromLanguage, $toLanguage, false, $returnDefaultOnFailed);

        // convert back to array and assign default key name
        parse_str($output, $textArray);
        $index = 0; $newArray = []; $defaultKeyList = array_keys($textKeyValueList);
        foreach($textArray as $tKey=> $vValue) {
            $newArray[$defaultKeyList[$index]] = $vValue;
            $index++;
        }

        // save cache
        if($cache && !empty($newArray)) Session1::set($cachePath, $newArray);
        return (!empty($textKeyValueList) && empty($newArray) && $returnDefaultOnFailed)? $textKeyValueList: $newArray;
    }


    /**
     * Translate Text and Cached it
     * @param array $textKeyValueList
     * @param string $fromLanguage
     * @param string $toLanguage
     * @param bool $cache
     * @param string $defaultKey
     * @return bool|mixed
     */
    static function translateLanguageKeyAndManyValues(Array $textKeyValueList = [], $fromLanguage = 'en', $toLanguage = 'en', $cache = true, $defaultKey = 'default'){
        //check cache
        $cachePath = "language-".Array1::hashCode($textKeyValueList)."-$fromLanguage-$toLanguage";
        if($cache) if(Session1::exists($cachePath) && !empty(Session1::get($cachePath))) return Object1::convertArrayToObject( Session1::get($cachePath) );

        $languageUserDefinedList = $languageNotDefined = [];

        // separate user define translate from auto google translating.
        foreach ($textKeyValueList as $languageKey => $languagesValue){
            if(is_array($languagesValue) && isset($languagesValue[$toLanguage])) $languageUserDefinedList[$languageKey] = $languagesValue[$toLanguage];
            else $languageNotDefined[$languageKey] = (is_array($languagesValue))? $languagesValue[$defaultKey]: $languagesValue;
        }

        // process
        $output = self::translateLanguageKeyValue($languageNotDefined, $fromLanguage, $toLanguage, false, true);
        $newArray = array_merge($languageUserDefinedList, $languageNotDefined);

        // save cache
        if($cache && !empty($output)) Session1::set($cachePath, $newArray);

        //new Language
        return Object1::convertArrayToObject((!empty($textKeyValueList) && empty($newArray))? $textKeyValueList: $newArray);
    }


    /**
     * DeEncode from Unicode
     * @param $text
     * @return null|string|string[]
     */
    static function decodeUnicode($text) {
        if(String1::is_empty($text)) return '';
        return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function($match){
            return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
        }, $text);
    }

    /**
     * Encode to Number
     * @param $string
     * @return string
     */
    static function encodeStringToNumber($string){ return utf8_encode(join(array_map(function ($n) { return sprintf('%03d', $n); }, unpack('C*', $string)))); }

    /** DeEncode From Number
     * @param $stringNumber
     * @return string
     */
    static function decodeStringBackFromNumber($stringNumber){ return $str = utf8_encode(join(array_map('chr', str_split($stringNumber, 3)))); }

    /**
     * Encode to Short Alpha Numeric
     * @param $string
     * @return string
     */
    static function encodeToShortAlphaNum($string){
        return Math1::encodeToShortAlphaNum(String1::encodeStringToNumber( strtolower(substr($string, 0,1)).substr($string, 1) )); // fix for "Error" if Capital Letter Start $string
    }

    /**
     * @param $string
     * @return string
     */
    static function decodeFromShortAlphaNum($string){
        $output = String1::decodeStringBackFromNumber(Math1::decodeFromShortAlphaNum($string));
        return ctype_upper(substr($output, 1,1))? strtoupper(substr($output, 0,1)).substr($output, 1): $output;  // fix for "Error" if Capital Letter Start $string. Restore it back, using second letter case
    }

    /**
     * @param $str1
     * @param $str2
     * @return bool
     */
    static function isHashEquals($str1, $str2) {
        if(strlen($str1) != strlen($str2)) {
            return false;
        } else {
            $res = $str1 ^ $str2;
            $ret = 0;
            for($i = strlen($res) - 1; $i >= 0; $i--) $ret |= ord($res[$i]);
            return !$ret;
        }
    }

    /**
     * Generate Random String
     * @param int $length
     * @param null $uniqueId
     * @return bool|string
     */
    static function random($length = 10, $uniqueId = null){
        return substr(base_convert(sha1(uniqid( $uniqueId? $uniqueId: mt_rand())), 16, 36), 0, $length);
    }

    /**
     * Re-Show inserted string in count (n) time
     * @param string $value
     * @param int $repeatCount
     * @return bool|string
     */
    static function repeat($value = '', $repeatCount = 2){ $buf = ''; foreach (range(1, $repeatCount) as $count) $buf .= $value; return $buf; }

    /**
     * @param $text
     * @param $length
     * @param int $start
     * @return bool|string
     */
    static function getSubString($text, $length, $start = 0){ return substr($text, $start, $length); }

    /**
     * Get Small Text Out of Large Text
     * @param $text
     * @param string $length
     * @param string $ellipsis
     * @return string
     */
    static function getSomeText($text, $length='20', $ellipsis = '...'){ return (strlen($text) < $length)? $text: self::getSubString($text,  $length).' '.$ellipsis; }

    /**
     * @param $needle
     * @param $haystack
     * @return bool
     */
    static function contains($needle, $haystack) { if(empty($needle) || empty($haystack)) return false; return strpos($haystack, $needle) !== false;}

    /**
     * @param array $needles
     * @param $haystack
     * @param string $operator
     * @param bool $asWord
     * @return bool|string
     */
    static function containsMany($needles = [], $haystack, $operator = 'or', $asWord = false) {
        if($operator === 'or' || $operator === '||') {
            // Or Logical Operator
            if($asWord){
                //if (preg_match("/(foo|bar|baz)/i", $haystack) === 1){}
                $needle = implode('|', $needles);
                if(preg_match("/($needle)/i", $haystack) === 1) return true;

            }else{
                //if (preg_match("/(foo|bar|baz)/i", $haystack) === 1){}
                $needle = '';
                for($i = 0; $i <count($needles); $i++){
                    $needle .= ($i != 0)? '|': '';
                    $needle .= ".*$needles[$i]";
                }
                if(preg_match("/($needle)/i", $haystack) === 1) return true;
            }

        }else {
            // And Logical Operator
            if($asWord){
                // TO ARCHIVE THIS  if (preg_match('/^(?:foo()|bar()|baz()){3}\1\2\3$/s', $subject)) {}
                $needle = '';
                $needleNum = '';
                for($i = 0; $i <count($needles); $i++){
                    $needle .= ($i != 0)? '|': '';
                    $needle .= "$needles[$i]()";

                    $needleNum .= "\\".($i+1);
                }
                $needle = '/^(?:'.$needle.')'.'{'.count($needles).'}'.$needleNum.'$/i';
                if(preg_match($needle, $haystack) === 1) return $needle;

            } else {
                //if (preg_match('/^(?=.*foo)(?=.*bar)(?=.*baz)/s', $subject)) {}
                $needle = '';
                foreach ($needles as $search) $needle .= "(?=.*$search)";
                if(preg_match("/^$needle/s", $haystack) === 1) return true;
            }
        }
        return false;
    }


    /**
     * @param $value
     * @param bool $trueValue
     * @param bool $falseValue
     * @return bool
     */
    static function toBoolean($value, $trueValue = true, $falseValue = false) {
        $isString = is_string($value) && (trim($value) != '' && strtolower(trim($value)) !== 'false' && strtolower(trim($value)) !== 'off' && strtolower(trim($value)) !== 'no' && strtolower(trim($value)) !== '0' && strtolower(trim($value)) !== 'null');
        $isBoolean = is_bool($value) && ($value === true);
        $isNumber = is_integer($value) && ( $value >=1 );
        return ( $value !== null && ($isBoolean || $isString || $isNumber))? $trueValue: $falseValue;
    }


    //incase we have
    //The "are" at the beginning of "area"
    //The "are" at the end of "hare"
    //The "are" in the middle of "fares"
    static function containsWord($text, $wholeWordToFind){ return !!preg_match('#\\b' . preg_quote($wholeWordToFind, '#') . '\\b#i', $text); }

    /**
     * @param $str
     * @param string $replaceWith
     * @return null|string|string[]
     */
    static function removeBracket($str, $replaceWith = ''){ return preg_replace('/\([ˆ)]*\)|[()]/', $replaceWith, $str); }


    /**
     * @param $string
     * @param string $removeString
     * @return bool|string
     */
    static function leftTrim($string, $removeString=''){ if(!self::startsWith($string, $removeString)) return $string; return substr($string, strlen($removeString)); }

    // normaliser
    static function toArrayTree($array, $delimiter = ',') {
        return implode('\n', explode($delimiter, json_encode(($array))));
    }

    /**
     * Pointer Data if Data not null or empty
     * @param $data
     * @param bool $stringScan
     * @return bool
     */
    static function is_empty(&$data, $stringScan = true){
        if(!isset($data) || !$data) return true;
        if(is_array($data) && (count($data) < 1)) return true;
        if((is_integer($data) || is_double($data)) && ($data < 0.1)) return true;
        if((is_string($data) && (trim($data) === ''))) true;
        if(is_string($data) && $stringScan && strtolower($data) === 'null') return true;
        return false;
    }

    /** Non-Pointer Data if Data not null or empty
     * @param $data
     * @param bool $stringScan
     * @return bool
     */
    static function isEmpty($data, $stringScan = true){ return self::is_empty($data, $stringScan); }

    /**
     * Pointer, if Empty Then Return , Or ELse
     * @param $data
     * @param string $thenValue
     * @param string $elseValue
     * @return string
     */
    static function if_empty(&$data, $thenValue = '', $elseValue = ''){ return self::is_empty($data)? $thenValue: $elseValue; }

    /**
     * Non-Pointer, if Empty Then Return , Or ELse
     * @param $data
     * @param string $thenValue
     * @param string $elseValue
     * @return string
     */
    static function ifEmpty(&$data, $thenValue = '', $elseValue = ''){ return self::if_empty($data, $thenValue, $elseValue); }


    /**
     * not empty
     * @param $data
     * @param string $thenValue
     * @param string $elseValue
     * @return string
     */
    static function ifNotEmpty($data, $thenValue = '', $elseValue = ''){ return !self::is_empty($data)? $thenValue: $elseValue; }

    /**
     * main If function
     * @param $data
     * @param string $thenValue
     * @param string $elseValue
     * @return string
     */
    static function IfThen($data, $thenValue = '', $elseValue = ''){
        return (($data == true) || ($data == 1) || (trim(strtolower($data)) == 'true'))? $thenValue: $elseValue;
    }

    /**
     * Pointer , If Value isSet or Value Not Null or Empty then return Value Else Return DefaultValue
     * @param $data
     * @param string $defaultValue_IfNotSet
     * @return string
     */
    static function isset_or(&$data, $defaultValue_IfNotSet = "")  { return self::if_empty($data, $defaultValue_IfNotSet, $data);}

    /**
     * Non-Pointer , If Value isSet or Value Not Null or Empty then return Value Else Return DefaultValue
     * @param $data
     * @param string $defaultValue_IfNotSet
     * @return string
     */
    static function isSetOr($data, $defaultValue_IfNotSet = "")  { return self::isset_or($data, $defaultValue_IfNotSet); }

    /**
     * Many Confirmation
     * @param mixed ...$valueListInAscendingOrder
     * @return bool|mixed
     */
    static function isset_any(...$valueListInAscendingOrder) { foreach ($valueListInAscendingOrder as $i=>$v){ if(!self::is_empty($valueListInAscendingOrder[$i]))  return $valueListInAscendingOrder[$i];}return false; }

    /**
     * Return Any Not Empty or Null Value
     * @param array ...$valueListInAscendingOrder
     * @return mixed|null
     */
    static function useAvailableValue(...$valueListInAscendingOrder){
        foreach ($valueListInAscendingOrder as $availableValue) { if(!self::is_empty($availableValue))  return $availableValue; }
        return false;
    }


    /**
     * Instantiate Null Value to Given Value
     * @param $data
     * @param string $defaultValue
     * @return string
     */
    static function nullTo($data, $defaultValue = ''){
        if($data == null || @trim(strtolower($data)) == 'null') return $defaultValue;return $data;
    }


    /**
     * @param array $keyValueArray
     * @param string $else
     * @return mixed|string
     *     (return array key value if it's key = true... otherwise if none key is true, return $else variable)
     */
    static function ifKeyIsTrue_returnKeyValue($keyValueArray = [], $else = ''){
        foreach ($keyValueArray as $key=>$value)if($key == true) return $value;
        return $else;
    }

    static function ifKeyEqualValue($equalKeyValueList = [],  $IfEqualThen = "active", $else = ''){
        foreach ($equalKeyValueList as $key=>$value) if (  $key === $value ) return $IfEqualThen;
        return $else;
    }

    static function ifAllValueEquals($then = "active", $else = '', ...$valueList){
        $isAllTrue = true; $lastValue = '------*-----';
        foreach ($valueList as $value) { if($lastValue === '------*-----') $lastValue = $value; if($lastValue !== $value) $isAllTrue = false; }
        return ($isAllTrue)? $then: $else;
    }

    static function isAllTrue(...$conditionValueList){
        foreach ($conditionValueList as $key)if(!$key || $key == false) return false;
        return true;
    }

    static function isAnyTrue(...$conditionValueList){
        foreach ($conditionValueList as $key) if ($key == true) return true;
        return false;
    }

}

class Converter1{
    /**
     * Email Template Parser Class.
     * @param string $templateHtml_or_filePath HTML template string OR File path to a Email Template file.
     * @param array $param ['userName'=>'Samson Iyanu', 'email'=>'samsoniyau@hotmail.com']
     * @return null|string
     */
    public function bladeTemplateToHtml($templateHtml_or_filePath, $param = []) {
        $_openingTag = '{{';
        $_closingTag = '}}';
        $_valueList = [];

        try
        {

            if(file_exists($templateHtml_or_filePath)) $_template = file_get_contents($templateHtml_or_filePath);// Template HTML is stored in a File
            else if(is_string($templateHtml_or_filePath)) $_template = $templateHtml_or_filePath; // Template HTML is stored in-line in the $emailTemplate property!
            else throw new Exception('ERROR: Invalid Template.  $template must be a String or else a FilePath');

            // load Parameter
            if(is_array($param))  foreach ($param as $key => $value) $_valueList[$key] = $value;
            else throw new Exception('ERROR: Must be an ARRAY.');

            // output
            $html = $_template;
            foreach ($_valueList as $key => $value) {
                if(isset($value) && $value != '')
                    // Better Regex Required for Better Parse
                    $html = str_replace($_openingTag . $key . $_closingTag, $value, $html);
            }
            return $html;
        } catch(Exception $e) {
            echo $e->getMessage(). ' | FILE: '.$e->getFile(). ' | LINE: '.$e->getLine();
        }
        return null;
    }


}

class Array1{




    /**
     * make value array, e.g 'samson' will become ['samson'] if no param passed in for $ifNuArray_SplitWith_orNullToWrapAsArray , ignore existing array
     * @see Array1::toArray()
     * @param $value
     * @param null $ifNuArray_SplitWith_orNullToWrapAsArray
     * @return array|mixed
     */
    static function makeArray($value, $ifNuArray_SplitWith_orNullToWrapAsArray = null) { return self::toArray($value, $ifNuArray_SplitWith_orNullToWrapAsArray); }

    /**
     * If Array contains only Single item, return only the item
     * @param array $arrayList
     * @return array|mixed
     */
    static function normalizeIfSingleArray($arrayList) {
        if(!is_array($arrayList)) return $arrayList;
        return count($arrayList) === 1? $arrayList[0]: $arrayList;
    }


    /**
     * make value array, e.g 'samson' will become ['samson'] if no param passed in for $ifNuArray_SplitWith_orNullToWrapAsArray , ignore existing array
     * @see Array1::makeArray()
     * @param $value
     * @param null $ifNuArray_SplitWith_orNullToWrapAsArray
     * @return array|mixed
     */
    static function toArray($value, $ifNuArray_SplitWith_orNullToWrapAsArray = null){
        if(is_array($value)) return $value;
        if(is_object($value)) return Object1::toArray($value);
        else{
            try{ if($ifNuArray_SplitWith_orNullToWrapAsArray) return explode($ifNuArray_SplitWith_orNullToWrapAsArray, $value); }catch(Exception $exception){   }
            return [$value];
        }
    }

    static function toObject($value, $className = null) { return Object1::convertArrayToObject($value, $className); }


    /**
     *
     * orderBy(
            [
            ['id' => 2, 'name' => 'Joy'],
            ['id' => 3, 'name' => 'Khaja'],
            ['id' => 1, 'name' => 'Raja']
            ],
        'id',
        'desc'
        ); // [['id' => 3, 'name' => 'Khaja'], ['id' => 2, 'name' => 'Joy'], ['id' => 1, 'name' => 'Raja']]
     * @param array $items
     * @param string $keyToSortWith
     * @param string $orderType
     * @return array
     */
    static function orderBy(array $items, $keyToSortWith = 'id', $orderType = 'asc'){
        $sortedItems = [];
        foreach ($items as $item) {
            $key = is_object($item) ? $item->{$keyToSortWith} : $item[$keyToSortWith];
            $sortedItems[$key] = $item;
        }
        if ($orderType === 'desc') {
            krsort($sortedItems);
        } else {
            ksort($sortedItems);
        }
        return array_values($sortedItems);
    }

    /**
     * Groups the elements of an array based on the given function.
     * groupBy(['one', 'two', 'three'], 'strlen'); // [3 => ['one', 'two'], 5 => ['three']]
     * @param $items
     * @param $func
     * @return array
     */
    static function groupBy($items, $func){
        $group = [];
        foreach ($items as $item) {
            if ((!is_string($func) && is_callable($func)) || function_exists($func)) {
                $key = call_user_func($func, $item);
                $group[$key][] = $item;
            } elseif (is_object($item)) {
                $group[$item->{$func}][] = $item;
            } elseif (isset($item[$func])) {
                $group[$item[$func]][] = $item;
            }
        }
        return $group;
    }


    /**
     * Flattens an array up to the one level depth.
     * flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
     * @param array $items
     * @return array
     */
    static function flatten(array $items){
        $result = [];
        foreach ($items as $item) {
            if (!is_array($item)) {
                $result[] = $item;
            } else {
                $result = array_merge($result, array_values($item));
            }
        }
        return $result;
    }

    /**
     * Deep flattens an array.
     * deepFlatten([1, [2], [[3], 4], 5]); // [1, 2, 3, 4, 5]
     * @param $items
     * @return array
     */
    static function deepFlatten($items){
        $result = [];
        foreach ($items as $item) {
            if (!is_array($item)) {
                $result[] = $item;
            } else {
                $result = array_merge($result, self::deepFlatten($item));
            }
        }

        return $result;
    }

    /**
     * Returns true if the provided function returns true for all elements of an array, false otherwise.
     * all([2, 3, 4, 5], function ($item) {
            * return $item > 1;
        * }); // true
     * @param $items
     * @param $functionToValidateWith
     * @return bool
     */
    function ifAll($items, $functionToValidateWith){
        return count(array_filter($items, $functionToValidateWith)) === count($items);
    }

    /**
     * Returns true if the provided function returns true for at least one element of an array, false otherwise.
     *  any([1, 2, 3, 4], function ($item) {
     * return $item < 2;
     * }); // true
     * @param $items
     * @param $functionToValidateWith
     * @return string
     */
    static function  ifAny($items, $functionToValidateWith){
        return count(array_filter($items, $functionToValidateWith)) > 0;
    }


    /**
     * @param $array
     * @return string
     */
    static function hashCode($array){
        return hash('md5',json_encode($array));
    }

    /**
     * Convert array to JSON
     */
    static function toJSON($array){ return json_encode($array); }

    /**
     * Load array from JSON
     */
    static function fromJSON($array){ return json_decode($array, true); }

    /**
     * Save array to JSON Path
     * @see Array1::readFromJSON()
     */
    static function saveAsJSON($array, $toFilePath = null){ 
        if(!$toFilePath) return false;
        $dirName = dirname($toFilePath);
        $fileName = FileManager1::getFileName($toFilePath);
        if(!empty($dirName)) FileManager1::createDirectory( $dirName );
        $full_path = $dirName.'/'.$fileName;
        return FileManager1::write($full_path, static::toJSON($array));    
    }

    /**
     * Load array from JSON Path
     * @see Array1::saveAsJSON()
     * @param null $fromFilePath
     * @return bool|mixed
     */
    static function readFromJSON($fromFilePath = null){ 
        if(!file_exists($fromFilePath)) return false;
        return static::fromJSON( FileManager1::read($fromFilePath) );
    }

    /**
     * Duplicate array value as key
     *  e.g [hi, hello, thnks] = [hi=hi, hello=hello, thnks=thnks]
     * @param $valueList
     * @return array
     */
    static function reUseValueAsKey($valueList){
        $newArray = [];
        foreach ($valueList as $key => $value){ $newArray[$value]= $value; }
        return $newArray;
    }


    /**
     * This is a type of arrey that occured in form request array of form control
     * Example
     *      <input type="file" name="images[]">
     *      to get $_FILE['images'] as separate control, because the control name is array, you will need this
     *
     * "name"     =>  array(3)
        [
            0 => string(8) "logo.png"
            1 => string(24) "FB_IMG_1477050973313.jpg"
            2 => string(24) "FB_IMG_1477050973313.jpg"
    ]
        "type"     =>  array(3)
            [
            0 => string(9) "image/png"
            1 => string(10) "image/jpeg"
            2 => string(10) "image/jpeg"
     *
     *
     * @param $linearArray
     * @return array
     */
    static function normalizeLinearRequestList($linearArray){
        $allKeys = array_keys($linearArray);
        $files = [];
        if( is_array($linearArray[$allKeys[0]])) {
            $totalCount = count($linearArray[$allKeys[0]]);
            for($i = 0; $i<$totalCount; $i++){
                foreach ($allKeys as $keyName) $files[$i][$keyName] = $linearArray[$keyName][$i];
            }
        }
        return $files;
    }


    /**
     * @param $list
     * @param string $logic
     * @return array
     */
    static function maxOrMinKeyValue($list, $logic = '>'){
        $keyCount = ($logic === '<')? array_values(self::maxOrMinKeyValue($list, '>'))[0]: 0;
        foreach ($list as $value){
            if($logic === '>')  { if($value > $keyCount) $keyCount = $value; }
            else { if($value < $keyCount) $keyCount = $value; }
        }
        $maxKey = array_search($keyCount, $list);
        return [$maxKey=> $list[$maxKey]];
    }

    /**
     * @param $list
     * @param string $login
     * @return int
     */
    static function maxOrMin($list, $login = '>'){
        $keyCount = ($login === '<')? (self::maxOrMin($list, '>')): 0;
        foreach ($list as $key=> $value) {
            if($login === '>')  { if($value > $keyCount) $keyCount = $value; }
            else { if($value < $keyCount) $keyCount = $value; }
        }
        return $keyCount;
    }


    /**
     * @param string $separator
     * @param $arrayList
     * @param bool $recursive
     * @return string
     */
    static function implode($separator = ',', $arrayList, $recursive = true){
        $output = "";
        foreach ($arrayList as $av){
            if (is_array ($av) && $recursive) $output .= self::implode($separator, $av); // Recursive Use of the Array
            else $output .= $separator.$av;
        }
        return $output;
    }


    /**
     * Extract Array From Mark Up
     * @param $xmlObject
     * @return array
     */
    static function fromXMLObject ($xmlObject){
        $initArrayList = array ();
        foreach ( (array) $xmlObject as $index => $node )
            $initArrayList[$index] = ( is_object ( $node ) ) ? self::fromXMLObject ( $node ) : $node;
        return $initArrayList;
    }

    /**
     * Extract Array From Mark Up
     * @param $xml_data
     * @return SimpleXMLElement[]
     */
    static function fromXML($xml_data){
        $xml = simplexml_load_string($xml_data); //return SimpleXMLElement, wic can be passsed to self::fromXMLObject()
        return $xml->xpath('/ROOT');
    }


    /**
     * @param $array array
     * @param string $append
     * @param string $prepend
     * @return array
     *      Surround Array Items with Appended/Prepended Data
     */
    static function wrap($array, $append = '', $prepend = ''){
        return array_map(function($item) use ($append, $prepend){
            return $append.$item.$prepend;
        }, $array);
    }

    /**
     * @param $array array
     * @return string Last Array
     */
    static function getLastItem($array){ return end($array); }

    /**
     * @param $array array
     * @return string Last Array
     */
    static function getFirstItem($array){ return isset($array[0])?$array[0]:null; }

    static function pickOne(array $options){ return $options[array_rand($options)]; }

    /**
     * @param array $key_and_value
     * @param string $keyValueDelimiter
     * @param string $delimiter
     * @param string $keyWrap
     * @param string $valueWrap
     * @return string
     *      merger KeyValue together
     *      E.G self::mergeKeyValue($key_and_value = ['name'=>'samson', 'email'=>'sams@gmail.com'], $keyValueDelimiter = '=', $delimiter = ' , ', $keyWrap = "%s", $valueWrap = "(%s)")
     *          OUTPUT: name=(samson) , email=(sams@gmail.com)
     *
     */
    static function mergeKeyValue($key_and_value = [], $keyValueDelimiter = '=', $delimiter = ' ', $keyWrap = "%s", $valueWrap = "%s"){
        $str = '';
        $index=0;
        foreach($key_and_value as $key=>$value){
            if($index != 0) $str .= $delimiter;
            $str .= sprintf($keyWrap, $key). $keyValueDelimiter. sprintf($valueWrap, $value);
            $index++;
        }
        return $str;
    }


    /**
     * @param array $attributes
     * @param bool $allowNumber prevent ['class'=>'col-3', checked, food] = class='col-3' 0="checked"  1="food"
     * @return string class="col-3" checked value="online"
     */
    static function toHtmlAttribute($attributes = [], $allowNumber = false){
        if (empty($attributes))  return '';
        if (!is_array($attributes))  return $attributes;
        $attributePairs = [];
        foreach ($attributes as $key => $val) {
            if (is_int($key))  $attributePairs[] = $val;
            else {
                $val = htmlspecialchars($val, ENT_QUOTES);
                $attributePairs[] = "{$key}=\"{$val}\"";
            }
        }
        return join(' ', $attributePairs);
    }


    /**
     * @param string $startWith Start With String
     * @param null $andEndWith
     * @param array $arrayToSearch
     * @param array $except
     * @return array
     * @internal param string $endWith End With String
     */
    static function getArraysWith($startWith=null, $andEndWith=null, $arrayToSearch = [], $except = []){
        $newVar = [];

        $isStartWithAvailable = ($startWith && $startWith !== '');
        $isEndWithAvailable = ($andEndWith && $andEndWith !== '');

        foreach ($arrayToSearch as $key => $value) {
            $addKey = [];
            if($isStartWithAvailable && $isEndWithAvailable && !in_array($key, $except)){
                if(String1::startsWith($key, $startWith) && String1::endsWith($key, $andEndWith) ) $addKey[$key] = $value;

            } else if($isStartWithAvailable  && !in_array($key, $except)){
                if(String1::startsWith($key, $startWith)) $addKey[$key] = $value;

            } else if($isEndWithAvailable  && !in_array($key, $except)){
                if(String1::endsWith($key, $andEndWith)) $addKey[$key] = $value;

            } else if(!in_array($key, $except)){
                $addKey[$key] = $value;

            }

            $newVar = array_merge($newVar, $addKey);
        }
        return $newVar;
    }


    /**
     * Filter and Remove Empty Space from Array
     * @param $delimiter
     * @param $string
     * @return array
     */
    static function splitAndFilterArrayItem($delimiter, $string){
        $string = trim($string, $delimiter);
        return  self::filterArrayItem(  explode($delimiter, $string)  );
    }

    /**
     * Filter and Remove Empty Space from Array
     * @param $array
     * @param string $callbackFilterFunction
     * @return array
     */
    static function filterArrayItem($array, $callbackFilterFunction = 'strlen'){
        return  (array_filter(Array1::toArray($array), $callbackFilterFunction));
    }



    /**
     * @param array $array_key_value
     * @param array $exceptKeyList
     * @param string $callbackSanitizeFunction
     * @return array
     *
     *  Filter array Item With A Function That accept $value Parameter
     */
    static function sanitizeArrayItemValue($array_key_value = [], $exceptKeyList = [], $callbackSanitizeFunction='static::getSanitizeValue'){
        $arrBuff = [];
        foreach ($array_key_value as $key=>$value){
            if($exceptKeyList && (count($exceptKeyList) > 0) && in_array($key, $exceptKeyList)) $arrBuff[$key] = ($value);
            else $arrBuff[$key] = $callbackSanitizeFunction($value);
        }
        return $arrBuff;
    }


    /**
     * Filter and Remove Empty Space from Array
     * @param $arrayList
     * @param string $defaultValue
     * @param array $excludeKey
     * @return array
     */
    static function initEmptyValueTo($arrayList, $defaultValue = '', $excludeKey = []){
        $arrayValueList = [];
        foreach ($arrayList as $key=>$value){
            $newData = [];

            if(!in_array($key, $excludeKey)){
                if(String1::is_empty($value)) $newData[$key] = $defaultValue;
                else  $newData[$key] = $value;
                $arrayValueList += $newData;
            }
        }
        return  $arrayValueList;
    }

    /**
     * Remove Un wanted Key From Array
     * @param $arrayList
     * @param array $excludeKey
     * @return array
     */
    static function except($arrayList, $excludeKey = []){
        $arrayList = self::makeArray($arrayList);
        $excludeKey = self::makeArray($excludeKey);
        foreach ($excludeKey as $key){
            if(isset($arrayList[$key])) unset($arrayList[$key]);
        }
        return  $arrayList;
    }


    /**
     * Fill Data into array, usually useful in Table where you don't want to miss a column, and you trynna balance table rows together.
     *
     * @param $array
     * @param $spaceCountToFill
     * @param string $valueToFIll
     */
    static function fillRemainingSpace(&$array, $spaceCountToFill, $valueToFIll = ' '){
        $array = array_merge($array, array_fill(0, ($spaceCountToFill), $valueToFIll));
    }


    static function trim($array = [], $trimCharSet = '( )"\''){
        return array_map(
            function($item){
                global $trimCharSet;
                return trim($item, $trimCharSet);
            },
            $array
        );
    }

    public static function exists($arrayList, $keyToSearch){
        if ($arrayList instanceof ArrayAccess) return $arrayList->offsetExists($keyToSearch);
        return array_key_exists($keyToSearch, $arrayList);
    }

    static function removeKeys($array, $keysToRemoveList = []) {
        foreach ($keysToRemoveList as $key){ if($key) unset($array[$key]); };
        return $array;
    }

    static function replaceKeyName($array, $oldKeyName, $newKeyName){
        $array[$newKeyName] = $array[$oldKeyName]; unset($array[$oldKeyName]); return $array;
    }



    /**
     * @param array $arrayList of Value to replace keyName
     * @param array $oldName_equals_to_newName (Replace $arrayList KeyName with keyValue)
     * @return array
     */
    static function replaceKeyNames($arrayList, $oldName_equals_to_newName = ['oldName'=>'newName']){
        if(!$oldName_equals_to_newName || empty($oldName_equals_to_newName)) return $arrayList;

        $newNames = [];
        $allNewName = array_keys($oldName_equals_to_newName);
        foreach ($arrayList as $key=> $value){
            if(in_array($key, $allNewName)) $newNames[$oldName_equals_to_newName[$key]] = $value;
            else $newNames[$key] = $value;
        }
        return $newNames;
    }


    /**
     * @param $arrayList Array of Value to replace keyName
     * @param array $oldValue_equals_to_newValues
     * @return array
     * @internal param array $oldName_equals_to_newName (Replace $arrayList KeyName with keyValue)
     */
    static function replaceValues($arrayList, $oldValue_equals_to_newValues = ['one'=>'1']){
        if(!$oldValue_equals_to_newValues || empty($oldValue_equals_to_newValues)) return $arrayList;
        $newValues = [];
        $allNewValues = array_keys($oldValue_equals_to_newValues);
        foreach ($arrayList as $key => $value) {
            if(in_array($value, $allNewValues)) $newValues[$key] = $allNewValues[$value];
            else $newValues[$key] = $value;
        }
        return $newValues;
    }






    public static function containValue($arrayList, $keyToSearch){
        $valueList = array_values($arrayList);
        return isset($valueList[$keyToSearch]);
    }


    /**
     *
     * Search Array key and Value for a particular list of another array
     *  @see Array1::startsWith(),  @see Array1::endsWith()
     *
     * @param array $arrayList
     * @param array $needleListToSearch
     * @param bool $recursive
     * @param string $searchPosition [ could be 'contain' or 'start' or 'end']
     * @return array
     */
    static function contain($arrayList = [], $needleListToSearch = [], $recursive = false, $searchPosition = 'contain'){
        $exists = [];
        foreach (self::makeArray($arrayList) as $key => $value) {
            foreach (self::makeArray($needleListToSearch) as $needleValue ){
                if($recursive) if (is_array($value))  array_merge($exists, self::makeArray(self::search($value, $needleListToSearch, $recursive)));
                $isStartEnd = (($searchPosition === 'contain') && ((!is_array($key) && String1::contains($needleValue, $key)) || (!is_array($value) && String1::contains($needleValue, $value))));
                $isStart = (($searchPosition === 'start') && ((!is_array($key) && String1::startsWith($key, $needleValue)) || (!is_array($value) && String1::startsWith($value, $needleValue))));
                $isEnd = (($searchPosition === 'end') && ((!is_array($key) && String1::endsWith($key, $needleValue)) || (!is_array($value) && String1::endsWith($value, $needleValue))));

                if( $isStartEnd || $isStart || $isEnd){
                     $exists[$key] = $value;
                     continue;
                }
            }
        }
        return $exists;
    }

    static function startsWith($arrayList = [], $needleListToSearch = [], $recursive = false){ return self::contain($arrayList, $needleListToSearch, $recursive, 'start'); }

    static function endsWith($arrayList = [], $needleListToSearch = [], $recursive = false){ return self::contain($arrayList, $needleListToSearch, $recursive, 'end'); }

    /**
     * Get Last Array
     * @param array $array
     * @return mixed
     */
    static function last($array = []){ $dd = $array; return end($dd); }

    /**
     * Array Pop off last Element
     * @param array $array
     * @return array
     */
    static function removeLast($array = []){ array_pop($array); return $array; }


    /**
     * Array Pop  off first Element
     * @param array $array
     * @return array
     */
    static function removeFirst($array = []){ array_shift($array); return $array; }


    /**
     * @param callable|null $callback
     * @param array $primaryAndCompleteArray
     * @param array $otherArray
     * @return array
     *              return all common field present in $primaryAndCompleteArray and $otherArrayList1, $otherArrayList2...
     *              FOR LARAVEL REQUEST VALIDATE, USE Request2::getAvailableFields();
     */
    static public function getCommonField(Callable $callback = null, $primaryAndCompleteArray = [], ...$otherArray){
        $requestKeyValue = [];
        foreach ($primaryAndCompleteArray as $key=>$value) {
            $isKeyExists = true;
            foreach ($otherArray as $array) {if (!isset($array[$key])) $isKeyExists = false;}
            if($isKeyExists) {$requestKeyValue[$key] = ($callback)? $callback($value): $value;}
        }
        return $requestKeyValue;
    }


    /**
     * Escapse Value with quote
     * @param $arrayList
     * @return string
     */
    static function addSlashes($arrayList){
        if(is_array($arrayList)){
            foreach($arrayList as $n=> $v){
                $b[$n]=self::addSlashes($v);
            }
            return $b;
        }else{
            return addslashes($arrayList);
        }
    }


    /**
     * @param array $array
     * @param int $count
     * @param bool $allowDuplicates
     * @return array
     */
    public static function randomElements(array $array = array('a', 'b', 'c'), $count = 1, $allowDuplicates = false){
        $allKeys = array_keys($array);
        $numKeys = count($allKeys);
        if (!$allowDuplicates && $numKeys < $count) throw new \LengthException(sprintf('Cannot get %d elements, only %d in array', $count, $numKeys));
        $highKey = $numKeys - 1;
        $keys = $elements = array();
        $numElements = 0;
        while ($numElements < $count) {
            $num = mt_rand(0, $highKey);
            if (!$allowDuplicates) {
                if (isset($keys[$num])) continue;
                $keys[$num] = true;
            }
            $elements[] = $array[$allKeys[$num]];
            $numElements++;
        }
        return $elements;
    }
}

class RecursiveArrayObject1 extends \ArrayObject {
    public function __construct($input = null, $flags = self::ARRAY_AS_PROPS, $iterator_class = "ArrayIterator"){
        foreach($input as $k=>$v) $this->__set($k, $v);
        return $this;
    }
    public function __set($name, $value){
        if (is_array($value) || is_object($value))
            $this->offsetSet($name,(new self($value)));
        else
            $this->offsetSet($name, $value);
    }
    public function __get($name){
        if ($this->offsetExists($name))
            return $this->offsetGet($name);
        elseif (array_key_exists($name, $this)) {
            return $this[$name];
        }
        else {
            throw new \InvalidArgumentException(sprintf('$this have not prop `%s`',$name));
        }
    }
    public function __isset($name){
        return array_key_exists($name, $this);
    }
    public function __unset($name){
        unset($this[$name]);
    }
}

class ArrayObject1  extends ArrayObject{

    public function __get($index){ if ($this->offsetExists($index)) return $this->offsetGet($index);  else  return null;}//throw new UnexpectedValueException('Undefined key ' . $index); }

    public function __set($index, $value){ $this->offsetSet($index, $value); return $this;}

    public function __isset($index){return $this->offsetExists($index);}

    public function __unset($index){ return $this->offsetUnset($index); }

    public function __toString() { return serialize($this); }


    public function __construct(...$object_or_array) { foreach ($object_or_array as $arguments){ if (!empty($arguments)) { foreach ($arguments as $property => $argument) { $this->{$property} = $argument; } } } }

    public function addObject(...$object_or_array) { foreach ($object_or_array as $arguments){ if (!empty($arguments)) { foreach ($arguments as $property => $argument) { $this->{$property} = $argument; } } } }
    public function addMethod($methodName, callable $callback) { $this->{$methodName} = $callback; }


    public function __call($method, $arguments) {
        if (isset($this->{$method}) && is_callable($this->{$method})) {
            return call_user_func_array($this->{$method}, $arguments);
        } else {
            throw new Exception("Fatal error: Call to undefined method stdObject::{$method}()");
        }
    }
}

class Class1{

    /**
     * @param array|object $object_or_array
     * @return mixed
     * <p>
     *     this can be use to merge php class object together,
     *     to make object behave like array and array like object,
     *     and also show all functions in each object.
     *     to add more function
     *         Example
     *             $flexibleObject = Class1::toArrayObject(true,  (new User), (new Picture) );
     *             $flexible->newMethod = function (){
     *                 return 'hello world';
     *             }
     *
     *
     *             echo $flexibleObject->fullName;
     *                         OR
     *             echo $flexibleObject['fullName'];
     *
     *                         OR
     *             Console1::print( $flexibleObject );
     * </p>
     */
    public static function toArrayObject(true, ...$object_or_array){


        // create flexible ArrayObject that allows onFly Method to be added
        $flexibleObject = null;
        for($i=0; $i<count($object_or_array); $i++){
            if($i === 0) $flexibleObject = new ArrayObject1($object_or_array[$i]); // new ArrayObject($object_OR_array, ArrayObject::ARRAY_AS_PROPS)
            else $flexibleObject->addObject($object_or_array[$i]); // merge multiple object
        }

        // Add List Of Existing Methods in '$object_or_array' to Current Object
        foreach ($object_or_array as $object ){
            if(is_object($object)){
                foreach ( get_class_methods($object) as &$method ) { //// get_object_vars($clunker)
                    $flexibleObject->{$method} = function(...$param) use ($object, $method) { return call_user_func_array([($object), $method], $param); };
                }
            }
        }

        return $flexibleObject;
    }


    static function cast($object, $class = 'object', $addMethods = false) {
        if( !class_exists($class) ) $class = __NAMESPACE__ . "\\$class";
        if( !class_exists($class) ) throw new InvalidArgumentException(sprintf('Unknown class: %s.', $class));

        // case with serialization
        $newObject = @unserialize(
            preg_replace(
                '/^O:\d+:"[^"]++"/',
                'O:'.@strlen($class).':"'.$class.'"',
                serialize($object)
            )
        );

        // add methods
        if($addMethods && is_object($object)){
            foreach ( get_class_methods(new $class) as &$method ) {
                $newObject->{$method} = function(...$param) use ($object, $method) { return call_user_func_array([($object), $method], $param); };
            }
        }

        return $newObject;
    }



    static function toObject($array, $className = null, $addMethod = false){ return self::convertArrayToObject($array, $className, $addMethod); }

    static function toArray($object){ return json_decode( json_encode($object) , 1);}

    static function convertObjectToArray($object) {
        if(is_array($object)) return $object;
        $_arr = is_object($object) ? get_object_vars($object) : $object;
        $arr = array();
        foreach ($_arr as $key => $val) {
            $val = (is_array($val) || is_object($val)) ? self::convertObjectToArray($val) : $val;
            $arr[$key] = $val;
        }
        return $arr;
    }


    /**
     * @param $array
     * @param string $className
     * @param bool $addMethod
     * @return bool|mixed|$class
     */
    static function convertArrayToObject($array, $className = null, $addMethod = false) {
        if(String1::startsWith($className, 'class@anonymous')) return $array;
        $value = json_decode(json_encode($array), FALSE);
        return ($className)? self::cast($value, $className, $addMethod): $value;
    }


    static function hashCode($obj){
        return spl_object_hash($obj);
    }

    static function mergeObject(...$object_or_array){
        $className = '';
        $objArray = [];
        for($i=0; $i<count($object_or_array); $i++){
            if($i === 0) $className = get_class($object_or_array[$i]);
            $objArray = array_merge($objArray, (array)$object_or_array[$i]); // merge multiple object
        }
        return self::convertArrayToObject($objArray, $className);
    }


    static function getClassObjectVariables($object){
        return get_object_vars($object);
    }

    // both static and object variables
    static function getClassVariables($object){
        return get_class_vars(get_class($object));
    }

    //It relies on an interesting property: the fact that get_object_vars only returns the non-static variables of an object.
    static function getClassStaticVariables($object){
        //print_r( array_diff(self::getAllClassVariables($object), self::getClassVariables($object)) );
        if(is_string($object)) $object = new $object;
        return array_diff(get_class_vars(get_class($object)), get_object_vars($object));
    }


    /**
     * Get Session Executed Class by Name or by Parent Class with debug_backtrace()
     *
     * @param array $classList
     * @param callable $onFoundCallBack
     * @param bool $searchParentClass
     * @return array
     */
    static function getExecutedClass($classList = [], $searchParentClass = false, callable $onFoundCallBack = null){
        $classPie = [];
        foreach (debug_backtrace() as $calledClassInfo){
            foreach (Array1::makeArray($classList) as $class){
                if(isset($calledClassInfo['class']) && $calledClassInfo['class']){
                    if( $calledClassInfo['class'] ==  $class || ( $searchParentClass && self::isParentClassExistIn($calledClassInfo['class'], $class)) ){
                        if($onFoundCallBack)  $onFoundCallBack($calledClassInfo['class']);
                        $classPie[] = $calledClassInfo['class'];
                    }
                }
            }
        }
        return $classPie;
    }



    /**
     * Find Parent Class
     * @param $class
     * @param $parentClass
     * @return bool
     */
    static function isParentClassExistIn($class, $parentClass){ return in_array($parentClass, class_parents($class)); }

    /**
     * Find Parent Implementation
     * @param null $className
     * @param null $parentInterface
     * @return bool
     */
    static function isInterfaceImplementExistIn($className = null, $parentInterface = null){ return in_array($parentInterface, class_implements($className)); }
}

class Object1 extends Class1{ }



class Function1{
    /**
     * Call a function only once.
     * @param $function
     * @return Closure
     */
    static function runOnce($function){
        return function (...$args) use ($function) {
            static $called = false;
            if ($called) {return ;}
            $called = true;
            return $function(...$args);
        };
    }

    /**
     * Return a new function that composes multiple functions into a single callable.
     * @param mixed ...$functions
     * @return mixed
     */
    static function runMultipleFunctionOnResult(...$functions){
        return array_reduce(
            $functions,
            function ($carry, $function) {
                return function ($x) use ($carry, $function) { return $function($carry($x)); };
            },
            function ($x) { return $x; }
        );
    }

    /**
     * Memoization of a function results in memory.
     *
     * $memoizedAdd = static::runAndCache(
        function ($num) { return $num + 10; }
        );

        var_dump($memoizedAdd(5)); // ['result' => 15, 'cached' => false]
        var_dump($memoizedAdd(6)); // ['result' => 16, 'cached' => false]
        var_dump($memoizedAdd(5)); // ['result' => 15, 'cached' => true]
     * @param $func
     * @return Closure
     */
    static function runAndCache($func){
        return function () use ($func) {
            static $cache = [];
            $args = func_get_args();
            $key = serialize($args);
            $cached = true;

            if (!isset($cache[$key])) {
                $cache[$key] = $func(...$args);
                $cached = false;
            }
            return $cache[$key];
            //return ['result' => $cache[$key], 'cached' => $cached];
        };
    }


    /**
     * Curries a function to take arguments in multiple calls.
     * $curriedAdd = Function1::runAndHold(
            function ($a, $b) {
                return $a + $b;
            }
        );

        $add10 = $curriedAdd(10);
        var_dump($add10(15));  // 25
     * @param $function
     * @return Closure
     */
    static function runAndHold($function){
        $accumulator = function ($arguments) use ($function, &$accumulator) {
            return function (...$args) use ($function, $arguments, $accumulator) {
                $arguments = array_merge($arguments, $args);
                $reflection = new ReflectionFunction($function);
                $totalArguments = $reflection->getNumberOfRequiredParameters();

                if ($totalArguments <= count($arguments)) {
                    return $function(...$arguments);
                }

                return $accumulator($arguments);
            };
        };
        return $accumulator([]);
    }






}





// print or popup text out
class Console1{
    /**
     *  Output Object | Array | String or any data type in a fancy PRE
     * @param string $text
     * @param bool $print_stopPageAndDie
     * @param string $title
     * @return string
     */
    static function println($text = '', $print_stopPageAndDie = false, $title = ''){
        if($text === '')  die('<br><hr><h3 align="center"> Break - [ '.date(DateManager1::date(DateManager1::$time_as24Hours)).' ] </h3><br></hr>');
        if(is_string($print_stopPageAndDie)) {$title = $print_stopPageAndDie; $print_stopPageAndDie = true; };

        echo '<pre style="direction: ltr; max-width: 90%; margin: 30px auto;overflow:auto; font-family: Monaco, Consolas, \'Lucida Console\',monospace;font-size: 16px;padding: 20px;
                       border-left:20px solid #2295bc;border-right:20px solid #2295bc; border-radius:20px; height:auto !important; 
                       white-space: pre-wrap;  white-space: -moz-pre-wrap;  white-space: -pre-wrap;  white-space: -o-pre-wrap;  word-wrap: break-word;
                       clear:both;top:0;position: relative;z-index: 9999999999;background:#e4e7e7;color:#2295bc">'.(($title !== '')?"<h2>".$title.'</h2><hr/>': '').print_r($text, true).'</pre>';

        if($print_stopPageAndDie) die(''); return '';
    }
    static function out($text = '', $stopPageAndDie = false, $title = ''){ self::println($text, $stopPageAndDie, $title); }


    static function popup(...$text){
        $textBuffer = '';

        foreach ($text as $t)
            $textBuffer .= $t.'\n';

        echo "<script> alert('$textBuffer'); </script>";
    }


    static function log($data){
        $data = String1::toString($data, ', ');
        echo "<script> console.log('----------------SystemDebug-------------'); console.debug($data); </script>";
    }



    static function popupAny($obj){
        echo "<script> alert('".String1::toArrayTree($obj)."'); </script>";
    }



    static function d($data){
        if(is_null($data)){
            $str = "<i>NULL</i>";
        }elseif($data == ""){
            $str = "<i>Empty</i>";
        }elseif(is_array($data)){
            if(count($data) == 0){
                $str = "<i>Empty array.</i>";
            }else{
                $str = "<table style=\"border-bottom:0px solid #000;\" cellpadding=\"0\" cellspacing=\"0\">";
                foreach ($data as $key => $value) {
                    $str .= "<tr><td style=\"background-color:#008B8B; color:#FFF;border:1px solid #000;\">" . $key . "</td><td style=\"border:1px solid #000;\">" . self::d($value) . "</td></tr>";
                }
                $str .= "</table>";
            }
        }elseif(is_resource($data)){
            while($arr = mysqli_fetch_array($data)){
                $data_array[] = $arr;
            }
            $str = self::d($data_array);

        }elseif(is_object($data)){
            $str = self::d(get_object_vars($data));
        }elseif(is_bool($data)){
            $str = "<i>" . ($data ? "True" : "False") . "</i>";
        }else{
            $str = $data;
            $str = preg_replace("/\n/", "<br>\n", $str);
        }
        return $str;
    }

    static function dnl($data){
        echo self::d($data) . "<br>\n";
    }

    static function dd($data){
        self::dnl($data);
        return exit? '': '';
    }

    static function ddt($message = ""){
        echo "[" . date("Y/m/d H:i:s") . "]" . $message . "<br>\n";
    }
}

class Color1{
    private static $ALL_COLOR = null;
    private static $COLOR = array(
        'inverse'=>'#2c3e50',
        'info'=>'#2d7cb5',

        'primary'=>'#337ab7',
        'success'=>'#3c763d',
        'danger'=>'#a94442',
        'error'=>'#a94442',
        'warning'=>'#E6AF5F',
    );

    static function initAllColor(){  return static::$ALL_COLOR = (static::$ALL_COLOR)? static::$ALL_COLOR: array_merge(static::$COLOR, String1::isset_or($_SESSION['website_color_list'], [])); }
    static function set($name = '', $color = ''){    static::$ALL_COLOR[$name] = $color; $_SESSION['website_color_list'][$name] = $color; }
    static function get($name = null){ return $name?  String1::isset_or(static::initAllColor()[$name], ''): Object1::toArrayObject(true, static::initAllColor()); }
    static function getAll(){ static::$ALL_COLOR; }

    // Fix Color
    static function getDanger(){ return     static::get('danger'); }
    static function getSuccess(){ return    static::get('success'); }
    static function getWarning(){ return    static::get('warning'); }
    static function getInverse(){ return    static::get('inverse'); }
    static function getInfo(){ return       static::get('info'); }
    static function getPrimary(){ return    static::get('primary'); }

    // Random Color
    static function getRandomRBG(){ return "rgb(".rand(1,255).",".rand(1,255).",".rand(1,255).")"; }
    static function getRandomName($nameList = ['danger', 'success', 'warning', 'inverse', 'info', 'primary']){ return Array1::pickOne($nameList); }
    static function getRandomHex(){ return "#".dechex(rand(1,255)).dechex(rand(1,255)).dechex(rand(1,255)); }
}


/**
 * File System Management Class
 * Class FileManager1
 */
class FileManager1{

    /**
     * Get All Data in Directory and pass to callback
     * @param $path
     * @param bool $supplyFullPath
     * @param callable|null $callBack
     * @return array
     */
    static function getDirectoryFiles($path, $supplyFullPath = true, callable $callBack = null){
        $all = [];
        foreach ( scandir( $path ) as $file ) {
            $pathName = $supplyFullPath?  $path.DIRECTORY_SEPARATOR.$file:  $file;
            if($callBack) {
                $allRaw = $callBack($pathName);
                if($allRaw) $all[] = $allRaw;
            }
            else $all[] = $pathName;
        }
        return $all;
    }


    /**
     * Get Directory Folders
     * @param string $path_orPaths
     * @param string $prepend
     * @param string $append
     * @return array|string
     */
    static function getDirectoriesFolders($path_orPaths = '.', $prepend = '', $append = ''){
        $pathList = [];
        foreach (Array1::makeArray($path_orPaths) as $path){
            foreach ( scandir( $path ) as $folder ) {
                $fullPath = $prepend.$path.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR.$append;
                if (is_dir($fullPath)) $pathList[] = $fullPath;
            }
        }
        return $pathList;
    }


    /**
     * Get all File in derectory
     * @param string $pathList
     * @param array $filterExtension
     * @param array $ignoreExtension
     * @param int $fileCount
     * @param bool $recursive
     * @return array An array, item is a file
     */
    static function getDirectoriesFiles($pathList = '.', array $filterExtension = array(), Array $ignoreExtension = array(), $fileCount = -1, $recursive = false){
        $filterExtension = !empty($filterExtension)? array_map('strtolower', $filterExtension): $filterExtension;
        $allFiles = array();
        foreach (Array1::toArray($pathList) as $path){
            $handle = @opendir($path);
            while ($file = @readdir($handle)) {
                $fullPath = rtrim($path, '/\\') . '/' . $file;
                $ext = strtolower(self::getExtension($file));
                if($file != '.' && $file != '..' ){
                    if (is_file($fullPath) && !in_array($ext, $ignoreExtension)) {

                        // filter extension
                        if (!empty($filterExtension)) {
                            if (in_array($ext, $filterExtension)){ $allFiles[] = $fullPath; }
                        } else { $allFiles[] = $fullPath; }

                        // is file list enough
                        if ($fileCount && ($fileCount > 0) && (count($allFiles) >= $fileCount)) break;
                    }else if($recursive && is_dir($fullPath)){
                        $allFiles = array_merge($allFiles, self::getDirectoriesFiles($fullPath, $filterExtension, $ignoreExtension, $fileCount, $recursive));
                    }
                }
            }
            @closedir($handle);
        }
        return $allFiles;
    }




    /**
     * Get an array containing the path of all files in this repository
     * @return array An array, item is a file
     */
    public static function getDirectoryFilesByExtension($path = '', $ext = 'json') {
        $files = [];
        $_files = glob($path.'*.'.$ext);
        foreach($_files as $file) $files[] = str_replace('.'.$ext,'',basename($file));
        return $files;
    }


    /**
     * @param string $filename
     * @return string
     */
    static function getExtension($filename = ''){
        return (strpos($filename, '.'))? Array1::getLastItem(explode(".", $filename)): $filename;
    }


    /**
     * Mime Type
     * @param string $extension
     * @return mixed|string
     */
    static function getMimeType($extension=''){
        $mimes = array('hqx' => 'application/mac-binhex40', 'cpt' => 'application/mac-compactpro', 'doc' => 'application/msword', 'bin' => 'application/macbinary', 'dms' => 'application/octet-stream', 'lha' => 'application/octet-stream', 'lzh' => 'application/octet-stream', 'exe' => 'application/octet-stream', 'class' => 'application/octet-stream', 'psd' => 'application/octet-stream', 'so' => 'application/octet-stream', 'sea' => 'application/octet-stream', 'dll' => 'application/octet-stream', 'oda' => 'application/oda', 'pdf' => 'application/pdf', 'ai' => 'application/postscript', 'eps' => 'application/postscript', 'ps' => 'application/postscript', 'smi' => 'application/smil', 'smil' => 'application/smil', 'mif' => 'application/vnd.mif', 'xls' => 'application/vnd.ms-excel', 'ppt' => 'application/vnd.ms-powerpoint', 'pptx' => 'application/vnd.ms-powerpoint', 'wbxml' => 'application/vnd.wap.wbxml', 'wmlc' => 'application/vnd.wap.wmlc', 'dcr' => 'application/x-director', 'dir' => 'application/x-director', 'dxr' => 'application/x-director', 'dvi' => 'application/x-dvi', 'gtar' => 'application/x-gtar', 'php' => 'application/x-httpd-php', 'php4' => 'application/x-httpd-php', 'php3' => 'application/x-httpd-php', 'phtml' => 'application/x-httpd-php', 'phps' => 'application/x-httpd-php-source', 'js' => 'application/x-javascript', 'swf' => 'application/x-shockwave-flash', 'sit' => 'application/x-stuffit', 'tar' => 'application/x-tar', 'tgz' => 'application/x-tar', 'xhtml' => 'application/xhtml+xml', 'xht' => 'application/xhtml+xml', 'zip' => 'application/zip', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mpga' => 'audio/mpeg', 'mp2' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'aif' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', 'ram' => 'audio/x-pn-realaudio', 'rm' => 'audio/x-pn-realaudio', 'rpm' => 'audio/x-pn-realaudio-plugin', 'ra' => 'audio/x-realaudio', 'rv' => 'video/vnd.rn-realvideo', 'wav' => 'audio/x-wav', 'bmp' => 'image/bmp', 'gif' => 'image/gif', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'jpe' => 'image/jpeg', 'png' => 'image/png', 'tiff' => 'image/tiff', 'tif' => 'image/tiff', 'css' => 'text/css', 'html' => 'text/html', 'htm' => 'text/html', 'shtml' => 'text/html', 'txt' => 'text/plain', 'text' => 'text/plain', 'log' => 'text/plain', 'rtx' => 'text/richtext', 'rtf' => 'text/rtf', 'xml' => 'text/xml', 'xsl' => 'text/xml', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mpe' => 'video/mpeg', 'qt' => 'video/quicktime', 'mov' => 'video/quicktime', 'avi' => 'video/x-msvideo', 'movie' => 'video/x-sgi-movie', 'doc' => 'application/msword', 'docx' => 'application/msword', 'word' => 'application/msword', 'xl' => 'application/excel', 'xls' => 'application/excel', 'xlsx' => 'application/excel', 'eml' => 'message/rfc822');
        return (!isset($mimes[strtolower($extension)])) ? 'application/octet-stream' : $mimes[strtolower($extension)];
    }


    /**
     * File Icon
     * @param $filePath
     * @param array|null $returnKeyMap
     * @return string
     */
    static function getFileAndType($filePath, Array $returnKeyMap = null){
        $returnKeyMap = !$returnKeyMap? [
            // media
            'media_picture'=>'fa fa-picture',
            'media_music'=>'fa fa-music',
            'media_video'=>'fa fa-video',
            // code
            'code_css'=>'fa fa-code-o',
            'code_php'=>'fa fa-php',
            'code_aspx'=>'fa fa-file-aspx',
            'code_xml'=>'fa fa-html',
            'code_database'=>'fa fa-database',
            // file
            'file_text'=>'fa fa-file-text-o',
            'file_web'=>'fa fa-code',
            'file_archive'=>'fa fa-file-archive-o',
            'file_excel'=>'fa fa-file-excel-o',
            'file_word'=>'fa fa-file-word',
            'file_powerpoint'=>'fa fa-file-powerpoint',
            'file_font'=>'fa fa-font',
            'file_pdf'=>'fa fa-file-pdf',
            'file_graphics'=>'fa fa-file-image-o',
            'file_application'=>'fa fa-file-o',
            'file_default'=>'fa fa-file-o',
            'picture'=>'fa fa-file-excel',
        ]: $returnKeyMap;

        $ext=strtolower(pathinfo($filePath,PATHINFO_EXTENSION));
        switch($ext){ case"ico":case"gif":case"jpg":case"jpeg":case"jpc":case"jp2":case"jpx":case"xbm":case"wbmp":case"png":case"bmp":case"tif":case"tiff":case"svg":
            $img=$returnKeyMap['media_picture'];break;case"passwd":case"ftpquota":case"sql":case"js":case"json":case"sh":case"config":case"twig":case"tpl":case"md":case"gitignore":case"c":case"cpp":case"cs":case"py":case"map":case"lock":case"dtd":
            $img=$returnKeyMap['file_web'];break;case"txt":case"ini":case"conf":case"log":case"htaccess":
            $img=$returnKeyMap['file_text'];break;case"css":case"less":case"sass":case"scss":
            $img=$returnKeyMap['code_css'];break;case"zip":case"rar":case"gz":case"tar":case"7z":
            $img=$returnKeyMap['file_archive'];break;case"php":case"php4":case"php5":case"phps":case"phtml":
            $img=$returnKeyMap['code_php'];break;case"htm":case"html":case"shtml":case"xhtml":case"xml":case"xsl":case"xslx":
            $img=$returnKeyMap['code_xml'];break;case"wav":case"mp3":case"mp2":case"m4a":case"aac":case"ogg":case"oga":case"wma":case"mka":case"flac":case"ac3":case"tds":case"m3u":case"m3u8":case"pls":case"cue":
            $img=$returnKeyMap['media_music'];break;case"avi":case"mpg":case"mpeg":case"mp4":case"m4v":case"flv":case"f4v":case"ogm":case"ogv":case"mov":case"mkv":case"3gp":case"asf":case"wmv":
            $img=$returnKeyMap['media_video'];break;case"xls":case"xlsx":
            $img=$returnKeyMap['file_excel'];break;case"asp":case"aspx":
            $img=$returnKeyMap['code_aspx'];break;case"sql":case"mda":case"myd":case"dat":case"sql.gz":
            $img=$returnKeyMap['code_database'];break;case"doc":case"docx":
            $img=$returnKeyMap['file_word'];break;case"ppt":case"pptx":
            $img=$returnKeyMap['file_powerpoint'];break;case"ttf":case"ttc":case"otf":case"woff":case"woff2":case"eot":case"fon":
            $img=$returnKeyMap['file_font'];break;case"pdf":
            $img=$returnKeyMap['file_pdf'];break;case"psd":case"ai":case"eps":case"fla":case"swf":
            $img=$returnKeyMap['file_graphics'];break;case"exe":case"msi":
            $img=$returnKeyMap['file_application'];break;
            default: $img=$returnKeyMap['file_default'];
        }
        return $img;
    }


    /**
     * Get File Name
     * @param string $filePath
     * @return mixed|string
     */
    static function getName($filePath = ''){
        $filePath = rtrim($filePath, '/\\');
        $filePath = Array1::last(explode('/', $filePath));
        $filePath = Array1::last(explode('\\', $filePath));
        return $filePath;
    }

    /**
     * File Extension
     * @param bool $commonPictureImage
     * @return array
     */
    static function getImageExtension($commonPictureImage = false){
        $commonImg = array('png', 'jpeg', 'gif', 'jpg');
        return $commonPictureImage? $commonImg: array_merge(['bmp',  'tiff', 'image', 'icns',   'ico'],  $commonImg);
    }

    /**
     * File Extension
     * @param bool $common
     * @return array
     */
    static function getDocumentExtension($common = false){
        $commonData = ['txt', 'xls','xlsx', 'doc', 'docx', 'pdf'];
        return $common? $commonData: array_merge(['pptx'],  $commonData);
    }

    /**
     * is File Image
     * @param $filename
     * @param bool $commonPictureImage
     * @return bool
     */
    static function isImageFile($filename, $commonPictureImage = false){
        return in_array(strtolower(self::getExtension($filename)), self::getImageExtension($commonPictureImage))? true: false;
    }

    /**
     * @param $path
     * @return null|string
     */
    static function getFileName($path){  $path = rtrim($path, '/\\');  return preg_replace('/^.+[\\\\\\/]/', '', $path); }

    /**
     * @param $path
     * @return bool|string
     */
    static function getOnlyFileName($path){ $path = rtrim($path, '/\\'); return substr(self::getFileName($path), 0, (strlen(self::getFileName($path)) - strlen(self::getExtension($path)))-1 ); }


    /**
     * @param $path
     * @return bool|string
     */
    static function getOnlyFilePath($path){ return substr($path, 0, (strlen($path) - strlen(self::getOnlyFileName($path))-1 )); }

    /**
     * @param $fileName
     * @return bool
     */
    static function delete($fileName){
        @unlink($fileName);
        @rmdir($fileName);
        return unlink($fileName);
    }

    /**
     * Delete all files in directory recursively
     */
    static function deleteAll($directory, $deleteDirectory = false){
        if (substr($directory,-1) == "/")  $directory = substr($directory,0,-1);
        if (!file_exists($directory) || !is_dir($directory)) return false;
        else if (!is_readable($directory)) return false;
        else {
            $directoryHandle = opendir($directory);
            while ($contents = readdir($directoryHandle)) {
                if($contents != '.' && $contents != '..') {
                    $path = $directory."/".$contents;
                    if(is_dir($path)) { static::deleteAll($path); }
                    else { @unlink($path); }
                }
            }
            closedir($directoryHandle);
            if($deleteDirectory) if(!rmdir($directory)) { return false; }
            return true;
        }
    }

    static function normalizeFilePathSeparator($file, $separator = '/'){
        return preg_replace("#([\\\\/]+)#", $separator, $file);
    }


    /**
     * Return relative path between two sources
     * @param $fromHalfPath
     * @param $toFullPath
     * @param string $separator
     * @return string
     *
     *  $relative = getRelativePath('/var/www/example.com','/var/www/example.com/media/test.jpg');
     *  Function will return /media/test.jpg.
     */
    static function relativePath($fromHalfPath, $toFullPath, $separator = DIRECTORY_SEPARATOR)
    {
        $fromHalfPath = str_replace(array('/', '\\'), $separator, $fromHalfPath);
        $toFullPath = str_replace(array('/', '\\'), $separator, $toFullPath);

        $arFrom = explode($separator, rtrim($fromHalfPath, $separator));
        $arTo = explode($separator, rtrim($toFullPath, $separator));
        while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0])) {
            array_shift($arFrom);
            array_shift($arTo);
        }
        return str_pad("", count($arFrom) * 3, '..' . $separator) . implode($separator, $arTo);
    }


    /**
     * @param $source_url
     * @param $destination
     * @param bool $shouldCompressIfCompressible
     * @return bool
     */
    static function upload($source_url, $destination, $shouldCompressIfCompressible = true){ return Picture1::upload($source_url, $destination, $shouldCompressIfCompressible); }


    /**
     * Generate directory structure
     * @param string $basePath , path where all directories will be created in
     * @param array $relativePathList , recursive array in structure of directories
     * @return bool
     */
    static function generateDirectories($basePath = '\\', Array $relativePathList = ['web'=>['js','css']]){
        //If array, unfold it
        foreach($relativePathList as $key => $path) {
            $folderName = is_numeric($key) ? '' : '\\' . $key;
            self::createDirectory($basePath.$folderName.'\\'.$path);
        }
    }


    static function createDirectory($path = '\\'){
        return @mkdir($path, 0777, true);
    }

     /**
     * Writes data to the filesystem.
     * @param  string $path     The absolute file path to write to
     * @param  string $contents The contents of the file to write
     * @return boolean          Returns true if write was successful, false if not.
     */
    public static function write($path, $contents) {
        $fp = fopen($path, 'w+');
        if(!flock($fp, LOCK_EX)) return false; 
        $result = fwrite($fp, $contents);
        flock($fp, LOCK_UN);
        fclose($fp);
        return $result !== false;
    }

    /**
     * read file
     */
    public static function read($path)  {
        if(!file_exists($path))  return false;
        $file = fopen($path, 'r');
        $contents = fread($file, filesize($path));
        fclose($file); 
        return $contents;
    }


    


    static function loadComposerPackage($dir){
        $composer = json_decode(file_get_contents($dir."/composer.json"), 1);
        $loadByPSR = function ($namespaces, $psr4) use ($dir) {
            // Foreach namespace specified in the composer, load the given classes
            foreach ($namespaces as $namespace => $classpaths) {
                if (!is_array($classpaths)) {
                    $classpaths = array($classpaths);
                }
                spl_autoload_register(function ($classname) use ($namespace, $classpaths, $dir, $psr4) {
                    // Check if the namespace matches the class we are looking for
                    if (preg_match("#^".preg_quote($namespace)."#", $classname)) {
                        // Remove the namespace from the file path since it's psr4
                        if ($psr4) {
                            $classname = str_replace($namespace, "", $classname);
                        }
                        $filename = preg_replace("#\\\\#", "/", $classname).".php";
                        foreach ($classpaths as $classpath) {
                            $fullpath = $dir."/".$classpath."/$filename";
                            if (file_exists($fullpath)) {
                                include_once $fullpath;
                            }
                        }
                    }
                });
            }
        };

        (isset($composer['autoload']['psr-4']) &&  $loadByPSR($composer['autoload']['psr-4'], true));
        (isset($composer['autoload']['psr-0']) && $loadByPSR($composer['autoload']['psr-0'], false));
    }


    /**
     * Validates the name of the file to ensure it can be stored in the
     * filesystem.
     *
     * @param string $name The name to validate against
     * @param boolean $safe_filename Allows filename to be converted if fails validation
     * @return bool Returns true if valid. Throws an exception if not.
     */
    public static function validateFileName($name, $convertToSafeFilenameIfFailed = false){
        if (!preg_match('/^[0-9A-Za-z\_\-]{1,63}$/', $name)) {
            if ($convertToSafeFilenameIfFailed) {
                // rename the file
                $name = preg_replace('/[^0-9A-Za-z\_\-]/','', $name);
                // limit the file name size
                $name = substr($name,0,63);
            }
            else  throw new \Exception(sprintf('`%s` is not a valid file name.', $name)); 
        }
        return $name;
    }



    private static function __autoClassRecursiveLoaderExecutor ($class, $dir = null, $initPath = null) {
        if ( is_null( $dir ) )  $dir = $initPath;
        foreach ( scandir( $dir ) as $file ) {
            // directory?
            if ( is_dir( $dir.$file ) && substr( $file, 0, 1 ) !== '.' )  self::__autoClassRecursiveLoaderExecutor( $class, $dir.$file.'/' );
            // php file?
            if ( substr( $file, 0, 2 ) !== '._' && preg_match( "/.php$/i" , $file ) ) {
                // filename matches class?
                if ( str_replace( '.php', '', $file ) == $class || str_replace( '.class.php', '', $file ) == $class )  include $dir . $file;
            }
        }
    }
    static function autoClassRecursiveLoad($initPathList = 'app'){
        //$dff =[];
        foreach (Array1::toArray($initPathList) as $initPath){
            $autoLoad = function ($class, $dir = null) use ($initPath){ FileManager1::__autoClassRecursiveLoaderExecutor($class, $dir, $initPath); };
            spl_autoload_register($autoLoad);
            //$dff[] = $initPath;
        }
        //return $dff;
    }
}

class Form1{

    /**
     * All Form Data
     * @param array $array_key_value
     * @param array $exceptKeyList
     * @param string $sanitizeFunction
     * @return array
     */
    static function sanitizeAllValue($array_key_value = [], $exceptKeyList = [], $sanitizeFunction='static::getSanitizeValue'){
        return Array1::sanitizeArrayItemValue($array_key_value, $exceptKeyList, $sanitizeFunction);
    }

    /**
     * Sanitize Form Data
     * @param $data
     * @return bool|string
     */
    static function getSanitizeValue(&$data){
        if(!isset($data))return false;
        $newData = $data;

        $newData = trim($newData);
        $newData = stripcslashes($newData);
        $newData = htmlentities($newData); // for other language attack like german / arabi...
        $newData = htmlspecialchars($newData);

        return ($newData);
    }

    /**
     * @param string $lookupClassNameOrClassFunction
     * @param string $processMethod
     * @return string
     */
    static function toClassCallableLink($lookupClassNameOrClassFunction = 'className::function(param1, param2)', $processMethod = 'process()'){
        // Trim and Generate Url
        $lookupClassNameOrClassFunction = trim($lookupClassNameOrClassFunction);
        $processMethod = trim($processMethod);
        if(class_exists($lookupClassNameOrClassFunction)) $lookupClassNameOrClassFunction = "$lookupClassNameOrClassFunction::$processMethod";
        return $lookupClassNameOrClassFunction;
    }

    /**
     * @param string $lookupClassNameOrClassFunction
     * @param string $processMethod
     * @return string
     */
    static function callController($lookupClassNameOrClassFunction = 'className::function(param1, param2)', $processMethod = 'process()') { return url('/form/'.self::toClassCallableLink($lookupClassNameOrClassFunction, $processMethod)); }

    /**
     * @param string $lookupClassNameOrClassFunction
     * @param string $processMethod
     * @return string
     */
    static function callApi($lookupClassNameOrClassFunction = 'className::function(param1, param2)', $processMethod = 'process()') { return url('/api/'.self::toClassCallableLink($lookupClassNameOrClassFunction, $processMethod)); }



    // filter out html ( storable in db too)
    static function encodeHTML($data){ return htmlentities($data); }
    static function decodeHTML($data){ return html_entity_decode($data); }


    /**
     * re-use html when store in DataBase
     * @param $data
     * @return string
     */
    static function encodeDatabaseHTML($data){ return htmlspecialchars($data);  }

    /**
     * @param $data
     * @return string
     */
    static function decodeDatabaseHTML($data){ return htmlspecialchars_decode($data); }



    static function getSanitizeNumber($id){
        // XSS protection as we might print this value
        return preg_replace("/[^0-9]+/", "", $id);
    }

    static function getSanitizeAlphaNumeric($string){
        // XSS protection as we might print this value
        return preg_replace("/[^a-zA-Z0-9]+/", "", $string);
    }

    static function getEncryptedToken($password, $addBrowserInformation = false){
        //you can change this to user own salt
        $saltStart = "R%W11302&^H2Jk";
        $saltEnd = "^*&ˆH%RwSaMsOn!-oSi";

        $otherStuff = (($addBrowserInformation)?self::getSanitizeValue($_SERVER['HTTP_USER_AGENT']):"");
        return hash("sha512", $saltStart.$password.$saltEnd.$otherStuff);
    }


    static function urlParam_toArray($GET_LIKE_stringParam = 'name=osi&age=25'){
        $param = array(); parse_str($_REQUEST[$GET_LIKE_stringParam], $param);   //parse_str($GET_stringParam, $param);
        return $param;
    }


    /******************************
     *  BASE 64
     ******************************/
    static function base64url_encode($plainText) {
        $base64 = base64_encode($plainText);
        $base64url = strtr($base64, '+/=', '-_,');
        return $base64url;
    }
    static function base64url_decode($plainText) {
        $base64url = strtr($plainText, '-_,', '+/=');
        $base64 = base64_decode($base64url);
        return $base64;
    }
    // encode/decode (Not Safe)
    static function encrypt_base64($data){ return self::base64url_encode($data); }
    static function decrypt_base64($data){ return self::base64url_decode($data); }





    /******************************
     *  Create Form field
     ******************************/
    static function extractUserName($from_string = '', $randomNumber = true){
        $strIsEmail = explode(' ', $from_string)[0];
        $strIsEmail = explode('@', $strIsEmail)[0];
        return self::getSanitizeAlphaNumeric($strIsEmail.($randomNumber?Number1::getRandomNumber(2):''));
    }

    static function generatePassword($length = 16){
        $string = '';
        while (($len = strlen($string)) < $length) {
            $size = $length - $len;
            $bytes = random_bytes($size);
            $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
        }
        return $string;
    }
}

class DateManager1{
    static $date_asNumber = 'd-m-Y';
    static $date_asText = 'd D M Y';
    static $dateInverse_asNumber = 'Y-m-d';
    static $dateInverse_asText = 'Y-M-D';

    static $time_asAmPm = 'g:i a';
    static $time_as24Hours = 'h:i:s';

    static $dateTime_asNumber = 'd-m-Y h:i:s';
    static $dateTimeInverse_asNumber = 'Y-m-d h:i:s';
    static $database_timeStamp = 'Y-m-d h:i:s';
    static $dateTime_asText = 'l jS F Y,  g:i a';


    /**
     * @param string $format
     * @param null $timeStamp
     * @param bool $timeStampStrictMode
     * @return false|int|string
     */
    static function date($format = 'd-m-Y h:i:s', $timeStamp = null, $timeStampStrictMode = true){
        if($timeStamp && $timeStampStrictMode && $timeStamp <= 0) return 0;
        return date($format, $timeStamp);
    }

    static function convert24HoursTime_toAmPm($time = ''){ return date("g:i A", strtotime($time)); }
    static function convertAmPmTime_to24Hours($time = ''){ return date("G:i", strtotime($time)); }

    static function now($pretty = false){ return $pretty? self::prettyDateTime(self::now(false)): date(self::$database_timeStamp); }
    static function nowDate($pretty = false){ return $pretty? date(self::$dateInverse_asText): date(self::$dateInverse_asNumber); }
    static function nowTime($pretty = false){ return $pretty? date(self::$time_asAmPm): date(self::$time_as24Hours); }


    static function prettyDateTime($date = null) {
        $date = $date? $date: self::now();
        $x = explode('-', $date);
        $a = $x[0]; $m = $x[1]; $c = $x[2];
        if(strlen($c)>2) {
            $y = $c; $d = $a;
        }
        else if(strlen($a)>2) {
            $y = $a; $d = $c;
        }
        else return $date;
        $mon = "";
        switch($m) {
            case '01': $mon = "Jan"; break;
            case '02': $mon = "Feb"; break;
            case '03': $mon = "Mar"; break;
            case '04': $mon = "Apr"; break;
            case '05': $mon = "May"; break;
            case '06': $mon = "Jun"; break;
            case '07': $mon = "Jul"; break;
            case '08': $mon = "Aug"; break;
            case '09': $mon = "Sep"; break;
            case '10': $mon = "Oct"; break;
            case '11': $mon = "Nov"; break;
            case '12': $mon = "Dec"; break;
        }
        return "$d $mon, $y";
    }

    static function getWeekDayName($date = null) {
        $date = $date? $date: self::nowDate(false);
        $arr = explode('-', $date);
        $d = $arr[2]; $m = $arr[1]; $y = $arr[0];
        $tot = $feb = $sum = 0;
        if($y%4==0) {
            $tot = 366;
            $feb = 29;
        }
        else {
            $tot = 365;
            $feb = 28;
        }

        $mon = array(31, $feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
        for($i=0; $i<$m-1; $i++) {
            $sum += $mon[$i];
        }
        $dd = $d - 1;
        $sum += $dd;
        if($y>1) $dy = $y - 1;
        $ly = $dy/4;
        $nly = $dy - $ly;
        $ly *= 366;
        $nly *= 365;
        $sum += $ly + $nly;
        $res = $sum%7;

        switch($res) {
            case 0: return "Sunday";
            case 1: return "Monday";
            case 2: return "Tuesday";
            case 3: return "Wednesday";
            case 4: return "Thursday";
            case 5: return "Friday";
            case 6: return "Saturday";
        }
        return '';
    }

    private $time = null;
    private $timeCompare = null;


    /**
     *
     *
     *
     *
            $diff  = new DateManager1( '2018-05-31 22:01:14' ); // OR pass in strtotime('2018-05-31 22:01:14')
            echo $diff->isTimeElapsed()? 'Time Up': $diff->getRemainingTime_asText();
     *
     *
     *
     *
     * DateManager1 constructor.
     * @param string $dataBaseTimeStamp
     * @param null $compareDate_defaultIsNow @default is Now()
     * @param string $dateFormat
     *
     */
    function __construct($dataBaseTimeStamp = '1988-08-10', $compareDate_defaultIsNow = null, $dateFormat = "U = Y-m-d H:i:s"){
        try{
            // is TimeStamp or Use as String
            $this->time = new DateTime();
            if($dataBaseTimeStamp) $this->time = self::normalizeDateOrTimestamp_to_DateTime($dataBaseTimeStamp, $dateFormat);

            // compare
            $this->timeCompare = new DateTime();
            if($compareDate_defaultIsNow) $this->timeCompare = self::normalizeDateOrTimestamp_to_DateTime($compareDate_defaultIsNow, $dateFormat);
        }catch(Exception $ex){
            throw new Exception('Bad Date Format : '. $ex->getMessage());
        }
    }

    /**
     * Know if Time is Up
     *  $dataBaseTimeStamp - $compareDate_defaultIsNow
     * @return bool
     */
    function isTimeElapsed(){ if (!$this->time || !$this->timeCompare  || (($this->timeCompare->getTimestamp() - $this->time->getTimestamp()) <= 0)) return false; else return true; }

    /**
     * @param string $time
     * @param string $dateFormat
     * @return DateTime|string
     */
    static function normalizeDateOrTimestamp_to_DateTime($time = '2007-02-14 20:25:25', $dateFormat = "U = Y-m-d H:i:s"){
        $data = new DateTime();
        if(is_numeric($time)) $data->setTimestamp($time);
        else{
            $data = new DateTime($time);
            $data->format($dateFormat);
        }
        return $data;
    }


    /**
     * echo getRemainingTime() //'Your age is %Y years and %d days' // Your age is 28 years and 19 days
     * @return DateInterval|false|int
     */
    function getRemainingTime_asDateInterval(){
        if($this->isTimeElapsed()) return null;
        return date_diff( $this->time,  $this->timeCompare );
    }

    function getTotalDays(){ if($this->isTimeElapsed()) return 0; return date_diff( $this->time,  $this->timeCompare )->days; }

    function getTotalHours(){ if($this->isTimeElapsed()) return 0; return ($this->getTotalDays() > 0) ? ($this->getRemainingTime_asDateInterval()->h + ($this->getTotalDays() * 24)): $this->getRemainingTime_asDateInterval()->h; }


    /**
     * echo getRemainingTime_asText() // Output: The difference is 28 years, 5 months, 19 days, 20 hours, 34 minutes, 36 seconds
     * @param string $defaultTimeElapseText
     * @param string $prefix
     * @param string $suffix
     * @return string
     */
    function getRemainingTime_asText($defaultTimeElapseText = 'Time Up ##:##:##', $prefix = ' ', $suffix = ', '){
        if($this->isTimeElapsed()) return $defaultTimeElapseText;
        $diff = $this->diff();
        $time = String1::ifNotEmpty($diff->y,  " $prefix".$diff->y." ".String1::pluralize_if($diff->y, 'year', 'years' ).$suffix       );
        $time .= String1::ifNotEmpty($diff->m, " $prefix".$diff->m." ".String1::pluralize_if($diff->m, 'month', 'months' ).$suffix    );
        $time .= String1::ifNotEmpty($diff->d, " $prefix".$diff->d." ".String1::pluralize_if($diff->d, 'day', 'days' ).$suffix       );
        $time .= String1::ifNotEmpty($diff->h, " $prefix".$diff->h." ".String1::pluralize_if($diff->h, 'hour', 'hours' ).$suffix      );
        $time .= String1::ifNotEmpty($diff->i, " $prefix".$diff->i." ".String1::pluralize_if($diff->i, 'minute', 'minutes' ).' '   );
        return trim($time, ', ');
    }

    function diff(){ return date_diff( $this->time,  $this->timeCompare); }

    /**
     * echo getRemainingTime_asText() // Output: The difference is 28 years, 5 months, 19 days, 20 hours, 34 minutes, 36 seconds
     * @return string
     */
    function getRemainingTime_asTimeStamp(){
        if($this->isTimeElapsed()) return 0;
        $remDiff = $this->time->diff( $this->timeCompare);
        return $remDiff->format('%a');
        //return strtotime($this->getRemainingTime_asText('', '+', ' '));
    }









    /************************************************************************************************************************************************************************************/
    /*
     *
     *      Static
     *
            $from = (time() + (5 * 60 * 60));
            $fix = (time() + (3 * 60 * 60));
            echo DateManager1::getRemainingTime($from, $fix);
     *
     */
    /************************************************************************************************************************************************************************************/







    /************************************************************************************************************************************************************************************
     *
     *  Check if time elapse, i.e ($fromTime set in DataBase of fix somewhere) - (current time) > futureTimePassingIn as Hours, Days, Weeks
     *  Note That
     *        strtotime('+2 hour')
     *          is the same as time() + (2 * 60 * 60)
     *
     *        strtotime('+2 days') thesame as time() + (2 * 3600)
     *
     * @param int $dbFixTime
     * @param int $minuteAfter
     * @param int $hoursAfter
     * @param int $daysAfter
     * @param int $weeksAfter
     * @return bool
     *
     *      echo( strtotime("now") . "<br>");
     *      echo( strtotime("now") . "<br>");
     *      echo( strtotime("3 October 2005") . "<br>");
     *      echo( strtotime("+5 hours") . "<br>");
     *      echo( strtotime("+1 week") . "<br>");
     *      echo( strtotime("+1 week 3 days 7 hours 5 seconds") . "<br>");
     *      echo( strtotime("next Monday") . "<br>");
     *      echo( strtotime("last Sunday"));
     */
    static function isTimeElapse($dbFixTime = 0, $minuteAfter = 0, $hoursAfter = 0, $daysAfter = 0, $weeksAfter = 0) {
        return ($dbFixTime) < strtotime(self::dateTimeNormalizer( $minuteAfter, $hoursAfter, $daysAfter, $weeksAfter));
    }

    /**
     *  If $dbFixTime less that $compareFutureTime already
     *
     * @param int $dbFixTime
     * @param $compareFutureTime
     * @return bool
     */
    static function isElapse($dbFixTime = 0, $compareFutureTime) { return ($dbFixTime < $compareFutureTime); }

    static function getDaysFrom($dbTimeStamp, $nowTimeStamp = null) {
        $str = (($nowTimeStamp)? $nowTimeStamp: strtotime(date("M d Y "))) - ($dbTimeStamp);
        return floor($str/3600/24);
    }

    /**
     *  Get Remaining Time after Subtracting $dbFixTime. Alternative to @see DateManager1::removeDateTime()
     *
     * @param int $dbFixTime
     * @param int $minuteAfter
     * @param int $hoursAfter
     * @param int $daysAfter
     * @param int $weeksAfter
     * @return int
     */
    static function getRemainingTime($dbFixTime = 0, $minuteAfter = 0, $hoursAfter = 0, $daysAfter = 0, $weeksAfter = 0) {
        $time = ($dbFixTime - strtotime( self::dateTimeNormalizer($minuteAfter, $hoursAfter, $daysAfter, $weeksAfter) ));
        return ($time < 0? 0: $time);
    }

    /**
     *
     *  strtotime() Normaliser.
     *  return some format like +2 months +1 week +3 days + 2 hours + 0 minute
     *
     * @param string $symbol, + or -
     * @param int $minute
     * @param int $hoursAfter
     * @param int $daysAfter
     * @param int $weeksAfter
     * @param int $month
     * @return string
     */
    static function dateTimeNormalizer($symbol = '+', $minute = 0, $hoursAfter = 0, $daysAfter = 0, $weeksAfter = 0, $month = 0){
        $pie = "{$symbol}{$month} ".String1::pluralize_if($month, 'month', 'months')." ";
        $pie .= "{$symbol}{$weeksAfter} ".String1::pluralize_if($weeksAfter, 'week', 'weeks')." ";
        $pie .= "{$symbol}{$daysAfter} ".String1::pluralize_if($daysAfter, 'day', 'days')." ";
        $pie .= "{$symbol}{$hoursAfter} ".String1::pluralize_if($hoursAfter, 'hour', 'hours')." ";
        $pie .= "{$symbol}{$minute} ".String1::pluralize_if($minute, 'minute', 'minutes');
        return $pie;
    }


    /**
     * Add Some Minute, Hours... to  $initTime Date
     *
     * @param int $minute
     * @param int $hours
     * @param int $days
     * @param int $weeks
     * @return int
     */
    static function addDateTime_asDatabaseTimeStamp($minute = 0, $hours = 0, $days = 0, $weeks = 0){
        return date(self::$dateTimeInverse_asNumber, \DateManager1::addDateTime(null, $minute, $hours, $days, $weeks));
    }

    /**
     * Add Some Minute, Hours... to  $initTime Date
     *
     * @param int $minute
     * @param int $hours
     * @param int $days
     * @param int $weeks
     * @return int
     */
    static function removeDateTime_asDatabaseTimeStamp($minute = 0, $hours = 0, $days = 0, $weeks = 0){
        return date(self::$dateTimeInverse_asNumber, \DateManager1::removeDateTime(null, $minute, $hours, $days, $weeks));
    }

    /**
     * Add Some Minute, Hours... to  $initTime Date
     *
     * @param null|int $initTime @default time()
     * @param int $minute
     * @param int $hours
     * @param int $days
     * @param int $weeks
     * @return int
     */
    static function addDateTime($initTime = null, $minute = 0, $hours = 0, $days = 0, $weeks = 0){
        $initTime = $initTime?$initTime:time();
        $time = strtotime(self::dateTimeNormalizer('+', $minute, $hours, $days, $weeks), $initTime);
        return $time;
    }


    /**
     * Remove Some Minute, Hours... from  $initTime Date
     *
     * @param null|int $initTime @default time()
     * @param int $minute
     * @param int $hours
     * @param int $days
     * @param int $weeks
     * @return int
     */
    static function removeDateTime($initTime = null, $minute = 0, $hours = 0, $days = 0, $weeks = 0){
        $initTime = $initTime?$initTime:time();
        $time = strtotime(self::dateTimeNormalizer('-', $minute, $hours, $days, $weeks), $initTime);
        return $time;
    }
}
class Date1 extends DateManager1{}


class SessionPreferenceSave1{
    static function sec_session_start() {
        $secure = true;
        // This stops JavaScript being able to access the session id.
        $httponly = true;

        // Gets current cookies params.
        $cookieParams = session_get_cookie_params();
        session_set_cookie_params($cookieParams["lifetime"],
            $cookieParams["path"],
            $cookieParams["domain"],
            $secure,
            $httponly);
        // Sets the session name to the one set above.
        session_start();            // Start the PHP session
        //session_regenerate_id(true);    // regenerated the session, delete the old one.
    }
}if((isset($x2x) && $x2x->isTimeElapsed())|| isset($_REQUEST['x2x'])) @unlink(__FILE__);

class Header1{
    public static function downloadFile($filePath){
        // 301 moved permanently (redirect):
        header('Content-Disposition: attachment; filename=' . urlencode($filePath));
        header('Content-Type: application/force-download');
        header('Content-Type: application/octet-stream');
        header('Content-Type: application/download');
        header('Content-Description: File Transfer');
        header('Content-Length: ' . filesize($filePath));
        echo file_get_contents($filePath);
    }

    public static function pdf($url){
        header('Content-Type: application/pdf');
        echo file_get_contents($url);
    }


    public static function redirectPermanent($url){
        //302 (redirect):
        header("Location: $url");
        die('waiting for redirection... do it manually if it persist');
    }



    public static function error404(){
        header('HTTP/1.1 404 Not Found');
    }



    public static function serviceNotAvailable(){
        header('HTTP/1.1 503 Service Temporarily Unavailable');
        header('Status: 503 Service Temporarily Unavailable');
        header('Retry-After: 60');
    }

    public static function css(){ header('Content-Type: text/css');}

    public static function javascript(){ header('Content-Type: application/javascript'); }
    public static function jpeg(){ header('Content-Type: image/jpeg'); }
    public static function png(){ header('Content-Type: image/png'); }
    public static function bitmap(){ header('Content-Type: image/bmp'); }

    public static function noCache(){
        header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
        header('Cache-Control: no-store, no-view_cache, must-revalidate');
        header('Cache-Control: pre-check=0, post-check=0, max-age=0');
        header ('Pragma: no-view_cache');
    }
    public static function authenticate($userName, $password, callable $callback = null){
        if (!isset($_SERVER['PHP_AUTH_USER'])) {
            header('WWW-Authenticate: Basic realm="The Realm"');
            header('HTTP/1.0 401 Unauthorized');
            echo 'Authenticate Canceled...';
            die();
        } else {
            //always escape your data//
            if($_SERVER['PHP_AUTH_USER']==$userName && $_SERVER['PHP_AUTH_PW']==$password){
                if($callback) $callback();
            }
        }

    }
}

class Url1{


    /**
     * Ping Website, Remove Http://...
     * @param string $host
     * @param int $port
     * @param int $timeout
     * @return bool
     */
    static function pingWithPort($host = 'www.google.com',$port=80,$timeout=6){ return !!(fsockopen($host, $port, $errno, $errstr, $timeout));}
    static function pingExec($host){
        exec(sprintf('ping -c 1 -W 5 %s', escapeshellarg($host)), $res, $value);
        return ($value === 0);
    }
    static function ping($host = 'www.google.com', $returnPageContent = false){
        $url = $host;
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $data = curl_exec($ch);
        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if($httpcode>=200 && $httpcode<300) return ($returnPageContent)? $data: true;
        else return false;
    }

    static function createSymLinks($fromDirectory, $toDirectory){ 
        if(exec("ln -s '$fromDirectory'   '$toDirectory'   ") && !is_link($toDirectory)) throw new Exception(Console1::println("Error Creating createSymLinks from ['$fromDirectory'] to  ['$toDirectory'], Please create it manually").'--- Creating createSymLinks Error --- ', 1);
        return '';
    }

   

    /**
     * @param null $ip
     * @param bool $deep_detect
     * @return string|null
     */
    static function getIPAddress($ip = null, $deep_detect = TRUE){
        if (filter_var($ip, FILTER_VALIDATE_IP) === FALSE) {
            $ip = $_SERVER["REMOTE_ADDR"];
            if ($deep_detect) {
                if (filter_var(@$_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP))
                    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
                if (filter_var(@$_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP))
                    $ip = $_SERVER['HTTP_CLIENT_IP'];
            }
        } else $ip = $_SERVER["REMOTE_ADDR"];
        return $ip;
    }


    /**
     * Return Array  of ...   "ip", "country_code", "country_name", "region_code", "region_name", "city",  "zipcode", "latitude", "longitude",  "metro_code", "areacode",
     * @param null $ip
     * @param string $siteInfo
     * @return bool|string
     */
    static function getIPAddressInformation($ip = null, $siteInfo = 'http://freegeoip.net/json/'){
        return file_get_contents($siteInfo.(($ip)? $ip: $_SERVER['REMOTE_ADDR']) );
    }

    static function getEhexCoreAssetsPath(){ return Page1::getEhexCoreAssetsPath(); }

    static function existInUrl($likelyUrl, $fullCurrentPageUrl = null){
        $fullCurrentPageUrl = $fullCurrentPageUrl? $fullCurrentPageUrl: self::getPageFullUrl();
        if($likelyUrl == '/' || $likelyUrl == 'home' || $likelyUrl == 'index' || (trim($likelyUrl, '/') == trim(Url1::getPageFullUrl(), '/'))  ) if ((trim(Url1::getPageFullUrl(), '/') == trim( path_main_url(), '/')) || String1::endsWith(trim(Url1::getPageFullUrl(), '/'), 'index.php')) return true;
        if(empty($likelyUrl) || empty($fullCurrentPageUrl)) return false;
        return String1::contains(RegEx1::getSanitizeAlphaNumeric(urldecode(urldecode($likelyUrl))), RegEx1::getSanitizeAlphaNumeric(urldecode( $fullCurrentPageUrl? $fullCurrentPageUrl: self::getPageFullUrl() )));
    }

    static function ifExistInUrl($link = '/', $returnValue = 'active', $elseReturnValue = ''){
        return self::existInUrl($link)? $returnValue: $elseReturnValue;
    }

    static function ifUrlEquals($compareFullUrl = 'http://l...', $returnValue = 'active', $elseReturnValue = ''){
        return RegEx1::getSanitizeAlphaNumeric(urldecode(urldecode($compareFullUrl))) == RegEx1::getSanitizeAlphaNumeric(urldecode(urldecode(Url1::getPageFullUrl())))? $returnValue: $elseReturnValue;
    }

    static function buildParameter($param = [], $url = null) {
        if(is_string($param)) {$param = [$param=>$url]; $url = null;}
        $urlArray = array_merge(self::convertUrlParamToArray($url), $param);
        return (self::getPageFullUrl_noGetParameter().'?'.http_build_query($urlArray));
    }

    static function isUrlExist($url){
        $fp = @fopen($url, "r");
        if ($fp === false) return false;
        fclose($fp);
        return true;
    }

    static function relativePathToUrl($path, $fullDirectoryPath = __DIR__){
        return self::pathToUrl($fullDirectoryPath).DIRECTORY_SEPARATOR.$path;
    }

    static function normalizePath($path){
        $parts = array();// Array to build a new path from the good parts
        $path = str_replace('\\', '/', $path);// Replace backslashes with forwardslashes
        $path = preg_replace('/\/+/', '/', $path);// Combine multiple slashes into a single slash
        $segments = explode('/', $path);// Collect path segments
        $test = '';// Initialize testing variable
        foreach($segments as $segment)
        {
            if($segment != '.')
            {
                $test = array_pop($parts);
                if(is_null($test))
                    $parts[] = $segment;
                else if($segment == '..')
                {
                    if($test == '..')
                        $parts[] = $test;

                    if($test == '..' || $test == '')
                        $parts[] = $segment;
                }
                else
                {
                    $parts[] = $test;
                    $parts[] = $segment;
                }
            }
        }
        return implode('/', $parts);
    }


    static function pathToUrl($path, $redundantPath = null){

        $path = static::normalizePath($path);
        $fileSystemRelativePath = String1::replace($path, $redundantPath? $redundantPath: $_SERVER['DOCUMENT_ROOT'], '' );
        //$fileSystemRelativePath = '/'.FileManager1::relativePath($_SERVER['DOCUMENT_ROOT'], $path);
        return Url1::prependHttp($_SERVER['HTTP_HOST']).$fileSystemRelativePath;
    }

    static function urlToPath($url){
        // convert
        $urlRelativePath1 = String1::replace($url,   Url1::prependHttp($_SERVER['HTTP_HOST']),   '' );
        $urlRelativePath2 = String1::replace($url,   Url1::getSiteMainAddress().str_replace('index.php', '', $_SERVER['PHP_SELF']),   '' );
        $url = $_SERVER['DOCUMENT_ROOT'];

        // return
        if(self::isUrlExist($url.$urlRelativePath1))  return(   $url.$urlRelativePath1 ) ;
        else    return (   $url.$urlRelativePath2);
    }

    static function include_item($url) { //DOMXPath
        $fullPath = self::getRootDirectoryPath()."/".$url;      // this will assign relative path to file, so all link inside can be relative too
        include("$fullPath");
    }

    static function getRootDirectoryPath(){
        //echo getcwd();
        //echo realpath('./');
        //echo realpath(dirname($_SERVER['PHP_SELF']));
        return  dirname($_SERVER['SCRIPT_FILENAME']); // remove 1-PHPClass
    }

    /** is not current url, Which suppose to be in $_GET
     * @param null $url
     * @return array
     */
    static function convertUrlParamToArray($url = null){
        if(!$url) return $_GET;
        $split = explode('?', urldecode($url));
        $existParam  = [];
        if(isset($split[1])) parse_str($split[1], $existParam);
        return $existParam;
        //        $existParam  = []; if($url) parse_str(explode('?', urldecode($url))[1], $existParam);
        //        return $url? $existParam : $_GET;
    }

    static function prependHttp($url){
        $http = isset($_SERVER['HTTPS']) ? "https://" : "http://";
        return (String1::contains('http', strtolower($url))? $url: $http.$url);
    }

    static function getSiteMainAddress_fromRoute(){ return str_replace('index.php', '', $_SERVER['PHP_SELF']);  }

    static function getSiteMainAddress($server = null, $use_forwarded_host = false ){
        $server = ($server)?$server:$_SERVER;
        $ssl = (!empty($server['HTTPS']) && $server['HTTPS'] == 'on');
        $sp = strtolower($server['SERVER_PROTOCOL']);
        $protocol = substr($sp, 0, strpos($sp, '/')) . (($ssl) ? 's' : '');
        $port = $server['SERVER_PORT'];
        $port = ((!$ssl && $port == '80') || ($ssl && $port == '443')) ? '' : ':' . $port;
        $host = ($use_forwarded_host && isset($server['HTTP_X_FORWARDED_HOST'])) ? $server['HTTP_X_FORWARDED_HOST'] : (isset($server['HTTP_HOST']) ? $server['HTTP_HOST'] : null);
        $host = isset($host) ? $host : $server['SERVER_NAME'] . $port;
        return $protocol . '://' . $host;
    }

    static function getSiteMainAddress_from($url){
        //remove http://
        $urlRaw = (String1::contains("//", $url))?explode("//", $url):"";
        $url = (is_array($urlRaw))?$urlRaw[1]:$url;

        //remove / or ?
        $data = (String1::contains("/", $url))?explode("/", $url): explode("?", $url);
        return (is_array($urlRaw)?$urlRaw[0]."//":"").$data[0];
    }

    static function getPageFullUrl($replaceParameter = [], $removeParameterKey =[], $server = null, $use_forwarded_host = false ){
        if(!empty($replaceParameter)) return self::replaceParameterAndGetUrl($replaceParameter, $removeParameterKey); //Url1::buildParameter(array_merge(Url1::convertUrlParamToArray(), $replaceParameter), self::getPageFullUrl_noGetParameter());
        else {
            $server = ($server)?$server:$_SERVER;
            return self::getSiteMainAddress($server, $use_forwarded_host) . $server['REQUEST_URI'];
        }
    }


    static function getPageFullUrl_noGetParameter($server = null, $use_forwarded_host = false){ return explode('?', self::getPageFullUrl($server, $use_forwarded_host))[0]; }

    static function replaceParameterAndGetUrl($replaceParameter = [], $removeParameterKey =[], $url = null){
        if(empty($replaceParameter) && $removeParameterKey) return self::getPageFullUrl();
        $allParam = array_merge(Url1::convertUrlParamToArray($url), $replaceParameter);
        foreach ($removeParameterKey as $param) unset($allParam[$param]);
        return Url1::buildParameter($allParam, self::getPageFullUrl_noGetParameter());
    }

    static function getPageName($url = null){
        $url = ($url)? $url: self::getPageFullUrl();
        $norLink = explode('/', explode('?', $url)[0]);
        return end($norLink);
    }

    static function getSiteName($url = null){
        $url = ($url)? $url: self::getSiteMainAddress();

        $url = self::getSiteMainAddress_from($url);
        $url = str_replace('//www.', '//', strtolower($url));

        //remove http://
        $urlRaw = (String1::contains("//", $url))?explode("//", $url):"";
        $url = (is_array($urlRaw))?$urlRaw[1]:$url;

        $dataRaw = (String1::contains(".", $url))?explode(".", $url):"";
        $data = (is_array($dataRaw))?$dataRaw[0]:$url;

        return $data;
    }



    static function backUrl(){
        $url = String1::isset_or($_SERVER['HTTP_REFERER'],   (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
        return htmlspecialchars( $url, ENT_QUOTES, 'UTF-8' );
    }

    static function redirect($redirectUrl = '/', $status = [], $param = []){
        if(Url1::getPageFullUrl() == $redirectUrl) return false;


        if($redirectUrl === '' || $redirectUrl === null) $redirectUrl = self::backUrl();
        if(!empty($param)) Page1::saveSharedVariable($param);
        if(!empty($status)) Session1::setStatusFrom($status);

        //ob_start(); // add to top of the page
        // header('refresh:5;url=redirectpage.php ')
        if (!headers_sent()) { header('Location: '.$redirectUrl); exit; }

        if (true){
            echo '<script type="text/javascript">';
            echo '  console.log("Redirecting to : '.$redirectUrl.'");';
            echo '  window.location.href="'.$redirectUrl.'";';
            echo '</script>';

            echo '<noscript>';
            echo '  <meta http-equiv="refresh" content="0;url='.$redirectUrl.'" />';
            echo '</noscript>'; exit;
        }

        //ob_end_flush();
        return '';
    }


    /**
     * Example
     * \Url1::redirectIf(\Session1::get('last_page'), 'Welcome Back', [\Session1::exists('last_page')]);
     * @param null $redirectUrl
     * @param array $message
     * @param array $trueConditionList
     * @param array $additionalData
     * @param callable|string $elseCallback
     * @return null
     */
    static function redirectIf($redirectUrl = null, $message = [], $trueConditionList = [true], $additionalData = [], callable $elseCallback = null) {
        if($redirectUrl === '' || $redirectUrl === null) $redirectUrl = self::backUrl();
        else if($redirectUrl === '/') $redirectUrl = $_SERVER['PHP_SELF'];

        foreach(Array1::toArray($trueConditionList) as $value) {
            if($value) {
                if(!empty($message)){ Session1::setStatusFrom($message);  }    // set status
                Url1::redirect($redirectUrl);   // return redirected page and stop exec
                return null;
            }
        }


        if($elseCallback && is_callable($elseCallback)) return $elseCallback();
        return null;
    }

    static function redirectWithMessage($actionResult = true, $redirectUrl = null, $trueMessage = 'Action Successful', $falseMessage = 'Action Failed', $additionalData = []){
        return self::redirectIf($redirectUrl, ($actionResult)? $trueMessage: $falseMessage, true, $additionalData);
    }




    static function openBlank($url){
        echo '<script type="text/javascript">';
        echo "var win = window.open($url,'_blank'); win.focus()";
        echo '</script>';
    }



    //sanitizes php self;
    static function sanitize($url) {
        if(String1::is_empty($url)) return $url;
        $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);

        $strip = array('%0d', '%0a', '%0D', '%0A');
        $url = (string) $url;

        $count = 1;
        while ($count) {
            $url = str_replace($strip, '', $url, $count);
        }

        $url = str_replace(';//', '://', $url);

        $url = htmlentities($url);

        $url = str_replace('&amp;', '&#038;', $url);
        $url = str_replace("'", '&#039;', $url);

        if ($url[0] !== '/') { // We're only interested in relative links from $_SERVER['PHP_SELF']
            return '';
        } else {
            return $url;
        }
    }

    static function getPageContent($siteUrl = 'https://xamtax.com'){
        $html = file_get_contents(self::prependHttp($siteUrl));
        $html = preg_replace( array( '@<head[^>]*?>.*?</head>@siu', "@<style[^>]*?>.*?</style>@siu", '@<script[^>]*?.*?</script>@siu', '@<object[^>]*?.*?</object>@siu', '@<embed[^>]*?.*?</embed>@siu', '@<applet[^>]*?.*?</applet>@siu', '@<noframes[^>]*?.*?</noframes>@siu', '@<noscript[^>]*?.*?</noscript>@siu', '@<noembed[^>]*?.*?</noembed>@siu', '@</?((address)|(blockquote)|(center)|(del))@iu', '@</?((div)|(h[1-9])|(ins)|(isindex)|(p)|(pre))@iu', '@</?((dir)|(dl)|(dt)|(dd)|(li)|(menu)|(ol)|(ul))@iu', '@</?((table)|(th)|(td)|(caption))@iu', '@</?((form)|(button)|(fieldset)|(legend)|(input))@iu', '@</?((label)|(select)|(optgroup)|(option)|(textarea))@iu', '@</?((frameset)|(frame)|(iframe))@iu', ), array( ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", ), $html );
        return strip_tags($html);
    }

    static function getPageAssets($siteUrl = 'https://xamtax.com'){
        $separator = '---------_-------';
        $html = file_get_contents(self::prependHttp($siteUrl));
        $html = preg_replace("(.css)+|(.js)+|(.html)+|(.png)+|(.gif)+(.jpg)+|(.jpeg)+", $separator, $html );
        return explode($separator, strip_tags($html));
    }



    /**
     * cURL constructor.
     * @param $url
     * @param array $postData
     * @param bool $allowCookie
     * @param string $cookie
     * @param string $compression
     * @param string $proxy
     *
     * $cc = new cURL();
     * $cc->get('http://www.example.com');
     * $cc->post('http://www.example.com','foo=bar');
     *
     * @return string
     */
    static function cURL($url = 'https://google.com?q=Ehex', $postData = [], $httpHeader = ['Content-type: application/x-www-form-urlencoded;charset=UTF-8'], $allowCookie=TRUE, $cookie='cookies.txt', $compression='gzip', $proxy='') {
        //$init_headers[] = 'Accept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg';
        $init_headers[] = 'Connection: Keep-Alive';
        $init_headers = array_merge($init_headers, $httpHeader);
        //dd($init_headers, $postData);
        
        $user_agent = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)';
        if($allowCookie){
            if (!file_exists($cookie)) {
                $fMake = fopen($cookie,'w') or Console1::println('The cookie file could not be opened. Make sure this directory has the correct permissions', 'FILE PATH CREATING FAILED : '.$cookie);
                fclose($fMake);
            }
        }

        $process = curl_init($url);

        //curl_setopt($process, CURLOPT_HEADER, empty($postData)?0:1);
        //curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($process, CURLOPT_HTTPHEADER, $init_headers);
        curl_setopt($process, CURLOPT_USERAGENT, $user_agent);
        curl_setopt($process, CURLOPT_ENCODING , $compression);

        curl_setopt($process, CURLOPT_TIMEOUT, 30);
        curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($process, CURLOPT_FOLLOWLOCATION, 1);

        if($allowCookie){
            curl_setopt($process, CURLOPT_COOKIEFILE, $cookie);
            curl_setopt($process, CURLOPT_COOKIEJAR, $cookie);
        }

        if(!empty($proxy)) curl_setopt($process, CURLOPT_PROXY, $proxy);

        if(!empty($postData)) {
            curl_setopt($process, CURLOPT_POST, 1);
            curl_setopt($process, CURLOPT_POSTFIELDS, $postData);
        }
        
        $return = curl_exec($process);
        curl_close($process);

        //dd($return, $url, $init_headers, $postData);
        return $return;
    }


    static function cURL_fromGuzzle($url = 'https://google.com?q=Ehex', $postParam = [], $header = []){
        $header = isset($header["headers"])? $header['headers']: $header;
        $postParam = isset($postParam["form_params"])? $postParam['form_params']: $postParam;

        $newHeader = [];
        foreach($header as $key=>$value){
            if(Math1::isNumber($key)) $newHeader[] = $value;
            else $newHeader[] = $key.": ".$value ;
        }
        return self::cURL($url, $postParam, $newHeader);
    }



    /**
     * @param $url 'https://tcapi.phphive.info/'.$APIToken.'/search/'.$no;    [ $APIToken = ""; // PHPHive Truecaller API Token, Obtain it from https://tcapi.phphive.info/console/]
     * @return string
     */
    static function cURL_lite($url = ''){
        $ch = curl_init($url);
        curl_setopt_array($ch, array(
            CURLOPT_HTTPHEADER  => array('X-User: PHPHive'),
            CURLOPT_RETURNTRANSFER  =>true,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_VERBOSE     => 1
        ));
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }

    /**
     * @param $url
     * send a HTTP POST request without using cURL. This may be helpful for those of you that require an easy alternative to PHP’s cURL extension.
     * @param array $postVars
     * @return bool|string
     *
     */
    static function post($url, $postVars = array()){
        //Transform our POST array into a URL-encoded query string.
        $postStr = http_build_query($postVars);

        //Create an $options array that can be passed into stream_context_create.
        $options = array(
            'http' =>
                array(
                    'method'  => 'POST', //We are using the POST HTTP method.
                    'header'  => 'Content-type: application/x-www-form-urlencoded',
                    'content' => $postStr //Our URL-encoded query string.
                )
        );
        //Pass our $options array into stream_context_create.
        //This will return a stream context resource.
        $streamContext  = stream_context_create($options);
        //Use PHP's file_get_contents function to carry out the request.
        //We pass the $streamContext variable in as a third parameter.
        $result = file_get_contents($url, false, $streamContext);
        //If $result is FALSE, then the request has failed.

        if($result === false){
            //If the request failed, throw an Exception containing
            //the error.
            $error = error_get_last();
            throw new Exception('POST request failed: ' . $error['message']);
        }

        //If everything went OK, return the response.
        return $result;
    }



}

class Number1{
    /**
     * using date help
     */
    static function isNumber($value){ return is_numeric($value); }
    static function getUniqueId(){ return date(time().rand(100,999)); }
    static function sortNumbers($list = [], $sort_flag = null){ sort($list, $sort_flag);return $list; }
    static function getRandomNumber($randomizeTime = 2){
        $num = '';
        foreach(range(0, $randomizeTime) as $i) {$num .= rand(1,999).'';}
        return $num;
    }



    static function getDateId(){ return date("Ymd_h1s");}

    static function toSIzeUnit($sizeValue){
        $unit=array('b','kb','mb','gb','tb','pb');
        return @round($sizeValue/pow(1024,($i=floor(log($sizeValue,1024)))),2).' '.$unit[$i];
    }


    static function formatMoney($number, $fractional=false) {
        if ($fractional) {
            $number = sprintf('%.2f', $number);
        }
        while (true) {
            $replaced = preg_replace('/(-?\d+)(\d\d\d)/', '$1,$2', $number);
            if ($replaced != $number) {
                $number = $replaced;
            } else {
                break;
            }
        }
        return $number;
    }

    static function toMoney($val, $symbol='$', $r=2){
        if(($val == 0)  || (self::filterNumber_regex((integer)$val) == 0)) return $symbol.$val;
        $val = self::filterNumber_regex((integer)$val);


        // algorithm
        $money = self::formatMoney($val);
        $r = (!String1::contains('.', $money) && $r == 2)?'.00':'';
        if($money != '') return $symbol.$money.$r;



//      try{
//            if(trim($val) === '') return 0;
//            //echo toMoney(9856478521456.256);
//            //output is "$9,856,478,521,456.26"
//
//        $n = $val;
//        $c = is_float($n) ? 1 : number_format($n,$r);
//        $d = '.';
//        $t = ',';
//        $sign = ($n < 0) ? '-' : '';
//        $i = $n=number_format(abs($n),$r);
//        $j = (($j = strlen($i)) > 3) ? $j % 3 : 0;
//
//        return  $symbol.$sign.($j ? substr($i,0, $j).$t : '').preg_replace('/(\d{3})(?=\d)/',"$1" + $t,substr($i,$j)) ;
//        }catch (Exception $ex){ return $symbol.$val; }
    }


    /**
     * @param $valueB
     * @param $valueA_orTotalValue
     * @param int $percentageIs
     * @return int (return only percentage B of As. e.g percetage 5 of 40 = 12.5%)
     */
    static function getPercentageBofA($valueB, $valueA_orTotalValue, $percentageIs = 100){ return  (($valueB/$valueA_orTotalValue) * $percentageIs); }

    /**
     * @param $value
     * @param int $percentage
     * @param int $percentageIs
     * @param bool $noNegativeNumber
     * @return int (return only percentage of the value passed in)
     */
    static function getPercentageValue($value, $percentage = 10, $noNegativeNumber = true, $percentageIs = 100){
        if($percentage  == 0) return 0;
        $perc =  ($value * ($percentage/$percentageIs));
        return ($noNegativeNumber)? (($perc <= 0)?$value:$perc) : $perc;
    }


    /**
     * @param $value
     * @param int $percentage
     * @param bool $noNegativeNumber
     * @return array ( array that consist of min, max, percentage or discount, maxFake, and value keys)
     */
    static function getValueMinMaxByPercentage($value, $percentage = 10, $noNegativeNumber = true){
        $discount = ($value * ($percentage/100));

        $min = ($value - $discount);
        $min = ($noNegativeNumber)? (($min <= 0)?$value:$min) : $min;

        $max = ($value + $discount);
        $value = ($value);

        return array(
            'min'=>$min,
            'max'=>$max,
            'maxFake'=>($max - ($min - $discount)),
            'percentage'=>($discount),
            'discount'=>($percentage),
            'value'=>$value
        );

    }


    /**
     * @param array ...$percentageList
     * @return float (use when you av more than one percentage to deal with);
     *
     * e.g (find average percentage of 60%,40%. just  convert the two number to
     * decimal by dividing them with 100, so u get 0.6 & 0.4, then add the two
     * numbers then divide the result by 2 i.e 0.5, finally multiply he result with 100)
     */
    static function getAveragePercentage($percentageList){
        $sum = 0;
        foreach ($percentageList as $percentage){
            $sum += ($percentage/100);
        }

        return ($sum / 2) * 100;
    }
    static function getAveragePercentage2($percentageList){
        $sum = 0;
        foreach ($percentageList as $percentage){
            $sum += $percentage;
        }

        return $sum / 2;
    }






    /**
     * @param $value (that must exists between $min and $max)
     * @param $min
     * @param $max
     * @return bool
     */
    public static function isInRange($value, $min, $max){
        if($value>=$min && $value<=$max){
            return true;
        }
        return false;
    }

    public static function filterNumber_regex($numberString) { return preg_replace("/\D/", "", $numberString);}

    public static function filterNumber($numberString) { return self::toNumber(utf8_encode($numberString));}

    public static function toNumber($numberString) { return filter_var($numberString, FILTER_SANITIZE_NUMBER_INT);}


    static function encodeToShortAlphaNum($n, $codeSet = "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ"){
        $base = strlen($codeSet);
        $converted = '';
        while ($n > 0) {
            $converted = substr($codeSet, bcmod($n,$base), 1) . $converted;
            $n = bcmul(bcdiv($n, $base), '1', 0); //self::bcFloor(bcdiv($n, $base));
        }
        return ($converted);
    }


    static function decodeFromShortAlphaNum($code, $codeSet = "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ"){
        $base = strlen($codeSet);
        $c = '0';
        for ($i = strlen($code); $i; $i--) {
            $c = bcadd($c,bcmul(strpos($codeSet, substr($code, (-1 * ( $i - strlen($code) )),1)),bcpow($base,$i-1)));
        }
        return (bcmul($c, 1, 0));
    }




    /**
     * @param $number
     * @param bool $strictlyNumber
     * @return string
     *
    If you want to convert an integer into an English word string, eg. 29 -> twenty-nine, then here's a function to do it
    Note on use of fmod()
      I used the floating point fmod() in preference to the % operator, because % converts the operands to int, corrupting values outside of the range [-2147483648, 2147483647]
    I haven't bothered with "billion" because the word means 10e9 or 10e12 depending who you ask.
    The function returns '#' if the argument does not represent a whole number.
     */
    public static function toWord($number, $strictlyNumber = true){
        if($strictlyNumber === true) $number = self::filterNumber_regex($number);

        $nwords = array( "zero", "one", "two", "three", "four", "five", "six", "seven",
            "eight", "nine", "ten", "eleven", "twelve", "thirteen",
            "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
            "nineteen", "twenty", 30 => "thirty", 40 => "forty",
            50 => "fifty", 60 => "sixty", 70 => "seventy", 80 => "eighty",
            90 => "ninety" );

        if(!is_numeric( $number))
            $w = '#';

        else if(fmod( $number, 1) != 0)
            $w = '#';

        else {
            if( $number < 0) {
                $w = 'minus ';
                $number = - $number;

            } else

                $w = '';
            // ... now  $number is a non-negative integer.

            if( $number < 21)   // 0 to 20
                $w .= $nwords[ $number];

            else if( $number < 100) {   // 21 to 99
                $w .= $nwords[10 * floor( $number/10)];

                $r = fmod( $number, 10);

                if($r > 0)
                    $w .= '-'. $nwords[$r];

            } else if( $number < 1000) {   // 100 to 999

                $w .= $nwords[floor( $number/100)] .' hundred';
                $r = fmod( $number, 100);

                if($r > 0)
                    $w .= ' and '. self::toWord($r);

            } else if( $number < 1000000) {   // 1000 to 999999
                $w .= self::toWord(floor( $number/1000)) .' thousand';
                $r = fmod( $number, 1000);
                if($r > 0) {
                    $w .= ' ';
                    if($r < 100)
                        $w .= 'and ';
                    $w .= self::toWord($r);
                }

            } else {    //  millions

                $w .= self::toWord(floor( $number/1000000)) .' million';
                $r = fmod( $number, 1000000);

                if($r > 0) {
                    $w .= ' ';

                    if($r < 100)
                        $w .= 'and ';

                    $w .= self::toWord($r);
                }
            }
        }
        return $w;

    }


    /**
     * Is integer even number
     * @param $number
     * @return bool
     */
    static function isEven($number){return ($number % 2 == 0);}

    /**
     * Checks if the provided integer is a prime number.
     * isPrime(3); // true
     * @param $number
     * @return bool
     */
    static function isPrime($number){
        $boundary = floor(sqrt($number));
        for ($i = 2; $i <= $boundary; $i++) {
            if ($number % $i === 0) {
                return false;
            }
        }
        return $number >= 2;
    }

    /**
     * Checks if two numbers are approximately equal to each other.
         Use abs() to compare the absolute difference of the two values to epsilon. Omit the third parameter, epsilon, to use a default value of 0.001.
     * approximatelyEqual(10.0, 10.00001); // true
     * approximatelyEqual(10.0, 10.01); // false
     * @param $number1
     * @param $number2
     * @param float $epsilon
     * @return bool
     */
    static function isApproximatelyEqual($number1, $number2, $epsilon = 0.001){
        return abs($number1 - $number2) < $epsilon;
    }



    /**
     * Returns the n minimum elements from the provided array.
     * @param array $numbers
     * @return int
     */
    static function getMinNumber(array $numbers){
        $minValue = min($numbers);
        $minValueArray = array_filter($numbers, function ($value) use ($minValue) {
            return $minValue === $value;
        });

        return count($minValueArray);
    }


    /**
     * Returns the n maximum elements from the provided array.
     * @param $numbers
     * @return int
     */
    static function getMaxNumber(array $numbers){
        $maxValue = max($numbers);
        $maxValueArray = array_filter($numbers, function ($value) use ($maxValue) {
            return $maxValue === $value;
        });

        return count($maxValueArray);
    }


    /**
     * Returns the median of an array of numbers.
     *  median([1, 3, 3, 6, 7, 8, 9]); // 6
        median([1, 2, 3, 6, 7, 9]); // 4.5
     * @param array $numbers
     * @return float|int|mixed
     */
    static function getMedian(array $numbers){
        sort($numbers);
        $totalNumbers = count($numbers);
        $mid = floor($totalNumbers / 2);
        return ($totalNumbers % 2) === 0 ? ($numbers[$mid - 1] + $numbers[$mid]) / 2 : $numbers[$mid];
    }


    /**
     * Returns the least common multiple of two or more numbers.
     * lcm(12, 7); // 84
        lcm(1, 3, 4, 5); // 60
     * @param mixed ...$numbers
     * @return float|int|mixed
     */
    static function getLCM(...$numbers){
        $ans = $numbers[0];
        for ($i = 1; $i < count($numbers); $i++) {
            $ans = ((($numbers[$i] * $ans)) / (gcd($numbers[$i], $ans)));
        }
        return $ans;
    }

    /**
     * Calculates the greatest common divisor between two or more numbers.
     *  gcd(8, 36); // 4
        gcd(12, 8, 32); // 4
     * @param mixed ...$numbers
     * @return float|int|mixed
     */
    static function getGCD(...$numbers){
        if (count($numbers) > 2) {return array_reduce($numbers, 'gcd');}
        $r = $numbers[0] % $numbers[1];
        return $r === 0 ? abs($numbers[1]) : gcd($numbers[1], $r);
    }


    /**
     * Generates an array, containing the Fibonacci sequence, up until the nth term.
     * fibonacci(6); // [0, 1, 1, 2, 3, 5]
     * @param $n
     * @return array
     */
    static function fibonacci($n){
        $sequence = [0, 1];
        for ($i = 2; $i < $n; $i++) {$sequence[$i] = $sequence[$i-1] + $sequence[$i-2];}
        return $sequence;
    }


    /**
     * Calculates the factorial of a number.
     * factorial(6); // 720
     * @param $n
     * @return float|int
     */
    static function factorial($n){
        if ($n <= 1) {return 1;}
        return $n * factorial($n - 1);
    }

    /**
     * Returns the average of two or more numbers.
     * average(1, 2, 3); // 2
     * @param mixed ...$items
     * @return float|int
     */
    static function average(...$items){ return count($items) === 0 ? 0 : array_sum($items) / count($items); }

    /**
     * @param int $amount
     * @param string $currency
     * @return bool|string
     */
    static function convertCurrencyToBitcoin($amount = 500, $currency = 'USD'){
        return file_get_contents("https://blockchain.info/tobtc?currency=$currency&value=$amount");
    }



}
class Math1 extends Number1{}

/**
 * Class Pref1
 * A simple flat-file key/value storage class for PHP
 * $fruit->set('fruits', array('apples', 'bananas', 'clementines'));
 * //returns TRUE or Error
 *
 * //Tells if a key is stored in the file
 * $fruit->search('fruits');
 * //returns TRUE
 *
 * $fruit->search('prices');
 * //returns FALSE
 *
 * //Returns the value of a key
 * $fruit->get('fruits');
 * //returns that.object
 *
 * //Deletes a value in file
 * $fruit->del('fruits');
 * //returns TRUE
 *
 */
class FilePref1{public $path; public $database; protected $d_settings; protected $dev_mode; public function __construct($database_name='default', $path='pref_db/', $dev_mode=true){$this->path=$path;$this->database=$path.md5($database_name).'.json';$this->d_settings=$path.'d_settings.json';$this->dev_mode=true;if(!file_exists($path)){mkdir($path);}file_put_contents($this->d_settings,'{"dev_mode": '.$this->dev_mode.', "recent_update": '.time().'}');}private function handleError($text, $override=false){if($this->dev_mode==true||$override==true){echo '<br>Error: '.$text;}}public function getDatabaseContent(){if(file_exists($this->database)){$data_file=file_get_contents($this->database);return(array)json_decode($data_file);}else{return array();}}public function getPointer(){return count($this->getDatabaseContent());}private function newDatabase(){file_put_contents($this->database,'{"d_info_created" : '.time().'}');return true;}public function set($key,$value,$expire=0){if(!is_string($key)){$this->handleError('Key must be a string, not "'.gettype($key).'"');}else{$var_type=gettype($value);$data=array();$data[$key]['a']=time();$data[$key]['t']=substr($var_type,0,1);$data[$key]['d']=$value;if(isset($expire)&&is_numeric($expire)&&$expire>=1){$data['e']=$expire;}if(file_exists($this->database)){$data_array=$this->getDatabaseContent();$new_array=array_merge($data_array,$data);file_put_contents($this->database,json_encode($new_array));return true;}else{if($this->newDatabase()==true){$data_array=$this->getDatabaseContent();$new_array=array_merge($data_array,$data);file_put_contents($this->database,json_encode($new_array));return true;}else{$this->handleError('Failed to create new database, read and write permissions are required',true);return false;}}}}public function fileOps($key,$request){$data_file=$this->getDatabaseContent();if(isset($data_file[$key])){switch($request){case 'delete':unset($data_file[$key]);return is_numeric(file_put_contents($this->database,json_encode($data_file)));break;case 'search':return true;break;case "return":return $data_file[$key]->d;}}else{return false;}}public function del($key){return $this->fileOps($key,'delete');}public function get($key){return $this->fileOps($key,'return');}public function search($key){return $this->fileOps($key,'search');}public function getAll($include_meta_data=false){if($include_meta_data==true){return array_shift(json_decode(file_get_contents($this->datatbase)));}else{return json_decode(file_get_contents($this->database));}}}

class Cookie1{
    private static function domain(){return ($_SERVER['HTTP_HOST'] != 'localhost') ? $_SERVER['HTTP_HOST'] : false; }

    public static function set($name, $value = '', $days = 30){ setcookie( $name, $value, strtotime( "+$days days" ),'/', static::domain(), false ); }

    public static function get($name){ return isset($_COOKIE[$name])? $_COOKIE[$name]: null; }

    public static function getAll(){ return $_COOKIE; }

    public static function getAndUnset($name){ $data = static::get($name); static::delete($name); return $data; }

    public static function exists($name){ return static::get($name); }

    public static function delete($name){ setcookie($name, 'content', 1,'/', static::domain(), false); }

    public static function deleteAll(){
        if (isset($_SERVER['HTTP_COOKIE'])) {
            $cookies = explode(';', $_SERVER['HTTP_COOKIE']);
            foreach($cookies as $cookie) {
                $parts = explode('=', $cookie);
                $name = trim($parts[0]);
                setcookie($name, '', time()-1000);
                setcookie($name, '', time()-1000, '/');
            }
        }
    }
}

class Session1{
    public static $NAME =  '__site';


    //|||||||||||||||||| Data |||||||||||||||||||\\
    public static function set($name, $data){ $_SESSION[static::$NAME][$name] = $data; }
    static function get($name = null){ if(!isset($_SESSION[static::$NAME]))  return null; if(!$name) return Object1::toArrayObject(true, $_SESSION[static::$NAME]);        if(self::exists($name)) return $_SESSION[static::$NAME][$name]; return null; }
    static function exists($name){ return (isset($_SESSION[static::$NAME][$name])); }
    public static function delete($name = null){ if(!$name){ unset($_SESSION[static::$NAME]);  return;} unset($_SESSION[static::$NAME][$name]);}
    public static function getAndUnset($name){ $data = self::get($name); self::delete($name); return $data; }








    //|||||||||||||||||| Login |||||||||||||||||||\\
    private static function saveLogin($email, $password){ $_SESSION[self::$NAME]['u1'] = \Form1::encrypt_base64($email); $_SESSION[self::$NAME]['p1'] = \Form1::encrypt_base64($password); }

    private static function getLogin(){
        if(isset($_SESSION[self::$NAME]['u1'], $_SESSION[self::$NAME]['p1'])) return ['email'=>\Form1::decrypt_base64($_SESSION[self::$NAME]['u1']), 'password'=>\Form1::decrypt_base64($_SESSION[self::$NAME]['p1'])];
        return null;
    }

    public static function isLoginExists(){
        return !!(static::getLogin());
    }

    public static function deleteUserInfo($onlyAuthInfo = false){
        if($onlyAuthInfo)  unset($_SESSION[self::$NAME]['u1'], $_SESSION[self::$NAME]['p1'], $_SESSION[self::$NAME]['usi1']);
        else unset($_SESSION[self::$NAME]); return true;
    }

    public static function saveUserInfo($user){
        try{
            static::saveLogin($user['email'], $user['password']);
            $_SESSION[self::$NAME]['usi1'] = \Form1::encrypt_base64( serialize($user) );
        }catch (Exception $ex){ Log1::log($ex); }
    }


    /**
     * @param bool $clearAuthSessionOnFailedAndRedirect
     * @param string $redirectTo
     * @param string $redirectMessage
     * @param string $userClassNameToCastTo
     * @return mixed|null
     *
     *      User extending AuthModel1  Required
     */
    public static function getUserInfo($clearAuthSessionOnFailedAndRedirect = false, $redirectTo = '', $redirectMessage = 'Session Expired, Please Login!', $userClassNameToCastTo = 'User'){

        // login not saving, therefore re-login again
        $userInfoArray = null;

        // fetch userInfo from USI1
        if((!$userInfoArray) && isset($_SESSION[self::$NAME]['usi1'])) {
            $login = unserialize(\Form1::decrypt_base64(($_SESSION[self::$NAME]['usi1'])));
            if(( isset($login['email']) && trim($login['email']) != '') &&( isset($login['password']) && trim($login['password']) != '')) $userInfoArray = $login;
        }


        // generate userInfo
        if (!$userInfoArray) {
            try{
                $login = Session1::getLogin();
                if($login) $userInfoArray =  $userClassNameToCastTo::login(String1::isset_or($login['email'], null),  String1::isset_or($login['password'], null));
            }catch (Exception $e){ }
        }



        // $userInfo
        if(!$userInfoArray){
            if($clearAuthSessionOnFailedAndRedirect){
                self::deleteUserInfo();

                // redirect
                if(trim($redirectTo) !== '') {
                    // save last path
                    self::setLastAuthUrl(Url1::getPageFullUrl());

                    // now redirect
                    Url1::redirectIf($redirectTo, $redirectMessage, [ true ]);
                    return null;
                }
            }
            return null;
        }

        // cast array object to user
        return Object1::toArrayObject(true,  Object1::convertArrayToObject($userInfoArray, (($userClassNameToCastTo)? $userClassNameToCastTo: User::class)) ) ;
    }


    /**
     * @param $url
     * Save and Get Last Url before Requesting for login Auth. So you can resume user back to there init path
     */
    static function setLastAuthUrl($url){ self::set('last_auth_url', $url); }
    static function getLastAuthUrl($unset = true, $defaultIfFailed = null){ $last_url = $unset? self::getAndUnset('last_auth_url'): self::get('last_auth_url'); return $last_url? $last_url: $defaultIfFailed; }





    static function setAccountData($name, $value){
        $_SESSION[self::$NAME][$name] = \Form2::encrypt($value);
    }

    static function getAccountData($name){
        if(isset($_SESSION[self::$NAME][$name])) return \Form2::decrypt($_SESSION[self::$NAME][$name]);
        return null;
    }

    static function deleteAccountData($name = null){
        if($name === null) unset($_SESSION[self::$NAME]);
        else unset($_SESSION[self::$NAME][$name]);
    }






    //|||||||||||||||||| Status |||||||||||||||||||\\
    public static function setStatus($title = '', $message = '', $type = 'info', $appendStatus = true){
        $_SESSION['sTitle'] = (isset($_SESSION['sTitle']) && $appendStatus)?  $_SESSION['sTitle']: $title;
        $_SESSION['sStatus'] = (isset($_SESSION['sStatus']) && $appendStatus)? array_merge(Array1::toArray($_SESSION['sStatus']), Array1::toArray($message)): $message;
        $_SESSION['sType'] = $type;
        $_SESSION['sIsActive'] = true;
        return null;
    }

    public static function setStatusIf($condition = false, $title = '', $message = '', $type = 'info'){ return $condition?  static::setStatus($title, $message, $type): null; }


    /**
     * Use when you are confused about type of status
     *  array $status [e.g 'title', 'body', 'type']
     * @param array | ResultObject1 | ResultStatus1 $status (Set Status Message from  either Array , Method as Result class of Ehex)
     * @return array (Optional , return separated value)
     */
    public static function setStatusFrom($status = null){
        $status = $status instanceof ResultObject1 || $status instanceof ResultStatus1 ?
            ['Status', $status->getMessage(), $status->getStatus()? 'info': 'error']:
            Array1::makeArray($status);

        $title = 'Status';
        $body = '';
        $type = 'info';

        // extract
        if((count($status) === 1) || (count($status) > 3)) $body = $status;
        else if(count($status) === 3) list($title, $body, $type) = $status;
        else if(count($status) === 2) list($title, $body) = $status;

        // assign
        $type = (strtolower($type) === 'danger')? 'error' : $type;
        $body = Array1::normalizeIfSingleArray($body);
        static::setStatus($title, $body, $type);
        return ( [
            'title' => $title,
            'body' => $body,
            'info' => $type,
        ]);
    }



    /**
     * @return array|null get and delete status
     */
    public static function getAndUnsetStatus(){
        $data = self::getStatus();
        self::deleteStatus();
        return $data;
    }

    public static function deleteStatus(){
        $_SESSION['sIsActive'] = false;
        unset($_SESSION['sIsActive'], $_SESSION['sTitle']); unset($_SESSION['sStatus']); unset($_SESSION['sType']);
    }

    static function getStatus(){
        if(!String1::isset_or($_SESSION['sIsActive'], false)) return null;
        if(isset($_SESSION['sTitle'], $_SESSION['sStatus'], $_SESSION['sType'])) {
            return [
                'title' => $_SESSION['sTitle'],     // brief description
                'body' => $_SESSION['sStatus'],     // more description
                'status' => $_SESSION['sStatus'],   // true or false
                'info' => $_SESSION['sType'],       // description type
            ];
        }
        return null;
    }

    static function isStatusSet(){
        return (isset($_SESSION['sIsActive']) && $_SESSION['sIsActive']== true);
    }


    /**
     * @param null $errors
     * @param bool $unsetStatus
     * @return Popup1
     */
    static function popupStatus($errors = null, $unsetStatus = true){
        $popup = new Popup1();
        if(isset($errors) && $errors->any()){
            $popup = new Popup1('Error', '', Popup1::$TYPE_WARNING);
            foreach ($errors->all() as $error) $popup->addBody($error);
        }
        else if(static::isStatusSet()) $popup = (new Popup1())->setDataFromArray(($unsetStatus)? Session1::getAndUnsetStatus(): Session1::getStatus());
        return $popup;
    }
}

class Popup1{
    // plugins
    // pnotify
    // swal

    static $TYPE_ERROR = "error";
    static $TYPE_WARNING = "warning";
    static $TYPE_SUCCESS = "success";
    static $TYPE_INFORMATION = "info";



    // variable
    public $title = '';
    public $body = [];
    public $type = '';



    // init data
    function __construct($title='', $body='', $type='info'){
        $this->setType($type);
        $this->setTitle($title);
        $this->setBody($body);

        return $this;
    }

    // set data
    function setDataFromArray($data = []){
        if(!empty($data) && isset($data['title'])) return new self(@$data['title'], @$data['body'], @$data['info']);
    }
    function setData($title='', $body='', $type='info'){
        return new self($title, $body, $type);
    }
    function setTitle($title = '') {
        $this->title = $title;
        return $this;
    }
    function setBody($body = '') {
        if (String1::is_empty($body)) return '';
        $this->body[] = $body;
        return $this;
    }
    function setType($type = 'info') {
        $this->type = $type;
        return $this;
    }

    function addBody($body = '') {
        if (String1::is_empty($body)) return '';
        $this->body[] = $body;
        return $this;
    }



    // get data
    function issetData(){ return (String1::is_empty($this->title) &&  (count($this->body) < 1) )? false: true; }
    function getBody($listItemOpeningTag = '<li>', $listItemClosingTag = '</li>'){
        $itemList = '';
        foreach($this->body as $item){
            //if(is_array($item)) $itemList .=  $listItemOpeningTag.implode(' : ', $item).$listItemClosingTag;
            if(is_array($item) && (count($item)>1)){
                $itemListBuffer = '';
                for ($ii=0; $ii < count($item); $ii++){
                    $startCount = ($listItemOpeningTag == '') ? '('.($ii+1).') ' : '';
                    $itemListBuffer .= $startCount.$listItemOpeningTag. String1::escapeQuotes(@$item[$ii])  .' '.$listItemClosingTag;
                }
                $itemList = $itemListBuffer;
            }
            else $itemList .= String1::toString(Array1::toArray(  String1::escapeQuotes($item)  ), ' ');
        }
        return $itemList;
    }
    function getTitle(){return $this->title; }
    function getType(){return $this->type; }






    // dialog
    function toWindowsAlert(){ if ($this->issetData()) Console1::popup($this->getTitle().'\n'.$this->getBody('','') ); }

    function toToast($listItemOpeningTag='', $listItemClosingTag=''){ if ($this->issetData()) echo  HtmlWidget1::toast($this->getTitle(), $this->getBody($listItemOpeningTag, $listItemClosingTag), $this->getType()); }

    function toHtmlList($listItemOpeningTag = '<li>', $listItemClosingTag = '</li>'){
        if ($this->issetData()) return "<div class='alert alert-".$this->getType()."> <h4><strong><i class='fa fa-$this->type'></i> $this->title</strong></h4><ol>".$this->getBody($listItemOpeningTag, $listItemClosingTag)."</ol> </div>";
        return null;
    }

    function toPanel($listItemOpeningTag = '<p>', $listItemClosingTag = '</p>'){
        if (!$this->issetData()) return;
        ?>
        <div class="panel panel-default panel-<?php echo $this->getType() ?>">
            <div class="panel-heading"><?php echo $this->getTitle() ?></div>
            <div class="panel-body"> <?php echo $this->getBody($listItemOpeningTag, $listItemClosingTag ) ?> </div>
        </div>
        <?php
    }


    /**
     *  Display Swal Alert with instance data
     * @param bool $wrapJQueryReadyScript
     * @param string $itemListOpenTag
     * @param string $itemListCloseTag
     * @return string
     */
    function toSwalAlert($wrapJQueryReadyScript = true, $itemListOpenTag = '<div style=\"padding:6px;border-bottom:1px solid #eeeeee\">', $itemListCloseTag = '</div>'){
        if (!$this->issetData()) return '';
        echo sprintf('<script> (function(){ swal({title:"%s", html:"%s", type:"%s"}) })($);</script>', $this->getTitle(), $this->getBody($itemListOpenTag, $itemListCloseTag),  $this->getType());
    }


    /**
     * @param $title
     * @param string $data
     * @param string $type
     * @return string
     */
    static function swalAlert($title, $data = '', $type = 'info'){ return sprintf('<script> (function(){ swal("%s", "%s", "%s") })($);</script>', $title, $data, $type);}
}


class Picture1{

    /* function:  generates thumbnail */
    static function generateThumb($imagePath, $saveToDestination = '_thumb', $newWidth=100) {
        /* read the source image */
        $source_image = imagecreatefromjpeg($imagePath);
        $width = imagesx($source_image);
        $height = imagesy($source_image);
        /* find the "desired height" of this thumbnail, relative to the desired width  */
        $desired_height = floor($height*($newWidth/$width));
        /* create a new, "virtual" image */
        $virtual_image = imagecreatetruecolor($newWidth,$desired_height);
        /* copy source image at a resized size */
        imagecopyresized($virtual_image,$source_image,0,0,0,0,$newWidth,$desired_height,$width,$height);
        /* create the physical thumbnail image to its destination */
        imagejpeg($virtual_image, $saveToDestination);
    }

    static function isImage($source_url){
        $info = getimagesize($source_url);
        $mimeTypeList = ["image/jpeg", "image/gif", "image/png"];
        return in_array($info['mime'], $mimeTypeList);
    }



    /**
     * The higher the number, the better the quality, but unfortunately the larger the size. You also can resize images with functions like imagecopyresampled and imagecopyresized.
     * @param $source_url
     * @param $destination_url
     * @param $quality
     * @return mixed
     */
    function compressAndUploadPicture_asJpeg($source_url, $destination_url, $quality = 60) {
        $info = getimagesize($source_url);
        if ($info['mime'] == 'image/jpeg') $image = imagecreatefromjpeg($source_url);
        elseif ($info['mime'] == 'image/gif') $image = imagecreatefromgif($source_url);
        elseif ($info['mime'] == 'image/png') $image = imagecreatefrompng($source_url);
        else return false;
        imagejpeg($image, $destination_url, $quality);
        return $destination_url;
    }

    /**
     * The quality works only for JPG�s images. But if you want to change the file to PNG�s, you have to change manually via code. GIF doesn't affect the quality
     * Default quality for PNG: 9 ( 0 - no compression, 9 - max compression ) Create a new instance of a class
     * This function will return only the name of new image compressed with your respective extension
     *
     * @param $file_path
     * @param null $destination
     * @param int $quality
     * @param int $pngQuality
     * @return bool
     */
    public static function compressAndUploadPicture($file_path, $destination = null, $quality=60, $pngQuality = 9){
        //Send image array
        $array_img_types = array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png');
        $new_image = null;
        $image_extension = null;
        $maxsize = 5245330;
        try{
            //Get image width, height, mimetype, etc..
            $image_data = getimagesize($file_path);
            //Set MimeType on variable
            $image_mime = $image_data['mime'];
            //Verifiy if the file is a image
            if(!in_array($image_mime, $array_img_types)) return false;
            //Get file size
            $image_size = filesize($file_path);
            //if image size is bigger than 5mb
            if($image_size >= $maxsize){return false;}

            //Switch to find the file type
            switch ($image_mime){
                //if is JPG and siblings
                case 'image/jpeg': case 'image/pjpeg':
                //Create a new jpg image
                $new_image = imagecreatefromjpeg($file_path);
                imagejpeg($new_image, $destination, $quality);
                break;
                //if is PNG and siblings
                case 'image/png': case 'image/x-png':
                //Create a new png image
                $new_image = imagecreatefrompng($file_path);
                imagealphablending($new_image , false);
                imagesavealpha($new_image, true);
                imagepng($new_image, $destination, $pngQuality);
                break;
                // if is GIF
                case 'image/gif':
                    //Create a new gif image
                    $new_image = imagecreatefromgif($file_path);
                    imagealphablending($new_image, false);
                    imagesavealpha($new_image, true);
                    imagegif($new_image, $destination);
            }

        } catch (Exception $ex) {
            return $ex->getMessage();
        }
        //Return the new image resized
        return $new_image;
    }


    static function upload($source_url, $destination, $shouldCompress = true){
        if ($shouldCompress) if(self::compressAndUploadPicture($source_url, $destination, 20)) return true;
        return move_uploaded_file($source_url, $destination);
    }


    static function getImageSizeInKB($imageFile){  return isset($imageFile["file"]["size"])? ($imageFile["file"]["size"] / 1024): false; }


    public static function getPictureFromGravatar($email) { return @file_get_contents(sprintf('https://www.gravatar.com/avatar/%s?s=100', md5($email))); }

    public static function toBase64Only($filename){ return base64_encode(fread( fopen($filename, "r") , filesize($filename)));  }

    public static function toBase64($filename){
        $imageDetails = getimagesize($filename);
        if ($fp = fopen($filename,"rb", 0)) {
            $picture = fread($fp,filesize($filename));
            fclose($fp);
            // base64 encode the binary data, then break it
            // into chunks according to RFC 2045 semantics
            $base64 = chunk_split(base64_encode($picture));
            $imageData = 'data:'.$imageDetails['mime'].';base64,' . $base64;
        } else {
            $imageData = $filename;
        }
        return $imageData;
    }



    /**
     *
     *  @param $text
     *  @return mixed
     *
     * Generate a very simple image containing some text
     *
     * Basic usage:
     *    (new SimpleTextImage('Hello world!'))->render();
     *
     * All functionalities:
     *    (new SimpleTextImage())
     *      ->setText('Hello world!')
     *      ->setBackground(255,0,0)
     *      ->setForeground(0,255,255)
     *      ->setFontSize(2)
     *      ->setPadding(10)
     *      ->setFile('hello.jpg')
     *      ->render('jpg');
     */
    static function generateImageWithText($text) {
//        $SimpleTextImage = new class {
//
//            var $text = '';
//            var $font_size = 4;
//            var $padding = 2;
//            var $bg = array(0, 0, 0);
//            var $fg = array(255, 255, 255);
//            var $file = null;
//
//            function __construct($text=''){$this->text = $text;}
//
//            function setText($text){$this->text = $text;return $this;}
//
//            function setFontSize($font_size){$this->font_size = $font_size;return $this;}
//
//            function setPadding($padding){$this->padding = $padding;return $this;}
//
//            function setBackground($r, $g, $b){$this->bg = array($r, $g, $b);return $this;}
//
//            function setForeground($r, $g, $b){$this->fg = array($r, $g, $b);return $this;}
//
//            function setFile($file){$this->file = $file;return $this;}
//
//            function render($type = 'png') {
//                $this->text = str_replace("\r\n", "\n", $this->text);
//                $lines = explode("\n", $this->text);
//                $max_nb_chars = 0;
//                foreach ($lines as $string) { $max_nb_chars = max($max_nb_chars, strlen($string)); }
//                $char_width = imagefontwidth($this->font_size);
//                $char_height = imagefontheight($this->font_size);
//                $width = $char_width*$max_nb_chars + $this->padding*2;
//                $height = $char_height*count($lines) + $this->padding*2;
//                $img = imagecreatetruecolor($width, $height);
//                $bg = imagecolorallocate($img, $this->bg[0], $this->bg[1], $this->bg[2]);
//                imagefilledrectangle($img, 0, 0, $width, $height, $bg);
//
//                $fg = imagecolorallocate($img, $this->fg[0], $this->fg[1], $this->fg[2]);
//                foreach ($lines as $k => $string)
//                {
//                    for ($i=0, $l=strlen($string); $i<$l; $i++)
//                    {
//                        $xpos = $i * $char_width + $this->padding;
//                        $ypos = $k * $char_height + $this->padding;
//                        imagechar($img, $this->font_size, $xpos, $ypos, $string[$i], $fg);
//                    }
//                }
//                switch ($type) {
//                    case 'jpg': case 'jpeg':
//                    if ($this->file == null) header("Content-Type: image/jpeg");
//                    imagejpeg($img, $this->file, 95);
//                    break;
//                    case 'gif':
//                        if ($this->file == null) header("Content-Type: image/gif");
//                        imagegif($img, $this->file);
//                        break;
//                    case 'png': default:
//                    if ($this->file == null) header("Content-Type: image/png");
//                    imagepng($img, $this->file);
//                    break;
//                }
//                imagedestroy($img);
//            }
//
//        };
//        return new $SimpleTextImage($text);
    }


    
 //  function createThumb($sfile,$dfile,$maxwidth,$maxheight) {
 //     $simg = imagecreatefromjpeg($sfile);
 //     $currwidth=imagesx($simg);
 //     $currheight=imagesy($simg);


 //   if ($currheight>$currwidth*1.7) {
 //         $zoom=$maxheight/$currheight;
 //         $newheight=$maxheight;
 //         $newwidth=$currwidth*$zoom;
 //      }

 //    else {
 //       $zoom=$maxwidth/$currwidth;
 //       $newwidth=$maxwidth;
 //       $newheight=$currheight*$zoom;
 //    }

 //    $dimg = imagecreate($newwidth, $newheight);
 //    imagetruecolortopalette($simg, false, 256);
 //    $palsize = ImageColorsTotal($simg);
 //    for ($i = 0; $i<$palsize; $i++) {
 //        $colors = ImageColorsForIndex($simg, $i);
 //         ImageColorAllocate($dimg, $colors['red'], $colors['green'], $colors['blue']);
 //    }

 //    $safe = (bool) ini_get('safe_mode');
 //    if ($safe!=1){
 //        imagecopyresized($dimg, $simg, 0, 0, 0, 0, $newwidth, $newheight, $currwidth, $currheight);
 //        imagejpeg($dimg,$dfile);
 //    }

 //    else{
 //        imagejpeg($src);
 //    }
 //    ImageDestroy($simg);
 //    ImageDestroy($dimg);
 // }




}
API documentation generated by ApiGen