# Code coverage report for lib/fdb-all.js

## Statements: 53.76% (6803 / 12654) Branches: 40.03% (2371 / 5923) Functions: 52.8% (897 / 1699) Lines: 54.26% (6732 / 12407) Ignored: none

All files » lib/ » fdb-all.js

    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
    5776
    5777
    5778
    5779
    5780
    5781
    5782
    5783
    5784
    5785
    5786
    5787
    5788
    5789
    5790
    5791
    5792
    5793
    5794
    5795
    5796
    5797
    5798
    5799
    5800
    5801
    5802
    5803
    5804
    5805
    5806
    5807
    5808
    5809
    5810
    5811
    5812
    5813
    5814
    5815
    5816
    5817
    5818
    5819
    5820
    5821
    5822
    5823
    5824
    5825
    5826
    5827
    5828
    5829
    5830
    5831
    5832
    5833
    5834
    5835
    5836
    5837
    5838
    5839
    5840
    5841
    5842
    5843
    5844
    5845
    5846
    5847
    5848
    5849
    5850
    5851
    5852
    5853
    5854
    5855
    5856
    5857
    5858
    5859
    5860
    5861
    5862
    5863
    5864
    5865
    5866
    5867
    5868
    5869
    5870
    5871
    5872
    5873
    5874
    5875
    5876
    5877
    5878
    5879
    5880
    5881
    5882
    5883
    5884
    5885
    5886
    5887
    5888
    5889
    5890
    5891
    5892
    5893
    5894
    5895
    5896
    5897
    5898
    5899
    5900
    5901
    5902
    5903
    5904
    5905
    5906
    5907
    5908
    5909
    5910
    5911
    5912
    5913
    5914
    5915
    5916
    5917
    5918
    5919
    5920
    5921
    5922
    5923
    5924
    5925
    5926
    5927
    5928
    5929
    5930
    5931
    5932
    5933
    5934
    5935
    5936
    5937
    5938
    5939
    5940
    5941
    5942
    5943
    5944
    5945
    5946
    5947
    5948
    5949
    5950
    5951
    5952
    5953
    5954
    5955
    5956
    5957
    5958
    5959
    5960
    5961
    5962
    5963
    5964
    5965
    5966
    5967
    5968
    5969
    5970
    5971
    5972
    5973
    5974
    5975
    5976
    5977
    5978
    5979
    5980
    5981
    5982
    5983
    5984
    5985
    5986
    5987
    5988
    5989
    5990
    5991
    5992
    5993
    5994
    5995
    5996
    5997
    5998
    5999
    6000
    6001
    6002
    6003
    6004
    6005
    6006
    6007
    6008
    6009
    6010
    6011
    6012
    6013
    6014
    6015
    6016
    6017
    6018
    6019
    6020
    6021
    6022
    6023
    6024
    6025
    6026
    6027
    6028
    6029
    6030
    6031
    6032
    6033
    6034
    6035
    6036
    6037
    6038
    6039
    6040
    6041
    6042
    6043
    6044
    6045
    6046
    6047
    6048
    6049
    6050
    6051
    6052
    6053
    6054
    6055
    6056
    6057
    6058
    6059
    6060
    6061
    6062
    6063
    6064
    6065
    6066
    6067
    6068
    6069
    6070
    6071
    6072
    6073
    6074
    6075
    6076
    6077
    6078
    6079
    6080
    6081
    6082
    6083
    6084
    6085
    6086
    6087
    6088
    6089
    6090
    6091
    6092
    6093
    6094
    6095
    6096
    6097
    6098
    6099
    6100
    6101
    6102
    6103
    6104
    6105
    6106
    6107
    6108
    6109
    6110
    6111
    6112
    6113
    6114
    6115
    6116
    6117
    6118
    6119
    6120
    6121
    6122
    6123
    6124
    6125
    6126
    6127
    6128
    6129
    6130
    6131
    6132
    6133
    6134
    6135
    6136
    6137
    6138
    6139
    6140
    6141
    6142
    6143
    6144
    6145
    6146
    6147
    6148
    6149
    6150
    6151
    6152
    6153
    6154
    6155
    6156
    6157
    6158
    6159
    6160
    6161
    6162
    6163
    6164
    6165
    6166
    6167
    6168
    6169
    6170
    6171
    6172
    6173
    6174
    6175
    6176
    6177
    6178
    6179
    6180
    6181
    6182
    6183
    6184
    6185
    6186
    6187
    6188
    6189
    6190
    6191
    6192
    6193
    6194
    6195
    6196
    6197
    6198
    6199
    6200
    6201
    6202
    6203
    6204
    6205
    6206
    6207
    6208
    6209
    6210
    6211
    6212
    6213
    6214
    6215
    6216
    6217
    6218
    6219
    6220
    6221
    6222
    6223
    6224
    6225
    6226
    6227
    6228
    6229
    6230
    6231
    6232
    6233
    6234
    6235
    6236
    6237
    6238
    6239
    6240
    6241
    6242
    6243
    6244
    6245
    6246
    6247
    6248
    6249
    6250
    6251
    6252
    6253
    6254
    6255
    6256
    6257
    6258
    6259
    6260
    6261
    6262
    6263
    6264
    6265
    6266
    6267
    6268
    6269
    6270
    6271
    6272
    6273
    6274
    6275
    6276
    6277
    6278
    6279
    6280
    6281
    6282
    6283
    6284
    6285
    6286
    6287
    6288
    6289
    6290
    6291
    6292
    6293
    6294
    6295
    6296
    6297
    6298
    6299
    6300
    6301
    6302
    6303
    6304
    6305
    6306
    6307
    6308
    6309
    6310
    6311
    6312
    6313
    6314
    6315
    6316
    6317
    6318
    6319
    6320
    6321
    6322
    6323
    6324
    6325
    6326
    6327
    6328
    6329
    6330
    6331
    6332
    6333
    6334
    6335
    6336
    6337
    6338
    6339
    6340
    6341
    6342
    6343
    6344
    6345
    6346
    6347
    6348
    6349
    6350
    6351
    6352
    6353
    6354
    6355
    6356
    6357
    6358
    6359
    6360
    6361
    6362
    6363
    6364
    6365
    6366
    6367
    6368
    6369
    6370
    6371
    6372
    6373
    6374
    6375
    6376
    6377
    6378
    6379
    6380
    6381
    6382
    6383
    6384
    6385
    6386
    6387
    6388
    6389
    6390
    6391
    6392
    6393
    6394
    6395
    6396
    6397
    6398
    6399
    6400
    6401
    6402
    6403
    6404
    6405
    6406
    6407
    6408
    6409
    6410
    6411
    6412
    6413
    6414
    6415
    6416
    6417
    6418
    6419
    6420
    6421
    6422
    6423
    6424
    6425
    6426
    6427
    6428
    6429
    6430
    6431
    6432
    6433
    6434
    6435
    6436
    6437
    6438
    6439
    6440
    6441
    6442
    6443
    6444
    6445
    6446
    6447
    6448
    6449
    6450
    6451
    6452
    6453
    6454
    6455
    6456
    6457
    6458
    6459
    6460
    6461
    6462
    6463
    6464
    6465
    6466
    6467
    6468
    6469
    6470
    6471
    6472
    6473
    6474
    6475
    6476
    6477
    6478
    6479
    6480
    6481
    6482
    6483
    6484
    6485
    6486
    6487
    6488
    6489
    6490
    6491
    6492
    6493
    6494
    6495
    6496
    6497
    6498
    6499
    6500
    6501
    6502
    6503
    6504
    6505
    6506
    6507
    6508
    6509
    6510
    6511
    6512
    6513
    6514
    6515
    6516
    6517
    6518
    6519
    6520
    6521
    6522
    6523
    6524
    6525
    6526
    6527
    6528
    6529
    6530
    6531
    6532
    6533
    6534
    6535
    6536
    6537
    6538
    6539
    6540
    6541
    6542
    6543
    6544
    6545
    6546
    6547
    6548
    6549
    6550
    6551
    6552
    6553
    6554
    6555
    6556
    6557
    6558
    6559
    6560
    6561
    6562
    6563
    6564
    6565
    6566
    6567
    6568
    6569
    6570
    6571
    6572
    6573
    6574
    6575
    6576
    6577
    6578
    6579
    6580
    6581
    6582
    6583
    6584
    6585
    6586
    6587
    6588
    6589
    6590
    6591
    6592
    6593
    6594
    6595
    6596
    6597
    6598
    6599
    6600
    6601
    6602
    6603
    6604
    6605
    6606
    6607
    6608
    6609
    6610
    6611
    6612
    6613
    6614
    6615
    6616
    6617
    6618
    6619
    6620
    6621
    6622
    6623
    6624
    6625
    6626
    6627
    6628
    6629
    6630
    6631
    6632
    6633
    6634
    6635
    6636
    6637
    6638
    6639
    6640
    6641
    6642
    6643
    6644
    6645
    6646
    6647
    6648
    6649
    6650
    6651
    6652
    6653
    6654
    6655
    6656
    6657
    6658
    6659
    6660
    6661
    6662
    6663
    6664
    6665
    6666
    6667
    6668
    6669
    6670
    6671
    6672
    6673
    6674
    6675
    6676
    6677
    6678
    6679
    6680
    6681
    6682
    6683
    6684
    6685
    6686
    6687
    6688
    6689
    6690
    6691
    6692
    6693
    6694
    6695
    6696
    6697
    6698
    6699
    6700
    6701
    6702
    6703
    6704
    6705
    6706
    6707
    6708
    6709
    6710
    6711
    6712
    6713
    6714
    6715
    6716
    6717
    6718
    6719
    6720
    6721
    6722
    6723
    6724
    6725
    6726
    6727
    6728
    6729
    6730
    6731
    6732
    6733
    6734
    6735
    6736
    6737
    6738
    6739
    6740
    6741
    6742
    6743
    6744
    6745
    6746
    6747
    6748
    6749
    6750
    6751
    6752
    6753
    6754
    6755
    6756
    6757
    6758
    6759
    6760
    6761
    6762
    6763
    6764
    6765
    6766
    6767
    6768
    6769
    6770
    6771
    6772
    6773
    6774
    6775
    6776
    6777
    6778
    6779
    6780
    6781
    6782
    6783
    6784
    6785
    6786
    6787
    6788
    6789
    6790
    6791
    6792
    6793
    6794
    6795
    6796
    6797
    6798
    6799
    6800
    6801
    6802
    6803
    6804
    6805
    6806
    6807
    6808
    6809
    6810
    6811
    6812
    6813
    6814
    6815
    6816
    6817
    6818
    6819
    6820
    6821
    6822
    6823
    6824
    6825
    6826
    6827
    6828
    6829
    6830
    6831
    6832
    6833
    6834
    6835
    6836
    6837
    6838
    6839
    6840
    6841
    6842
    6843
    6844
    6845
    6846
    6847
    6848
    6849
    6850
    6851
    6852
    6853
    6854
    6855
    6856
    6857
    6858
    6859
    6860
    6861
    6862
    6863
    6864
    6865
    6866
    6867
    6868
    6869
    6870
    6871
    6872
    6873
    6874
    6875
    6876
    6877
    6878
    6879
    6880
    6881
    6882
    6883
    6884
    6885
    6886
    6887
    6888
    6889
    6890
    6891
    6892
    6893
    6894
    6895
    6896
    6897
    6898
    6899
    6900
    6901
    6902
    6903
    6904
    6905
    6906
    6907
    6908
    6909
    6910
    6911
    6912
    6913
    6914
    6915
    6916
    6917
    6918
    6919
    6920
    6921
    6922
    6923
    6924
    6925
    6926
    6927
    6928
    6929
    6930
    6931
    6932
    6933
    6934
    6935
    6936
    6937
    6938
    6939
    6940
    6941
    6942
    6943
    6944
    6945
    6946
    6947
    6948
    6949
    6950
    6951
    6952
    6953
    6954
    6955
    6956
    6957
    6958
    6959
    6960
    6961
    6962
    6963
    6964
    6965
    6966
    6967
    6968
    6969
    6970
    6971
    6972
    6973
    6974
    6975
    6976
    6977
    6978
    6979
    6980
    6981
    6982
    6983
    6984
    6985
    6986
    6987
    6988
    6989
    6990
    6991
    6992
    6993
    6994
    6995
    6996
    6997
    6998
    6999
    7000
    7001
    7002
    7003
    7004
    7005
    7006
    7007
    7008
    7009
    7010
    7011
    7012
    7013
    7014
    7015
    7016
    7017
    7018
    7019
    7020
    7021
    7022
    7023
    7024
    7025
    7026
    7027
    7028
    7029
    7030
    7031
    7032
    7033
    7034
    7035
    7036
    7037
    7038
    7039
    7040
    7041
    7042
    7043
    7044
    7045
    7046
    7047
    7048
    7049
    7050
    7051
    7052
    7053
    7054
    7055
    7056
    7057
    7058
    7059
    7060
    7061
    7062
    7063
    7064
    7065
    7066
    7067
    7068
    7069
    7070
    7071
    7072
    7073
    7074
    7075
    7076
    7077
    7078
    7079
    7080
    7081
    7082
    7083
    7084
    7085
    7086
    7087
    7088
    7089
    7090
    7091
    7092
    7093
    7094
    7095
    7096
    7097
    7098
    7099
    7100
    7101
    7102
    7103
    7104
    7105
    7106
    7107
    7108
    7109
    7110
    7111
    7112
    7113
    7114
    7115
    7116
    7117
    7118
    7119
    7120
    7121
    7122
    7123
    7124
    7125
    7126
    7127
    7128
    7129
    7130
    7131
    7132
    7133
    7134
    7135
    7136
    7137
    7138
    7139
    7140
    7141
    7142
    7143
    7144
    7145
    7146
    7147
    7148
    7149
    7150
    7151
    7152
    7153
    7154
    7155
    7156
    7157
    7158
    7159
    7160
    7161
    7162
    7163
    7164
    7165
    7166
    7167
    7168
    7169
    7170
    7171
    7172
    7173
    7174
    7175
    7176
    7177
    7178
    7179
    7180
    7181
    7182
    7183
    7184
    7185
    7186
    7187
    7188
    7189
    7190
    7191
    7192
    7193
    7194
    7195
    7196
    7197
    7198
    7199
    7200
    7201
    7202
    7203
    7204
    7205
    7206
    7207
    7208
    7209
    7210
    7211
    7212
    7213
    7214
    7215
    7216
    7217
    7218
    7219
    7220
    7221
    7222
    7223
    7224
    7225
    7226
    7227
    7228
    7229
    7230
    7231
    7232
    7233
    7234
    7235
    7236
    7237
    7238
    7239
    7240
    7241
    7242
    7243
    7244
    7245
    7246
    7247
    7248
    7249
    7250
    7251
    7252
    7253
    7254
    7255
    7256
    7257
    7258
    7259
    7260
    7261
    7262
    7263
    7264
    7265
    7266
    7267
    7268
    7269
    7270
    7271
    7272
    7273
    7274
    7275
    7276
    7277
    7278
    7279
    7280
    7281
    7282
    7283
    7284
    7285
    7286
    7287
    7288
    7289
    7290
    7291
    7292
    7293
    7294
    7295
    7296
    7297
    7298
    7299
    7300
    7301
    7302
    7303
    7304
    7305
    7306
    7307
    7308
    7309
    7310
    7311
    7312
    7313
    7314
    7315
    7316
    7317
    7318
    7319
    7320
    7321
    7322
    7323
    7324
    7325
    7326
    7327
    7328
    7329
    7330
    7331
    7332
    7333
    7334
    7335
    7336
    7337
    7338
    7339
    7340
    7341
    7342
    7343
    7344
    7345
    7346
    7347
    7348
    7349
    7350
    7351
    7352
    7353
    7354
    7355
    7356
    7357
    7358
    7359
    7360
    7361
    7362
    7363
    7364
    7365
    7366
    7367
    7368
    7369
    7370
    7371
    7372
    7373
    7374
    7375
    7376
    7377
    7378
    7379
    7380
    7381
    7382
    7383
    7384
    7385
    7386
    7387
    7388
    7389
    7390
    7391
    7392
    7393
    7394
    7395
    7396
    7397
    7398
    7399
    7400
    7401
    7402
    7403
    7404
    7405
    7406
    7407
    7408
    7409
    7410
    7411
    7412
    7413
    7414
    7415
    7416
    7417
    7418
    7419
    7420
    7421
    7422
    7423
    7424
    7425
    7426
    7427
    7428
    7429
    7430
    7431
    7432
    7433
    7434
    7435
    7436
    7437
    7438
    7439
    7440
    7441
    7442
    7443
    7444
    7445
    7446
    7447
    7448
    7449
    7450
    7451
    7452
    7453
    7454
    7455
    7456
    7457
    7458
    7459
    7460
    7461
    7462
    7463
    7464
    7465
    7466
    7467
    7468
    7469
    7470
    7471
    7472
    7473
    7474
    7475
    7476
    7477
    7478
    7479
    7480
    7481
    7482
    7483
    7484
    7485
    7486
    7487
    7488
    7489
    7490
    7491
    7492
    7493
    7494
    7495
    7496
    7497
    7498
    7499
    7500
    7501
    7502
    7503
    7504
    7505
    7506
    7507
    7508
    7509
    7510
    7511
    7512
    7513
    7514
    7515
    7516
    7517
    7518
    7519
    7520
    7521
    7522
    7523
    7524
    7525
    7526
    7527
    7528
    7529
    7530
    7531
    7532
    7533
    7534
    7535
    7536
    7537
    7538
    7539
    7540
    7541
    7542
    7543
    7544
    7545
    7546
    7547
    7548
    7549
    7550
    7551
    7552
    7553
    7554
    7555
    7556
    7557
    7558
    7559
    7560
    7561
    7562
    7563
    7564
    7565
    7566
    7567
    7568
    7569
    7570
    7571
    7572
    7573
    7574
    7575
    7576
    7577
    7578
    7579
    7580
    7581
    7582
    7583
    7584
    7585
    7586
    7587
    7588
    7589
    7590
    7591
    7592
    7593
    7594
    7595
    7596
    7597
    7598
    7599
    7600
    7601
    7602
    7603
    7604
    7605
    7606
    7607
    7608
    7609
    7610
    7611
    7612
    7613
    7614
    7615
    7616
    7617
    7618
    7619
    7620
    7621
    7622
    7623
    7624
    7625
    7626
    7627
    7628
    7629
    7630
    7631
    7632
    7633
    7634
    7635
    7636
    7637
    7638
    7639
    7640
    7641
    7642
    7643
    7644
    7645
    7646
    7647
    7648
    7649
    7650
    7651
    7652
    7653
    7654
    7655
    7656
    7657
    7658
    7659
    7660
    7661
    7662
    7663
    7664
    7665
    7666
    7667
    7668
    7669
    7670
    7671
    7672
    7673
    7674
    7675
    7676
    7677
    7678
    7679
    7680
    7681
    7682
    7683
    7684
    7685
    7686
    7687
    7688
    7689
    7690
    7691
    7692
    7693
    7694
    7695
    7696
    7697
    7698
    7699
    7700
    7701
    7702
    7703
    7704
    7705
    7706
    7707
    7708
    7709
    7710
    7711
    7712
    7713
    7714
    7715
    7716
    7717
    7718
    7719
    7720
    7721
    7722
    7723
    7724
    7725
    7726
    7727
    7728
    7729
    7730
    7731
    7732
    7733
    7734
    7735
    7736
    7737
    7738
    7739
    7740
    7741
    7742
    7743
    7744
    7745
    7746
    7747
    7748
    7749
    7750
    7751
    7752
    7753
    7754
    7755
    7756
    7757
    7758
    7759
    7760
    7761
    7762
    7763
    7764
    7765
    7766
    7767
    7768
    7769
    7770
    7771
    7772
    7773
    7774
    7775
    7776
    7777
    7778
    7779
    7780
    7781
    7782
    7783
    7784
    7785
    7786
    7787
    7788
    7789
    7790
    7791
    7792
    7793
    7794
    7795
    7796
    7797
    7798
    7799
    7800
    7801
    7802
    7803
    7804
    7805
    7806
    7807
    7808
    7809
    7810
    7811
    7812
    7813
    7814
    7815
    7816
    7817
    7818
    7819
    7820
    7821
    7822
    7823
    7824
    7825
    7826
    7827
    7828
    7829
    7830
    7831
    7832
    7833
    7834
    7835
    7836
    7837
    7838
    7839
    7840
    7841
    7842
    7843
    7844
    7845
    7846
    7847
    7848
    7849
    7850
    7851
    7852
    7853
    7854
    7855
    7856
    7857
    7858
    7859
    7860
    7861
    7862
    7863
    7864
    7865
    7866
    7867
    7868
    7869
    7870
    7871
    7872
    7873
    7874
    7875
    7876
    7877
    7878
    7879
    7880
    7881
    7882
    7883
    7884
    7885
    7886
    7887
    7888
    7889
    7890
    7891
    7892
    7893
    7894
    7895
    7896
    7897
    7898
    7899
    7900
    7901
    7902
    7903
    7904
    7905
    7906
    7907
    7908
    7909
    7910
    7911
    7912
    7913
    7914
    7915
    7916
    7917
    7918
    7919
    7920
    7921
    7922
    7923
    7924
    7925
    7926
    7927
    7928
    7929
    7930
    7931
    7932
    7933
    7934
    7935
    7936
    7937
    7938
    7939
    7940
    7941
    7942
    7943
    7944
    7945
    7946
    7947
    7948
    7949
    7950
    7951
    7952
    7953
    7954
    7955
    7956
    7957
    7958
    7959
    7960
    7961
    7962
    7963
    7964
    7965
    7966
    7967
    7968
    7969
    7970
    7971
    7972
    7973
    7974
    7975
    7976
    7977
    7978
    7979
    7980
    7981
    7982
    7983
    7984
    7985
    7986
    7987
    7988
    7989
    7990
    7991
    7992
    7993
    7994
    7995
    7996
    7997
    7998
    7999
    8000
    8001
    8002
    8003
    8004
    8005
    8006
    8007
    8008
    8009
    8010
    8011
    8012
    8013
    8014
    8015
    8016
    8017
    8018
    8019
    8020
    8021
    8022
    8023
    8024
    8025
    8026
    8027
    8028
    8029
    8030
    8031
    8032
    8033
    8034
    8035
    8036
    8037
    8038
    8039
    8040
    8041
    8042
    8043
    8044
    8045
    8046
    8047
    8048
    8049
    8050
    8051
    8052
    8053
    8054
    8055
    8056
    8057
    8058
    8059
    8060
    8061
    8062
    8063
    8064
    8065
    8066
    8067
    8068
    8069
    8070
    8071
    8072
    8073
    8074
    8075
    8076
    8077
    8078
    8079
    8080
    8081
    8082
    8083
    8084
    8085
    8086
    8087
    8088
    8089
    8090
    8091
    8092
    8093
    8094
    8095
    8096
    8097
    8098
    8099
    8100
    8101
    8102
    8103
    8104
    8105
    8106
    8107
    8108
    8109
    8110
    8111
    8112
    8113
    8114
    8115
    8116
    8117
    8118
    8119
    8120
    8121
    8122
    8123
    8124
    8125
    8126
    8127
    8128
    8129
    8130
    8131
    8132
    8133
    8134
    8135
    8136
    8137
    8138
    8139
    8140
    8141
    8142
    8143
    8144
    8145
    8146
    8147
    8148
    8149
    8150
    8151
    8152
    8153
    8154
    8155
    8156
    8157
    8158
    8159
    8160
    8161
    8162
    8163
    8164
    8165
    8166
    8167
    8168
    8169
    8170
    8171
    8172
    8173
    8174
    8175
    8176
    8177
    8178
    8179
    8180
    8181
    8182
    8183
    8184
    8185
    8186
    8187
    8188
    8189
    8190
    8191
    8192
    8193
    8194
    8195
    8196
    8197
    8198
    8199
    8200
    8201
    8202
    8203
    8204
    8205
    8206
    8207
    8208
    8209
    8210
    8211
    8212
    8213
    8214
    8215
    8216
    8217
    8218
    8219
    8220
    8221
    8222
    8223
    8224
    8225
    8226
    8227
    8228
    8229
    8230
    8231
    8232
    8233
    8234
    8235
    8236
    8237
    8238
    8239
    8240
    8241
    8242
    8243
    8244
    8245
    8246
    8247
    8248
    8249
    8250
    8251
    8252
    8253
    8254
    8255
    8256
    8257
    8258
    8259
    8260
    8261
    8262
    8263
    8264
    8265
    8266
    8267
    8268
    8269
    8270
    8271
    8272
    8273
    8274
    8275
    8276
    8277
    8278
    8279
    8280
    8281
    8282
    8283
    8284
    8285
    8286
    8287
    8288
    8289
    8290
    8291
    8292
    8293
    8294
    8295
    8296
    8297
    8298
    8299
    8300
    8301
    8302
    8303
    8304
    8305
    8306
    8307
    8308
    8309
    8310
    8311
    8312
    8313
    8314
    8315
    8316
    8317
    8318
    8319
    8320
    8321
    8322
    8323
    8324
    8325
    8326
    8327
    8328
    8329
    8330
    8331
    8332
    8333
    8334
    8335
    8336
    8337
    8338
    8339
    8340
    8341
    8342
    8343
    8344
    8345
    8346
    8347
    8348
    8349
    8350
    8351
    8352
    8353
    8354
    8355
    8356
    8357
    8358
    8359
    8360
    8361
    8362
    8363
    8364
    8365
    8366
    8367
    8368
    8369
    8370
    8371
    8372
    8373
    8374
    8375
    8376
    8377
    8378
    8379
    8380
    8381
    8382
    8383
    8384
    8385
    8386
    8387
    8388
    8389
    8390
    8391
    8392
    8393
    8394
    8395
    8396
    8397
    8398
    8399
    8400
    8401
    8402
    8403
    8404
    8405
    8406
    8407
    8408
    8409
    8410
    8411
    8412
    8413
    8414
    8415
    8416
    8417
    8418
    8419
    8420
    8421
    8422
    8423
    8424
    8425
    8426
    8427
    8428
    8429
    8430
    8431
    8432
    8433
    8434
    8435
    8436
    8437
    8438
    8439
    8440
    8441
    8442
    8443
    8444
    8445
    8446
    8447
    8448
    8449
    8450
    8451
    8452
    8453
    8454
    8455
    8456
    8457
    8458
    8459
    8460
    8461
    8462
    8463
    8464
    8465
    8466
    8467
    8468
    8469
    8470
    8471
    8472
    8473
    8474
    8475
    8476
    8477
    8478
    8479
    8480
    8481
    8482
    8483
    8484
    8485
    8486
    8487
    8488
    8489
    8490
    8491
    8492
    8493
    8494
    8495
    8496
    8497
    8498
    8499
    8500
    8501
    8502
    8503
    8504
    8505
    8506
    8507
    8508
    8509
    8510
    8511
    8512
    8513
    8514
    8515
    8516
    8517
    8518
    8519
    8520
    8521
    8522
    8523
    8524
    8525
    8526
    8527
    8528
    8529
    8530
    8531
    8532
    8533
    8534
    8535
    8536
    8537
    8538
    8539
    8540
    8541
    8542
    8543
    8544
    8545
    8546
    8547
    8548
    8549
    8550
    8551
    8552
    8553
    8554
    8555
    8556
    8557
    8558
    8559
    8560
    8561
    8562
    8563
    8564
    8565
    8566
    8567
    8568
    8569
    8570
    8571
    8572
    8573
    8574
    8575
    8576
    8577
    8578
    8579
    8580
    8581
    8582
    8583
    8584
    8585
    8586
    8587
    8588
    8589
    8590
    8591
    8592
    8593
    8594
    8595
    8596
    8597
    8598
    8599
    8600
    8601
    8602
    8603
    8604
    8605
    8606
    8607
    8608
    8609
    8610
    8611
    8612
    8613
    8614
    8615
    8616
    8617
    8618
    8619
    8620
    8621
    8622
    8623
    8624
    8625
    8626
    8627
    8628
    8629
    8630
    8631
    8632
    8633
    8634
    8635
    8636
    8637
    8638
    8639
    8640
    8641
    8642
    8643
    8644
    8645
    8646
    8647
    8648
    8649
    8650
    8651
    8652
    8653
    8654
    8655
    8656
    8657
    8658
    8659
    8660
    8661
    8662
    8663
    8664
    8665
    8666
    8667
    8668
    8669
    8670
    8671
    8672
    8673
    8674
    8675
    8676
    8677
    8678
    8679
    8680
    8681
    8682
    8683
    8684
    8685
    8686
    8687
    8688
    8689
    8690
    8691
    8692
    8693
    8694
    8695
    8696
    8697
    8698
    8699
    8700
    8701
    8702
    8703
    8704
    8705
    8706
    8707
    8708
    8709
    8710
    8711
    8712
    8713
    8714
    8715
    8716
    8717
    8718
    8719
    8720
    8721
    8722
    8723
    8724
    8725
    8726
    8727
    8728
    8729
    8730
    8731
    8732
    8733
    8734
    8735
    8736
    8737
    8738
    8739
    8740
    8741
    8742
    8743
    8744
    8745
    8746
    8747
    8748
    8749
    8750
    8751
    8752
    8753
    8754
    8755
    8756
    8757
    8758
    8759
    8760
    8761
    8762
    8763
    8764
    8765
    8766
    8767
    8768
    8769
    8770
    8771
    8772
    8773
    8774
    8775
    8776
    8777
    8778
    8779
    8780
    8781
    8782
    8783
    8784
    8785
    8786
    8787
    8788
    8789
    8790
    8791
    8792
    8793
    8794
    8795
    8796
    8797
    8798
    8799
    8800
    8801
    8802
    8803
    8804
    8805
    8806
    8807
    8808
    8809
    8810
    8811
    8812
    8813
    8814
    8815
    8816
    8817
    8818
    8819
    8820
    8821
    8822
    8823
    8824
    8825
    8826
    8827
    8828
    8829
    8830
    8831
    8832
    8833
    8834
    8835
    8836
    8837
    8838
    8839
    8840
    8841
    8842
    8843
    8844
    8845
    8846
    8847
    8848
    8849
    8850
    8851
    8852
    8853
    8854
    8855
    8856
    8857
    8858
    8859
    8860
    8861
    8862
    8863
    8864
    8865
    8866
    8867
    8868
    8869
    8870
    8871
    8872
    8873
    8874
    8875
    8876
    8877
    8878
    8879
    8880
    8881
    8882
    8883
    8884
    8885
    8886
    8887
    8888
    8889
    8890
    8891
    8892
    8893
    8894
    8895
    8896
    8897
    8898
    8899
    8900
    8901
    8902
    8903
    8904
    8905
    8906
    8907
    8908
    8909
    8910
    8911
    8912
    8913
    8914
    8915
    8916
    8917
    8918
    8919
    8920
    8921
    8922
    8923
    8924
    8925
    8926
    8927
    8928
    8929
    8930
    8931
    8932
    8933
    8934
    8935
    8936
    8937
    8938
    8939
    8940
    8941
    8942
    8943
    8944
    8945
    8946
    8947
    8948
    8949
    8950
    8951
    8952
    8953
    8954
    8955
    8956
    8957
    8958
    8959
    8960
    8961
    8962
    8963
    8964
    8965
    8966
    8967
    8968
    8969
    8970
    8971
    8972
    8973
    8974
    8975
    8976
    8977
    8978
    8979
    8980
    8981
    8982
    8983
    8984
    8985
    8986
    8987
    8988
    8989
    8990
    8991
    8992
    8993
    8994
    8995
    8996
    8997
    8998
    8999
    9000
    9001
    9002
    9003
    9004
    9005
    9006
    9007
    9008
    9009
    9010
    9011
    9012
    9013
    9014
    9015
    9016
    9017
    9018
    9019
    9020
    9021
    9022
    9023
    9024
    9025
    9026
    9027
    9028
    9029
    9030
    9031
    9032
    9033
    9034
    9035
    9036
    9037
    9038
    9039
    9040
    9041
    9042
    9043
    9044
    9045
    9046
    9047
    9048
    9049
    9050
    9051
    9052
    9053
    9054
    9055
    9056
    9057
    9058
    9059
    9060
    9061
    9062
    9063
    9064
    9065
    9066
    9067
    9068
    9069
    9070
    9071
    9072
    9073
    9074
    9075
    9076
    9077
    9078
    9079
    9080
    9081
    9082
    9083
    9084
    9085
    9086
    9087
    9088
    9089
    9090
    9091
    9092
    9093
    9094
    9095
    9096
    9097
    9098
    9099
    9100
    9101
    9102
    9103
    9104
    9105
    9106
    9107
    9108
    9109
    9110
    9111
    9112
    9113
    9114
    9115
    9116
    9117
    9118
    9119
    9120
    9121
    9122
    9123
    9124
    9125
    9126
    9127
    9128
    9129
    9130
    9131
    9132
    9133
    9134
    9135
    9136
    9137
    9138
    9139
    9140
    9141
    9142
    9143
    9144
    9145
    9146
    9147
    9148
    9149
    9150
    9151
    9152
    9153
    9154
    9155
    9156
    9157
    9158
    9159
    9160
    9161
    9162
    9163
    9164
    9165
    9166
    9167
    9168
    9169
    9170
    9171
    9172
    9173
    9174
    9175
    9176
    9177
    9178
    9179
    9180
    9181
    9182
    9183
    9184
    9185
    9186
    9187
    9188
    9189
    9190
    9191
    9192
    9193
    9194
    9195
    9196
    9197
    9198
    9199
    9200
    9201
    9202
    9203
    9204
    9205
    9206
    9207
    9208
    9209
    9210
    9211
    9212
    9213
    9214
    9215
    9216
    9217
    9218
    9219
    9220
    9221
    9222
    9223
    9224
    9225
    9226
    9227
    9228
    9229
    9230
    9231
    9232
    9233
    9234
    9235
    9236
    9237
    9238
    9239
    9240
    9241
    9242
    9243
    9244
    9245
    9246
    9247
    9248
    9249
    9250
    9251
    9252
    9253
    9254
    9255
    9256
    9257
    9258
    9259
    9260
    9261
    9262
    9263
    9264
    9265
    9266
    9267
    9268
    9269
    9270
    9271
    9272
    9273
    9274
    9275
    9276
    9277
    9278
    9279
    9280
    9281
    9282
    9283
    9284
    9285
    9286
    9287
    9288
    9289
    9290
    9291
    9292
    9293
    9294
    9295
    9296
    9297
    9298
    9299
    9300
    9301
    9302
    9303
    9304
    9305
    9306
    9307
    9308
    9309
    9310
    9311
    9312
    9313
    9314
    9315
    9316
    9317
    9318
    9319
    9320
    9321
    9322
    9323
    9324
    9325
    9326
    9327
    9328
    9329
    9330
    9331
    9332
    9333
    9334
    9335
    9336
    9337
    9338
    9339
    9340
    9341
    9342
    9343
    9344
    9345
    9346
    9347
    9348
    9349
    9350
    9351
    9352
    9353
    9354
    9355
    9356
    9357
    9358
    9359
    9360
    9361
    9362
    9363
    9364
    9365
    9366
    9367
    9368
    9369
    9370
    9371
    9372
    9373
    9374
    9375
    9376
    9377
    9378
    9379
    9380
    9381
    9382
    9383
    9384
    9385
    9386
    9387
    9388
    9389
    9390
    9391
    9392
    9393
    9394
    9395
    9396
    9397
    9398
    9399
    9400
    9401
    9402
    9403
    9404
    9405
    9406
    9407
    9408
    9409
    9410
    9411
    9412
    9413
    9414
    9415
    9416
    9417
    9418
    9419
    9420
    9421
    9422
    9423
    9424
    9425
    9426
    9427
    9428
    9429
    9430
    9431
    9432
    9433
    9434
    9435
    9436
    9437
    9438
    9439
    9440
    9441
    9442
    9443
    9444
    9445
    9446
    9447
    9448
    9449
    9450
    9451
    9452
    9453
    9454
    9455
    9456
    9457
    9458
    9459
    9460
    9461
    9462
    9463
    9464
    9465
    9466
    9467
    9468
    9469
    9470
    9471
    9472
    9473
    9474
    9475
    9476
    9477
    9478
    9479
    9480
    9481
    9482
    9483
    9484
    9485
    9486
    9487
    9488
    9489
    9490
    9491
    9492
    9493
    9494
    9495
    9496
    9497
    9498
    9499
    9500
    9501
    9502
    9503
    9504
    9505
    9506
    9507
    9508
    9509
    9510
    9511
    9512
    9513
    9514
    9515
    9516
    9517
    9518
    9519
    9520
    9521
    9522
    9523
    9524
    9525
    9526
    9527
    9528
    9529
    9530
    9531
    9532
    9533
    9534
    9535
    9536
    9537
    9538
    9539
    9540
    9541
    9542
    9543
    9544
    9545
    9546
    9547
    9548
    9549
    9550
    9551
    9552
    9553
    9554
    9555
    9556
    9557
    9558
    9559
    9560
    9561
    9562
    9563
    9564
    9565
    9566
    9567
    9568
    9569
    9570
    9571
    9572
    9573
    9574
    9575
    9576
    9577
    9578
    9579
    9580
    9581
    9582
    9583
    9584
    9585
    9586
    9587
    9588
    9589
    9590
    9591
    9592
    9593
    9594
    9595
    9596
    9597
    9598
    9599
    9600
    9601
    9602
    9603
    9604
    9605
    9606
    9607
    9608
    9609
    9610
    9611
    9612
    9613
    9614
    9615
    9616
    9617
    9618
    9619
    9620
    9621
    9622
    9623
    9624
    9625
    9626
    9627
    9628
    9629
    9630
    9631
    9632
    9633
    9634
    9635
    9636
    9637
    9638
    9639
    9640
    9641
    9642
    9643
    9644
    9645
    9646
    9647
    9648
    9649
    9650
    9651
    9652
    9653
    9654
    9655
    9656
    9657
    9658
    9659
    9660
    9661
    9662
    9663
    9664
    9665
    9666
    9667
    9668
    9669
    9670
    9671
    9672
    9673
    9674
    9675
    9676
    9677
    9678
    9679
    9680
    9681
    9682
    9683
    9684
    9685
    9686
    9687
    9688
    9689
    9690
    9691
    9692
    9693
    9694
    9695
    9696
    9697
    9698
    9699
    9700
    9701
    9702
    9703
    9704
    9705
    9706
    9707
    9708
    9709
    9710
    9711
    9712
    9713
    9714
    9715
    9716
    9717
    9718
    9719
    9720
    9721
    9722
    9723
    9724
    9725
    9726
    9727
    9728
    9729
    9730
    9731
    9732
    9733
    9734
    9735
    9736
    9737
    9738
    9739
    9740
    9741
    9742
    9743
    9744
    9745
    9746
    9747
    9748
    9749
    9750
    9751
    9752
    9753
    9754
    9755
    9756
    9757
    9758
    9759
    9760
    9761
    9762
    9763
    9764
    9765
    9766
    9767
    9768
    9769
    9770
    9771
    9772
    9773
    9774
    9775
    9776
    9777
    9778
    9779
    9780
    9781
    9782
    9783
    9784
    9785
    9786
    9787
    9788
    9789
    9790
    9791
    9792
    9793
    9794
    9795
    9796
    9797
    9798
    9799
    9800
    9801
    9802
    9803
    9804
    9805
    9806
    9807
    9808
    9809
    9810
    9811
    9812
    9813
    9814
    9815
    9816
    9817
    9818
    9819
    9820
    9821
    9822
    9823
    9824
    9825
    9826
    9827
    9828
    9829
    9830
    9831
    9832
    9833
    9834
    9835
    9836
    9837
    9838
    9839
    9840
    9841
    9842
    9843
    9844
    9845
    9846
    9847
    9848
    9849
    9850
    9851
    9852
    9853
    9854
    9855
    9856
    9857
    9858
    9859
    9860
    9861
    9862
    9863
    9864
    9865
    9866
    9867
    9868
    9869
    9870
    9871
    9872
    9873
    9874
    9875
    9876
    9877
    9878
    9879
    9880
    9881
    9882
    9883
    9884
    9885
    9886
    9887
    9888
    9889
    9890
    9891
    9892
    9893
    9894
    9895
    9896
    9897
    9898
    9899
    9900
    9901
    9902
    9903
    9904
    9905
    9906
    9907
    9908
    9909
    9910
    9911
    9912
    9913
    9914
    9915
    9916
    9917
    9918
    9919
    9920
    9921
    9922
    9923
    9924
    9925
    9926
    9927
    9928
    9929
    9930
    9931
    9932
    9933
    9934
    9935
    9936
    9937
    9938
    9939
    9940
    9941
    9942
    9943
    9944
    9945
    9946
    9947
    9948
    9949
    9950
    9951
    9952
    9953
    9954
    9955
    9956
    9957
    9958
    9959
    9960
    9961
    9962
    9963
    9964
    9965
    9966
    9967
    9968
    9969
    9970
    9971
    9972
    9973
    9974
    9975
    9976
    9977
    9978
    9979
    9980
    9981
    9982
    9983
    9984
    9985
    9986
    9987
    9988
    9989
    9990
    9991
    9992
    9993
    9994
    9995
    9996
    9997
    9998
    9999
    10000
    10001
    10002
    10003
    10004
    10005
    10006
    10007
    10008
    10009
    10010
    10011
    10012
    10013
    10014
    10015
    10016
    10017
    10018
    10019
    10020
    10021
    10022
    10023
    10024
    10025
    10026
    10027
    10028
    10029
    10030
    10031
    10032
    10033
    10034
    10035
    10036
    10037
    10038
    10039
    10040
    10041
    10042
    10043
    10044
    10045
    10046
    10047
    10048
    10049
    10050
    10051
    10052
    10053
    10054
    10055
    10056
    10057
    10058
    10059
    10060
    10061
    10062
    10063
    10064
    10065
    10066
    10067
    10068
    10069
    10070
    10071
    10072
    10073
    10074
    10075
    10076
    10077
    10078
    10079
    10080
    10081
    10082
    10083
    10084
    10085
    10086
    10087
    10088
    10089
    10090
    10091
    10092
    10093
    10094
    10095
    10096
    10097
    10098
    10099
    10100
    10101
    10102
    10103
    10104
    10105
    10106
    10107
    10108
    10109
    10110
    10111
    10112
    10113
    10114
    10115
    10116
    10117
    10118
    10119
    10120
    10121
    10122
    10123
    10124
    10125
    10126
    10127
    10128
    10129
    10130
    10131
    10132
    10133
    10134
    10135
    10136
    10137
    10138
    10139
    10140
    10141
    10142
    10143
    10144
    10145
    10146
    10147
    10148
    10149
    10150
    10151
    10152
    10153
    10154
    10155
    10156
    10157
    10158
    10159
    10160
    10161
    10162
    10163
    10164
    10165
    10166
    10167
    10168
    10169
    10170
    10171
    10172
    10173
    10174
    10175
    10176
    10177
    10178
    10179
    10180
    10181
    10182
    10183
    10184
    10185
    10186
    10187
    10188
    10189
    10190
    10191
    10192
    10193
    10194
    10195
    10196
    10197
    10198
    10199
    10200
    10201
    10202
    10203
    10204
    10205
    10206
    10207
    10208
    10209
    10210
    10211
    10212
    10213
    10214
    10215
    10216
    10217
    10218
    10219
    10220
    10221
    10222
    10223
    10224
    10225
    10226
    10227
    10228
    10229
    10230
    10231
    10232
    10233
    10234
    10235
    10236
    10237
    10238
    10239
    10240
    10241
    10242
    10243
    10244
    10245
    10246
    10247
    10248
    10249
    10250
    10251
    10252
    10253
    10254
    10255
    10256
    10257
    10258
    10259
    10260
    10261
    10262
    10263
    10264
    10265
    10266
    10267
    10268
    10269
    10270
    10271
    10272
    10273
    10274
    10275
    10276
    10277
    10278
    10279
    10280
    10281
    10282
    10283
    10284
    10285
    10286
    10287
    10288
    10289
    10290
    10291
    10292
    10293
    10294
    10295
    10296
    10297
    10298
    10299
    10300
    10301
    10302
    10303
    10304
    10305
    10306
    10307
    10308
    10309
    10310
    10311
    10312
    10313
    10314
    10315
    10316
    10317
    10318
    10319
    10320
    10321
    10322
    10323
    10324
    10325
    10326
    10327
    10328
    10329
    10330
    10331
    10332
    10333
    10334
    10335
    10336
    10337
    10338
    10339
    10340
    10341
    10342
    10343
    10344
    10345
    10346
    10347
    10348
    10349
    10350
    10351
    10352
    10353
    10354
    10355
    10356
    10357
    10358
    10359
    10360
    10361
    10362
    10363
    10364
    10365
    10366
    10367
    10368
    10369
    10370
    10371
    10372
    10373
    10374
    10375
    10376
    10377
    10378
    10379
    10380
    10381
    10382
    10383
    10384
    10385
    10386
    10387
    10388
    10389
    10390
    10391
    10392
    10393
    10394
    10395
    10396
    10397
    10398
    10399
    10400
    10401
    10402
    10403
    10404
    10405
    10406
    10407
    10408
    10409
    10410
    10411
    10412
    10413
    10414
    10415
    10416
    10417
    10418
    10419
    10420
    10421
    10422
    10423
    10424
    10425
    10426
    10427
    10428
    10429
    10430
    10431
    10432
    10433
    10434
    10435
    10436
    10437
    10438
    10439
    10440
    10441
    10442
    10443
    10444
    10445
    10446
    10447
    10448
    10449
    10450
    10451
    10452
    10453
    10454
    10455
    10456
    10457
    10458
    10459
    10460
    10461
    10462
    10463
    10464
    10465
    10466
    10467
    10468
    10469
    10470
    10471
    10472
    10473
    10474
    10475
    10476
    10477
    10478
    10479
    10480
    10481
    10482
    10483
    10484
    10485
    10486
    10487
    10488
    10489
    10490
    10491
    10492
    10493
    10494
    10495
    10496
    10497
    10498
    10499
    10500
    10501
    10502
    10503
    10504
    10505
    10506
    10507
    10508
    10509
    10510
    10511
    10512
    10513
    10514
    10515
    10516
    10517
    10518
    10519
    10520
    10521
    10522
    10523
    10524
    10525
    10526
    10527
    10528
    10529
    10530
    10531
    10532
    10533
    10534
    10535
    10536
    10537
    10538
    10539
    10540
    10541
    10542
    10543
    10544
    10545
    10546
    10547
    10548
    10549
    10550
    10551
    10552
    10553
    10554
    10555
    10556
    10557
    10558
    10559
    10560
    10561
    10562
    10563
    10564
    10565
    10566
    10567
    10568
    10569
    10570
    10571
    10572
    10573
    10574
    10575
    10576
    10577
    10578
    10579
    10580
    10581
    10582
    10583
    10584
    10585
    10586
    10587
    10588
    10589
    10590
    10591
    10592
    10593
    10594
    10595
    10596
    10597
    10598
    10599
    10600
    10601
    10602
    10603
    10604
    10605
    10606
    10607
    10608
    10609
    10610
    10611
    10612
    10613
    10614
    10615
    10616
    10617
    10618
    10619
    10620
    10621
    10622
    10623
    10624
    10625
    10626
    10627
    10628
    10629
    10630
    10631
    10632
    10633
    10634
    10635
    10636
    10637
    10638
    10639
    10640
    10641
    10642
    10643
    10644
    10645
    10646
    10647
    10648
    10649
    10650
    10651
    10652
    10653
    10654
    10655
    10656
    10657
    10658
    10659
    10660
    10661
    10662
    10663
    10664
    10665
    10666
    10667
    10668
    10669
    10670
    10671
    10672
    10673
    10674
    10675
    10676
    10677
    10678
    10679
    10680
    10681
    10682
    10683
    10684
    10685
    10686
    10687
    10688
    10689
    10690
    10691
    10692
    10693
    10694
    10695
    10696
    10697
    10698
    10699
    10700
    10701
    10702
    10703
    10704
    10705
    10706
    10707
    10708
    10709
    10710
    10711
    10712
    10713
    10714
    10715
    10716
    10717
    10718
    10719
    10720
    10721
    10722
    10723
    10724
    10725
    10726
    10727
    10728
    10729
    10730
    10731
    10732
    10733
    10734
    10735
    10736
    10737
    10738
    10739
    10740
    10741
    10742
    10743
    10744
    10745
    10746
    10747
    10748
    10749
    10750
    10751
    10752
    10753
    10754
    10755
    10756
    10757
    10758
    10759
    10760
    10761
    10762
    10763
    10764
    10765
    10766
    10767
    10768
    10769
    10770
    10771
    10772
    10773
    10774
    10775
    10776
    10777
    10778
    10779
    10780
    10781
    10782
    10783
    10784
    10785
    10786
    10787
    10788
    10789
    10790
    10791
    10792
    10793
    10794
    10795
    10796
    10797
    10798
    10799
    10800
    10801
    10802
    10803
    10804
    10805
    10806
    10807
    10808
    10809
    10810
    10811
    10812
    10813
    10814
    10815
    10816
    10817
    10818
    10819
    10820
    10821
    10822
    10823
    10824
    10825
    10826
    10827
    10828
    10829
    10830
    10831
    10832
    10833
    10834
    10835
    10836
    10837
    10838
    10839
    10840
    10841
    10842
    10843
    10844
    10845
    10846
    10847
    10848
    10849
    10850
    10851
    10852
    10853
    10854
    10855
    10856
    10857
    10858
    10859
    10860
    10861
    10862
    10863
    10864
    10865
    10866
    10867
    10868
    10869
    10870
    10871
    10872
    10873
    10874
    10875
    10876
    10877
    10878
    10879
    10880
    10881
    10882
    10883
    10884
    10885
    10886
    10887
    10888
    10889
    10890
    10891
    10892
    10893
    10894
    10895
    10896
    10897
    10898
    10899
    10900
    10901
    10902
    10903
    10904
    10905
    10906
    10907
    10908
    10909
    10910
    10911
    10912
    10913
    10914
    10915
    10916
    10917
    10918
    10919
    10920
    10921
    10922
    10923
    10924
    10925
    10926
    10927
    10928
    10929
    10930
    10931
    10932
    10933
    10934
    10935
    10936
    10937
    10938
    10939
    10940
    10941
    10942
    10943
    10944
    10945
    10946
    10947
    10948
    10949
    10950
    10951
    10952
    10953
    10954
    10955
    10956
    10957
    10958
    10959
    10960
    10961
    10962
    10963
    10964
    10965
    10966
    10967
    10968
    10969
    10970
    10971
    10972
    10973
    10974
    10975
    10976
    10977
    10978
    10979
    10980
    10981
    10982
    10983
    10984
    10985
    10986
    10987
    10988
    10989
    10990
    10991
    10992
    10993
    10994
    10995
    10996
    10997
    10998
    10999
    11000
    11001
    11002
    11003
    11004
    11005
    11006
    11007
    11008
    11009
    11010
    11011
    11012
    11013
    11014
    11015
    11016
    11017
    11018
    11019
    11020
    11021
    11022
    11023
    11024
    11025
    11026
    11027
    11028
    11029
    11030
    11031
    11032
    11033
    11034
    11035
    11036
    11037
    11038
    11039
    11040
    11041
    11042
    11043
    11044
    11045
    11046
    11047
    11048
    11049
    11050
    11051
    11052
    11053
    11054
    11055
    11056
    11057
    11058
    11059
    11060
    11061
    11062
    11063
    11064
    11065
    11066
    11067
    11068
    11069
    11070
    11071
    11072
    11073
    11074
    11075
    11076
    11077
    11078
    11079
    11080
    11081
    11082
    11083
    11084
    11085
    11086
    11087
    11088
    11089
    11090
    11091
    11092
    11093
    11094
    11095
    11096
    11097
    11098
    11099
    11100
    11101
    11102
    11103
    11104
    11105
    11106
    11107
    11108
    11109
    11110
    11111
    11112
    11113
    11114
    11115
    11116
    11117
    11118
    11119
    11120
    11121
    11122
    11123
    11124
    11125
    11126
    11127
    11128
    11129
    11130
    11131
    11132
    11133
    11134
    11135
    11136
    11137
    11138
    11139
    11140
    11141
    11142
    11143
    11144
    11145
    11146
    11147
    11148
    11149
    11150
    11151
    11152
    11153
    11154
    11155
    11156
    11157
    11158
    11159
    11160
    11161
    11162
    11163
    11164
    11165
    11166
    11167
    11168
    11169
    11170
    11171
    11172
    11173
    11174
    11175
    11176
    11177
    11178
    11179
    11180
    11181
    11182
    11183
    11184
    11185
    11186
    11187
    11188
    11189
    11190
    11191
    11192
    11193
    11194
    11195
    11196
    11197
    11198
    11199
    11200
    11201
    11202
    11203
    11204
    11205
    11206
    11207
    11208
    11209
    11210
    11211
    11212
    11213
    11214
    11215
    11216
    11217
    11218
    11219
    11220
    11221
    11222
    11223
    11224
    11225
    11226
    11227
    11228
    11229
    11230
    11231
    11232
    11233
    11234
    11235
    11236
    11237
    11238
    11239
    11240
    11241
    11242
    11243
    11244
    11245
    11246
    11247
    11248
    11249
    11250
    11251
    11252
    11253
    11254
    11255
    11256
    11257
    11258
    11259
    11260
    11261
    11262
    11263
    11264
    11265
    11266
    11267
    11268
    11269
    11270
    11271
    11272
    11273
    11274
    11275
    11276
    11277
    11278
    11279
    11280
    11281
    11282
    11283
    11284
    11285
    11286
    11287
    11288
    11289
    11290
    11291
    11292
    11293
    11294
    11295
    11296
    11297
    11298
    11299
    11300
    11301
    11302
    11303
    11304
    11305
    11306
    11307
    11308
    11309
    11310
    11311
    11312
    11313
    11314
    11315
    11316
    11317
    11318
    11319
    11320
    11321
    11322
    11323
    11324
    11325
    11326
    11327
    11328
    11329
    11330
    11331
    11332
    11333
    11334
    11335
    11336
    11337
    11338
    11339
    11340
    11341
    11342
    11343
    11344
    11345
    11346
    11347
    11348
    11349
    11350
    11351
    11352
    11353
    11354
    11355
    11356
    11357
    11358
    11359
    11360
    11361
    11362
    11363
    11364
    11365
    11366
    11367
    11368
    11369
    11370
    11371
    11372
    11373
    11374
    11375
    11376
    11377
    11378
    11379
    11380
    11381
    11382
    11383
    11384
    11385
    11386
    11387
    11388
    11389
    11390
    11391
    11392
    11393
    11394
    11395
    11396
    11397
    11398
    11399
    11400
    11401
    11402
    11403
    11404
    11405
    11406
    11407
    11408
    11409
    11410
    11411
    11412
    11413
    11414
    11415
    11416
    11417
    11418
    11419
    11420
    11421
    11422
    11423
    11424
    11425
    11426
    11427
    11428
    11429
    11430
    11431
    11432
    11433
    11434
    11435
    11436
    11437
    11438
    11439
    11440
    11441
    11442
    11443
    11444
    11445
    11446
    11447
    11448
    11449
    11450
    11451
    11452
    11453
    11454
    11455
    11456
    11457
    11458
    11459
    11460
    11461
    11462
    11463
    11464
    11465
    11466
    11467
    11468
    11469
    11470
    11471
    11472
    11473
    11474
    11475
    11476
    11477
    11478
    11479
    11480
    11481
    11482
    11483
    11484
    11485
    11486
    11487
    11488
    11489
    11490
    11491
    11492
    11493
    11494
    11495
    11496
    11497
    11498
    11499
    11500
    11501
    11502
    11503
    11504
    11505
    11506
    11507
    11508
    11509
    11510
    11511
    11512
    11513
    11514
    11515
    11516
    11517
    11518
    11519
    11520
    11521
    11522
    11523
    11524
    11525
    11526
    11527
    11528
    11529
    11530
    11531
    11532
    11533
    11534
    11535
    11536
    11537
    11538
    11539
    11540
    11541
    11542
    11543
    11544
    11545
    11546
    11547
    11548
    11549
    11550
    11551
    11552
    11553
    11554
    11555
    11556
    11557
    11558
    11559
    11560
    11561
    11562
    11563
    11564
    11565
    11566
    11567
    11568
    11569
    11570
    11571
    11572
    11573
    11574
    11575
    11576
    11577
    11578
    11579
    11580
    11581
    11582
    11583
    11584
    11585
    11586
    11587
    11588
    11589
    11590
    11591
    11592
    11593
    11594
    11595
    11596
    11597
    11598
    11599
    11600
    11601
    11602
    11603
    11604
    11605
    11606
    11607
    11608
    11609
    11610
    11611
    11612
    11613
    11614
    11615
    11616
    11617
    11618
    11619
    11620
    11621
    11622
    11623
    11624
    11625
    11626
    11627
    11628
    11629
    11630
    11631
    11632
    11633
    11634
    11635
    11636
    11637
    11638
    11639
    11640
    11641
    11642
    11643
    11644
    11645
    11646
    11647
    11648
    11649
    11650
    11651
    11652
    11653
    11654
    11655
    11656
    11657
    11658
    11659
    11660
    11661
    11662
    11663
    11664
    11665
    11666
    11667
    11668
    11669
    11670
    11671
    11672
    11673
    11674
    11675
    11676
    11677
    11678
    11679
    11680
    11681
    11682
    11683
    11684
    11685
    11686
    11687
    11688
    11689
    11690
    11691
    11692
    11693
    11694
    11695
    11696
    11697
    11698
    11699
    11700
    11701
    11702
    11703
    11704
    11705
    11706
    11707
    11708
    11709
    11710
    11711
    11712
    11713
    11714
    11715
    11716
    11717
    11718
    11719
    11720
    11721
    11722
    11723
    11724
    11725
    11726
    11727
    11728
    11729
    11730
    11731
    11732
    11733
    11734
    11735
    11736
    11737
    11738
    11739
    11740
    11741
    11742
    11743
    11744
    11745
    11746
    11747
    11748
    11749
    11750
    11751
    11752
    11753
    11754
    11755
    11756
    11757
    11758
    11759
    11760
    11761
    11762
    11763
    11764
    11765
    11766
    11767
    11768
    11769
    11770
    11771
    11772
    11773
    11774
    11775
    11776
    11777
    11778
    11779
    11780
    11781
    11782
    11783
    11784
    11785
    11786
    11787
    11788
    11789
    11790
    11791
    11792
    11793
    11794
    11795
    11796
    11797
    11798
    11799
    11800
    11801
    11802
    11803
    11804
    11805
    11806
    11807
    11808
    11809
    11810
    11811
    11812
    11813
    11814
    11815
    11816
    11817
    11818
    11819
    11820
    11821
    11822
    11823
    11824
    11825
    11826
    11827
    11828
    11829
    11830
    11831
    11832
    11833
    11834
    11835
    11836
    11837
    11838
    11839
    11840
    11841
    11842
    11843
    11844
    11845
    11846
    11847
    11848
    11849
    11850
    11851
    11852
    11853
    11854
    11855
    11856
    11857
    11858
    11859
    11860
    11861
    11862
    11863
    11864
    11865
    11866
    11867
    11868
    11869
    11870
    11871
    11872
    11873
    11874
    11875
    11876
    11877
    11878
    11879
    11880
    11881
    11882
    11883
    11884
    11885
    11886
    11887
    11888
    11889
    11890
    11891
    11892
    11893
    11894
    11895
    11896
    11897
    11898
    11899
    11900
    11901
    11902
    11903
    11904
    11905
    11906
    11907
    11908
    11909
    11910
    11911
    11912
    11913
    11914
    11915
    11916
    11917
    11918
    11919
    11920
    11921
    11922
    11923
    11924
    11925
    11926
    11927
    11928
    11929
    11930
    11931
    11932
    11933
    11934
    11935
    11936
    11937
    11938
    11939
    11940
    11941
    11942
    11943
    11944
    11945
    11946
    11947
    11948
    11949
    11950
    11951
    11952
    11953
    11954
    11955
    11956
    11957
    11958
    11959
    11960
    11961
    11962
    11963
    11964
    11965
    11966
    11967
    11968
    11969
    11970
    11971
    11972
    11973
    11974
    11975
    11976
    11977
    11978
    11979
    11980
    11981
    11982
    11983
    11984
    11985
    11986
    11987
    11988
    11989
    11990
    11991
    11992
    11993
    11994
    11995
    11996
    11997
    11998
    11999
    12000
    12001
    12002
    12003
    12004
    12005
    12006
    12007
    12008
    12009
    12010
    12011
    12012
    12013
    12014
    12015
    12016
    12017
    12018
    12019
    12020
    12021
    12022
    12023
    12024
    12025
    12026
    12027
    12028
    12029
    12030
    12031
    12032
    12033
    12034
    12035
    12036
    12037
    12038
    12039
    12040
    12041
    12042
    12043
    12044
    12045
    12046
    12047
    12048
    12049
    12050
    12051
    12052
    12053
    12054
    12055
    12056
    12057
    12058
    12059
    12060
    12061
    12062
    12063
    12064
    12065
    12066
    12067
    12068
    12069
    12070
    12071
    12072
    12073
    12074
    12075
    12076
    12077
    12078
    12079
    12080
    12081
    12082
    12083
    12084
    12085
    12086
    12087
    12088
    12089
    12090
    12091
    12092
    12093
    12094
    12095
    12096
    12097
    12098
    12099
    12100
    12101
    12102
    12103
    12104
    12105
    12106
    12107
    12108
    12109
    12110
    12111
    12112
    12113
    12114
    12115
    12116
    12117
    12118
    12119
    12120
    12121
    12122
    12123
    12124
    12125
    12126
    12127
    12128
    12129
    12130
    12131
    12132
    12133
    12134
    12135
    12136
    12137
    12138
    12139
    12140
    12141
    12142
    12143
    12144
    12145
    12146
    12147
    12148
    12149
    12150
    12151
    12152
    12153
    12154
    12155
    12156
    12157
    12158
    12159
    12160
    12161
    12162
    12163
    12164
    12165
    12166
    12167
    12168
    12169
    12170
    12171
    12172
    12173
    12174
    12175
    12176
    12177
    12178
    12179
    12180
    12181
    12182
    12183
    12184
    12185
    12186
    12187
    12188
    12189
    12190
    12191
    12192
    12193
    12194
    12195
    12196
    12197
    12198
    12199
    12200
    12201
    12202
    12203
    12204
    12205
    12206
    12207
    12208
    12209
    12210
    12211
    12212
    12213
    12214
    12215
    12216
    12217
    12218
    12219
    12220
    12221
    12222
    12223
    12224
    12225
    12226
    12227
    12228
    12229
    12230
    12231
    12232
    12233
    12234
    12235
    12236
    12237
    12238
    12239
    12240
    12241
    12242
    12243
    12244
    12245
    12246
    12247
    12248
    12249
    12250
    12251
    12252
    12253
    12254
    12255
    12256
    12257
    12258
    12259
    12260
    12261
    12262
    12263
    12264
    12265
    12266
    12267
    12268
    12269
    12270
    12271
    12272
    12273
    12274
    12275
    12276
    12277
    12278
    12279
    12280
    12281
    12282
    12283
    12284
    12285
    12286
    12287
    12288
    12289
    12290
    12291
    12292
    12293
    12294
    12295
    12296
    12297
    12298
    12299
    12300
    12301
    12302
    12303
    12304
    12305
    12306
    12307
    12308
    12309
    12310
    12311
    12312
    12313
    12314
    12315
    12316
    12317
    12318
    12319
    12320
    12321
    12322
    12323
    12324
    12325
    12326
    12327
    12328
    12329
    12330
    12331
    12332
    12333
    12334
    12335
    12336
    12337
    12338
    12339
    12340
    12341
    12342
    12343
    12344
    12345
    12346
    12347
    12348
    12349
    12350
    12351
    12352
    12353
    12354
    12355
    12356
    12357
    12358
    12359
    12360
    12361
    12362
    12363
    12364
    12365
    12366
    12367
    12368
    12369
    12370
    12371
    12372
    12373
    12374
    12375
    12376
    12377
    12378
    12379
    12380
    12381
    12382
    12383
    12384
    12385
    12386
    12387
    12388
    12389
    12390
    12391
    12392
    12393
    12394
    12395
    12396
    12397
    12398
    12399
    12400
    12401
    12402
    12403
    12404
    12405
    12406
    12407
    12408
    12409
    12410
    12411
    12412
    12413
    12414
    12415
    12416
    12417
    12418
    12419
    12420
    12421
    12422
    12423
    12424
    12425
    12426
    12427
    12428
    12429
    12430
    12431
    12432
    12433
    12434
    12435
    12436
    12437
    12438
    12439
    12440
    12441
    12442
    12443
    12444
    12445
    12446
    12447
    12448
    12449
    12450
    12451
    12452
    12453
    12454
    12455
    12456
    12457
    12458
    12459
    12460
    12461
    12462
    12463
    12464
    12465
    12466
    12467
    12468
    12469
    12470
    12471
    12472
    12473
    12474
    12475
    12476
    12477
    12478
    12479
    12480
    12481
    12482
    12483
    12484
    12485
    12486
    12487
    12488
    12489
    12490
    12491
    12492
    12493
    12494
    12495
    12496
    12497
    12498
    12499
    12500
    12501
    12502
    12503
    12504
    12505
    12506
    12507
    12508
    12509
    12510
    12511
    12512
    12513
    12514
    12515
    12516
    12517
    12518
    12519
    12520
    12521
    12522
    12523
    12524
    12525
    12526
    12527
    12528
    12529
    12530
    12531
    12532
    12533
    12534
    12535
    12536
    12537
    12538
    12539
    12540
    12541
    12542
    12543
    12544
    12545
    12546
    12547
    12548
    12549
    12550
    12551
    12552
    12553
    12554
    12555
    12556
    12557
    12558
    12559
    12560
    12561
    12562
    12563
    12564
    12565
    12566
    12567
    12568
    12569
    12570
    12571
    12572
    12573
    12574
    12575
    12576
    12577
    12578
    12579
    12580
    12581
    12582
    12583
    12584
    12585
    12586
    12587
    12588
    12589
    12590
    12591
    12592
    12593
    12594
    12595
    12596
    12597
    12598
    12599
    12600
    12601
    12602
    12603
    12604
    12605
    12606
    12607
    12608
    12609
    12610
    12611
    12612
    12613
    12614
    12615
    12616
    12617
    12618
    12619
    12620
    12621
    12622
    12623
    12624
    12625
    12626
    12627
    12628
    12629
    12630
    12631
    12632
    12633
    12634
    12635
    12636
    12637
    12638
    12639
    12640
    12641
    12642
    12643
    12644
    12645
    12646
    12647
    12648
    12649
    12650
    12651
    12652
    12653
    12654
    12655
    12656
    12657
    12658
    12659
    12660
    12661
    12662
    12663
    12664
    12665
    12666
    12667
    12668
    12669
    12670
    12671
    12672
    12673
    12674
    12675
    12676
    12677
    12678
    12679
    12680
    12681
    12682
    12683
    12684
    12685
    12686
    12687
    12688
    12689
    12690
    12691
    12692
    12693
    12694
    12695
    12696
    12697
    12698
    12699
    12700
    12701
    12702
    12703
    12704
    12705
    12706
    12707
    12708
    12709
    12710
    12711
    12712
    12713
    12714
    12715
    12716
    12717
    12718
    12719
    12720
    12721
    12722
    12723
    12724
    12725
    12726
    12727
    12728
    12729
    12730
    12731
    12732
    12733
    12734
    12735
    12736
    12737
    12738
    12739
    12740
    12741
    12742
    12743
    12744
    12745
    12746
    12747
    12748
    12749
    12750
    12751
    12752
    12753
    12754
    12755
    12756
    12757
    12758
    12759
    12760
    12761
    12762
    12763
    12764
    12765
    12766
    12767
    12768
    12769
    12770
    12771
    12772
    12773
    12774
    12775
    12776
    12777
    12778
    12779
    12780
    12781
    12782
    12783
    12784
    12785
    12786
    12787
    12788
    12789
    12790
    12791
    12792
    12793
    12794
    12795
    12796
    12797
    12798
    12799
    12800
    12801
    12802
    12803
    12804
    12805
    12806
    12807
    12808
    12809
    12810
    12811
    12812
    12813
    12814
    12815
    12816
    12817
    12818
    12819
    12820
    12821
    12822
    12823
    12824
    12825
    12826
    12827
    12828
    12829
    12830
    12831
    12832
    12833
    12834
    12835
    12836
    12837
    12838
    12839
    12840
    12841
    12842
    12843
    12844
    12845
    12846
    12847
    12848
    12849
    12850
    12851
    12852
    12853
    12854
    12855
    12856
    12857
    12858
    12859
    12860
    12861
    12862
    12863
    12864
    12865
    12866
    12867
    12868
    12869
    12870
    12871
    12872
    12873
    12874
    12875
    12876
    12877
    12878
    12879
    12880
    12881
    12882
    12883
    12884
    12885
    12886
    12887
    12888
    12889
    12890
    12891
    12892
    12893
    12894
    12895
    12896
    12897
    12898
    12899
    12900
    12901
    12902
    12903
    12904
    12905
    12906
    12907
    12908
    12909
    12910
    12911
    12912
    12913
    12914
    12915
    12916
    12917
    12918
    12919
    12920
    12921
    12922
    12923
    12924
    12925
    12926
    12927
    12928
    12929
    12930
    12931
    12932
    12933
    12934
    12935
    12936
    12937
    12938
    12939
    12940
    12941
    12942
    12943
    12944
    12945
    12946
    12947
    12948
    12949
    12950
    12951
    12952
    12953
    12954
    12955
    12956
    12957
    12958
    12959
    12960
    12961
    12962
    12963
    12964
    12965
    12966
    12967
    12968
    12969
    12970
    12971
    12972
    12973
    12974
    12975
    12976
    12977
    12978
    12979
    12980
    12981
    12982
    12983
    12984
    12985
    12986
    12987
    12988
    12989
    12990
    12991
    12992
    12993
    12994
    12995
    12996
    12997
    12998
    12999
    13000
    13001
    13002
    13003
    13004
    13005
    13006
    13007
    13008
    13009
    13010
    13011
    13012
    13013
    13014
    13015
    13016
    13017
    13018
    13019
    13020
    13021
    13022
    13023
    13024
    13025
    13026
    13027
    13028
    13029
    13030
    13031
    13032
    13033
    13034
    13035
    13036
    13037
    13038
    13039
    13040
    13041
    13042
    13043
    13044
    13045
    13046
    13047
    13048
    13049
    13050
    13051
    13052
    13053
    13054
    13055
    13056
    13057
    13058
    13059
    13060
    13061
    13062
    13063
    13064
    13065
    13066
    13067
    13068
    13069
    13070
    13071
    13072
    13073
    13074
    13075
    13076
    13077
    13078
    13079
    13080
    13081
    13082
    13083
    13084
    13085
    13086
    13087
    13088
    13089
    13090
    13091
    13092
    13093
    13094
    13095
    13096
    13097
    13098
    13099
    13100
    13101
    13102
    13103
    13104
    13105
    13106
    13107
    13108
    13109
    13110
    13111
    13112
    13113
    13114
    13115
    13116
    13117
    13118
    13119
    13120
    13121
    13122
    13123
    13124
    13125
    13126
    13127
    13128
    13129
    13130
    13131
    13132
    13133
    13134
    13135
    13136
    13137
    13138
    13139
    13140
    13141
    13142
    13143
    13144
    13145
    13146
    13147
    13148
    13149
    13150
    13151
    13152
    13153
    13154
    13155
    13156
    13157
    13158
    13159
    13160
    13161
    13162
    13163
    13164
    13165
    13166
    13167
    13168
    13169
    13170
    13171
    13172
    13173
    13174
    13175
    13176
    13177
    13178
    13179
    13180
    13181
    13182
    13183
    13184
    13185
    13186
    13187
    13188
    13189
    13190
    13191
    13192
    13193
    13194
    13195
    13196
    13197
    13198
    13199
    13200
    13201
    13202
    13203
    13204
    13205
    13206
    13207
    13208
    13209
    13210
    13211
    13212
    13213
    13214
    13215
    13216
    13217
    13218
    13219
    13220
    13221
    13222
    13223
    13224
    13225
    13226
    13227
    13228
    13229
    13230
    13231
    13232
    13233
    13234
    13235
    13236
    13237
    13238
    13239
    13240
    13241
    13242
    13243
    13244
    13245
    13246
    13247
    13248
    13249
    13250
    13251
    13252
    13253
    13254
    13255
    13256
    13257
    13258
    13259
    13260
    13261
    13262
    13263
    13264
    13265
    13266
    13267
    13268
    13269
    13270
    13271
    13272
    13273
    13274
    13275
    13276
    13277
    13278
    13279
    13280
    13281
    13282
    13283
    13284
    13285
    13286
    13287
    13288
    13289
    13290
    13291
    13292
    13293
    13294
    13295
    13296
    13297
    13298
    13299
    13300
    13301
    13302
    13303
    13304
    13305
    13306
    13307
    13308
    13309
    13310
    13311
    13312
    13313
    13314
    13315
    13316
    13317
    13318
    13319
    13320
    13321
    13322
    13323
    13324
    13325
    13326
    13327
    13328
    13329
    13330
    13331
    13332
    13333
    13334
    13335
    13336
    13337
    13338
    13339
    13340
    13341
    13342
    13343
    13344
    13345
    13346
    13347
    13348
    13349
    13350
    13351
    13352
    13353
    13354
    13355
    13356
    13357
    13358
    13359
    13360
    13361
    13362
    13363
    13364
    13365
    13366
    13367
    13368
    13369
    13370
    13371
    13372
    13373
    13374
    13375
    13376
    13377
    13378
    13379
    13380
    13381
    13382
    13383
    13384
    13385
    13386
    13387
    13388
    13389
    13390
    13391
    13392
    13393
    13394
    13395
    13396
    13397
    13398
    13399
    13400
    13401
    13402
    13403
    13404
    13405
    13406
    13407
    13408
    13409
    13410
    13411
    13412
    13413
    13414
    13415
    13416
    13417
    13418
    13419
    13420
    13421
    13422
    13423
    13424
    13425
    13426
    13427
    13428
    13429
    13430
    13431
    13432
    13433
    13434
    13435
    13436
    13437
    13438
    13439
    13440
    13441
    13442
    13443
    13444
    13445
    13446
    13447
    13448
    13449
    13450
    13451
    13452
    13453
    13454
    13455
    13456
    13457
    13458
    13459
    13460
    13461
    13462
    13463
    13464
    13465
    13466
    13467
    13468
    13469
    13470
    13471
    13472
    13473
    13474
    13475
    13476
    13477
    13478
    13479
    13480
    13481
    13482
    13483
    13484
    13485
    13486
    13487
    13488
    13489
    13490
    13491
    13492
    13493
    13494
    13495
    13496
    13497
    13498
    13499
    13500
    13501
    13502
    13503
    13504
    13505
    13506
    13507
    13508
    13509
    13510
    13511
    13512
    13513
    13514
    13515
    13516
    13517
    13518
    13519
    13520
    13521
    13522
    13523
    13524
    13525
    13526
    13527
    13528
    13529
    13530
    13531
    13532
    13533
    13534
    13535
    13536
    13537
    13538
    13539
    13540
    13541
    13542
    13543
    13544
    13545
    13546
    13547
    13548
    13549
    13550
    13551
    13552
    13553
    13554
    13555
    13556
    13557
    13558
    13559
    13560
    13561
    13562
    13563
    13564
    13565
    13566
    13567
    13568
    13569
    13570
    13571
    13572
    13573
    13574
    13575
    13576
    13577
    13578
    13579
    13580
    13581
    13582
    13583
    13584
    13585
    13586
    13587
    13588
    13589
    13590
    13591
    13592
    13593
    13594
    13595
    13596
    13597
    13598
    13599
    13600
    13601
    13602
    13603
    13604
    13605
    13606
    13607
    13608
    13609
    13610
    13611
    13612
    13613
    13614
    13615
    13616
    13617
    13618
    13619
    13620
    13621
    13622
    13623
    13624
    13625
    13626
    13627
    13628
    13629
    13630
    13631
    13632
    13633
    13634
    13635
    13636
    13637
    13638
    13639
    13640
    13641
    13642
    13643
    13644
    13645
    13646
    13647
    13648
    13649
    13650
    13651
    13652
    13653
    13654
    13655
    13656
    13657
    13658
    13659
    13660
    13661
    13662
    13663
    13664
    13665
    13666
    13667
    13668
    13669
    13670
    13671
    13672
    13673
    13674
    13675
    13676
    13677
    13678
    13679
    13680
    13681
    13682
    13683
    13684
    13685
    13686
    13687
    13688
    13689
    13690
    13691
    13692
    13693
    13694
    13695
    13696
    13697
    13698
    13699
    13700
    13701
    13702
    13703
    13704
    13705
    13706
    13707
    13708
    13709
    13710
    13711
    13712
    13713
    13714
    13715
    13716
    13717
    13718
    13719
    13720
    13721
    13722
    13723
    13724
    13725
    13726
    13727
    13728
    13729
    13730
    13731
    13732
    13733
    13734
    13735
    13736
    13737
    13738
    13739
    13740
    13741
    13742
    13743
    13744
    13745
    13746
    13747
    13748
    13749
    13750
    13751
    13752
    13753
    13754
    13755
    13756
    13757
    13758
    13759
    13760
    13761
    13762
    13763
    13764
    13765
    13766
    13767
    13768
    13769
    13770
    13771
    13772
    13773
    13774
    13775
    13776
    13777
    13778
    13779
    13780
    13781
    13782
    13783
    13784
    13785
    13786
    13787
    13788
    13789
    13790
    13791
    13792
    13793
    13794
    13795
    13796
    13797
    13798
    13799
    13800
    13801
    13802
    13803
    13804
    13805
    13806
    13807
    13808
    13809
    13810
    13811
    13812
    13813
    13814
    13815
    13816
    13817
    13818
    13819
    13820
    13821
    13822
    13823
    13824
    13825
    13826
    13827
    13828
    13829
    13830
    13831
    13832
    13833
    13834
    13835
    13836
    13837
    13838
    13839
    13840
    13841
    13842
    13843
    13844
    13845
    13846
    13847
    13848
    13849
    13850
    13851
    13852
    13853
    13854
    13855
    13856
    13857
    13858
    13859
    13860
    13861
    13862
    13863
    13864
    13865
    13866
    13867
    13868
    13869
    13870
    13871
    13872
    13873
    13874
    13875
    13876
    13877
    13878
    13879
    13880
    13881
    13882
    13883
    13884
    13885
    13886
    13887
    13888
    13889
    13890
    13891
    13892
    13893
    13894
    13895
    13896
    13897
    13898
    13899
    13900
    13901
    13902
    13903
    13904
    13905
    13906
    13907
    13908
    13909
    13910
    13911
    13912
    13913
    13914
    13915
    13916
    13917
    13918
    13919
    13920
    13921
    13922
    13923
    13924
    13925
    13926
    13927
    13928
    13929
    13930
    13931
    13932
    13933
    13934
    13935
    13936
    13937
    13938
    13939
    13940
    13941
    13942
    13943
    13944
    13945
    13946
    13947
    13948
    13949
    13950
    13951
    13952
    13953
    13954
    13955
    13956
    13957
    13958
    13959
    13960
    13961
    13962
    13963
    13964
    13965
    13966
    13967
    13968
    13969
    13970
    13971
    13972
    13973
    13974
    13975
    13976
    13977
    13978
    13979
    13980
    13981
    13982
    13983
    13984
    13985
    13986
    13987
    13988
    13989
    13990
    13991
    13992
    13993
    13994
    13995
    13996
    13997
    13998
    13999
    14000
    14001
    14002
    14003
    14004
    14005
    14006
    14007
    14008
    14009
    14010
    14011
    14012
    14013
    14014
    14015
    14016
    14017
    14018
    14019
    14020
    14021
    14022
    14023
    14024
    14025
    14026
    14027
    14028
    14029
    14030
    14031
    14032
    14033
    14034
    14035
    14036
    14037
    14038
    14039
    14040
    14041
    14042
    14043
    14044
    14045
    14046
    14047
    14048
    14049
    14050
    14051
    14052
    14053
    14054
    14055
    14056
    14057
    14058
    14059
    14060
    14061
    14062
    14063
    14064
    14065
    14066
    14067
    14068
    14069
    14070
    14071
    14072
    14073
    14074
    14075
    14076
    14077
    14078
    14079
    14080
    14081
    14082
    14083
    14084
    14085
    14086
    14087
    14088
    14089
    14090
    14091
    14092
    14093
    14094
    14095
    14096
    14097
    14098
    14099
    14100
    14101
    14102
    14103
    14104
    14105
    14106
    14107
    14108
    14109
    14110
    14111
    14112
    14113
    14114
    14115
    14116
    14117
    14118
    14119
    14120
    14121
    14122
    14123
    14124
    14125
    14126
    14127
    14128
    14129
    14130
    14131
    14132
    14133
    14134
    14135
    14136
    14137
    14138
    14139
    14140
    14141
    14142
    14143
    14144
    14145
    14146
    14147
    14148
    14149
    14150
    14151
    14152
    14153
    14154
    14155
    14156
    14157
    14158
    14159
    14160
    14161
    14162
    14163
    14164
    14165
    14166
    14167
    14168
    14169
    14170
    14171
    14172
    14173
    14174
    14175
    14176
    14177
    14178
    14179
    14180
    14181
    14182
    14183
    14184
    14185
    14186
    14187
    14188
    14189
    14190
    14191
    14192
    14193
    14194
    14195
    14196
    14197
    14198
    14199
    14200
    14201
    14202
    14203
    14204
    14205
    14206
    14207
    14208
    14209
    14210
    14211
    14212
    14213
    14214
    14215
    14216
    14217
    14218
    14219
    14220
    14221
    14222
    14223
    14224
    14225
    14226
    14227
    14228
    14229
    14230
    14231
    14232
    14233
    14234
    14235
    14236
    14237
    14238
    14239
    14240
    14241
    14242
    14243
    14244
    14245
    14246
    14247
    14248
    14249
    14250
    14251
    14252
    14253
    14254
    14255
    14256
    14257
    14258
    14259
    14260
    14261
    14262
    14263
    14264
    14265
    14266
    14267
    14268
    14269
    14270
    14271
    14272
    14273
    14274
    14275
    14276
    14277
    14278
    14279
    14280
    14281
    14282
    14283
    14284
    14285
    14286
    14287
    14288
    14289
    14290
    14291
    14292
    14293
    14294
    14295
    14296
    14297
    14298
    14299
    14300
    14301
    14302
    14303
    14304
    14305
    14306
    14307
    14308
    14309
    14310
    14311
    14312
    14313
    14314
    14315
    14316
    14317
    14318
    14319
    14320
    14321
    14322
    14323
    14324
    14325
    14326
    14327
    14328
    14329
    14330
    14331
    14332
    14333
    14334
    14335
    14336
    14337
    14338
    14339
    14340
    14341
    14342
    14343
    14344
    14345
    14346
    14347
    14348
    14349
    14350
    14351
    14352
    14353
    14354
    14355
    14356
    14357
    14358
    14359
    14360
    14361
    14362
    14363
    14364
    14365
    14366
    14367
    14368
    14369
    14370
    14371
    14372
    14373
    14374
    14375
    14376
    14377
    14378
    14379
    14380
    14381
    14382
    14383
    14384
    14385
    14386
    14387
    14388
    14389
    14390
    14391
    14392
    14393
    14394
    14395
    14396
    14397
    14398
    14399
    14400
    14401
    14402
    14403
    14404
    14405
    14406
    14407
    14408
    14409
    14410
    14411
    14412
    14413
    14414
    14415
    14416
    14417
    14418
    14419
    14420
    14421
    14422
    14423
    14424
    14425
    14426
    14427
    14428
    14429
    14430
    14431
    14432
    14433
    14434
    14435
    14436
    14437
    14438
    14439
    14440
    14441
    14442
    14443
    14444
    14445
    14446
    14447
    14448
    14449
    14450
    14451
    14452
    14453
    14454
    14455
    14456
    14457
    14458
    14459
    14460
    14461
    14462
    14463
    14464
    14465
    14466
    14467
    14468
    14469
    14470
    14471
    14472
    14473
    14474
    14475
    14476
    14477
    14478
    14479
    14480
    14481
    14482
    14483
    14484
    14485
    14486
    14487
    14488
    14489
    14490
    14491
    14492
    14493
    14494
    14495
    14496
    14497
    14498
    14499
    14500
    14501
    14502
    14503
    14504
    14505
    14506
    14507
    14508
    14509
    14510
    14511
    14512
    14513
    14514
    14515
    14516
    14517
    14518
    14519
    14520
    14521
    14522
    14523
    14524
    14525
    14526
    14527
    14528
    14529
    14530
    14531
    14532
    14533
    14534
    14535
    14536
    14537
    14538
    14539
    14540
    14541
    14542
    14543
    14544
    14545
    14546
    14547
    14548
    14549
    14550
    14551
    14552
    14553
    14554
    14555
    14556
    14557
    14558
    14559
    14560
    14561
    14562
    14563
    14564
    14565
    14566
    14567
    14568
    14569
    14570
    14571
    14572
    14573
    14574
    14575
    14576
    14577
    14578
    14579
    14580
    14581
    14582
    14583
    14584
    14585
    14586
    14587
    14588
    14589
    14590
    14591
    14592
    14593
    14594
    14595
    14596
    14597
    14598
    14599
    14600
    14601
    14602
    14603
    14604
    14605
    14606
    14607
    14608
    14609
    14610
    14611
    14612
    14613
    14614
    14615
    14616
    14617
    14618
    14619
    14620
    14621
    14622
    14623
    14624
    14625
    14626
    14627
    14628
    14629
    14630
    14631
    14632
    14633
    14634
    14635
    14636
    14637
    14638
    14639
    14640
    14641
    14642
    14643
    14644
    14645
    14646
    14647
    14648
    14649
    14650
    14651
    14652
    14653
    14654
    14655
    14656
    14657
    14658
    14659
    14660
    14661
    14662
    14663
    14664
    14665
    14666
    14667
    14668
    14669
    14670
    14671
    14672
    14673
    14674
    14675
    14676
    14677
    14678
    14679
    14680
    14681
    14682
    14683
    14684
    14685
    14686
    14687
    14688
    14689
    14690
    14691
    14692
    14693
    14694
    14695
    14696
    14697
    14698
    14699
    14700
    14701
    14702
    14703
    14704
    14705
    14706
    14707
    14708
    14709
    14710
    14711
    14712
    14713
    14714
    14715
    14716
    14717
    14718
    14719
    14720
    14721
    14722
    14723
    14724
    14725
    14726
    14727
    14728
    14729
    14730
    14731
    14732
    14733
    14734
    14735
    14736
    14737
    14738
    14739
    14740
    14741
    14742
    14743
    14744
    14745
    14746
    14747
    14748
    14749
    14750
    14751
    14752
    14753
    14754
    14755
    14756
    14757
    14758
    14759
    14760
    14761
    14762
    14763
    14764
    14765
    14766
    14767
    14768
    14769
    14770
    14771
    14772
    14773
    14774
    14775
    14776
    14777
    14778
    14779
    14780
    14781
    14782
    14783
    14784
    14785
    14786
    14787
    14788
    14789
    14790
    14791
    14792
    14793
    14794
    14795
    14796
    14797
    14798
    14799
    14800
    14801
    14802
    14803
    14804
    14805
    14806
    14807
    14808
    14809
    14810
    14811
    14812
    14813
    14814
    14815
    14816
    14817
    14818
    14819
    14820
    14821
    14822
    14823
    14824
    14825
    14826
    14827
    14828
    14829
    14830
    14831
    14832
    14833
    14834
    14835
    14836
    14837
    14838
    14839
    14840
    14841
    14842
    14843
    14844
    14845
    14846
    14847
    14848
    14849
    14850
    14851
    14852
    14853
    14854
    14855
    14856
    14857
    14858
    14859
    14860
    14861
    14862
    14863
    14864
    14865
    14866
    14867
    14868
    14869
    14870
    14871
    14872
    14873
    14874
    14875
    14876
    14877
    14878
    14879
    14880
    14881
    14882
    14883
    14884
    14885
    14886
    14887
    14888
    14889
    14890
    14891
    14892
    14893
    14894
    14895
    14896
    14897
    14898
    14899
    14900
    14901
    14902
    14903
    14904
    14905
    14906
    14907
    14908
    14909
    14910
    14911
    14912
    14913
    14914
    14915
    14916
    14917
    14918
    14919
    14920
    14921
    14922
    14923
    14924
    14925
    14926
    14927
    14928
    14929
    14930
    14931
    14932
    14933
    14934
    14935
    14936
    14937
    14938
    14939
    14940
    14941
    14942
    14943
    14944
    14945
    14946
    14947
    14948
    14949
    14950
    14951
    14952
    14953
    14954
    14955
    14956
    14957
    14958
    14959
    14960
    14961
    14962
    14963
    14964
    14965
    14966
    14967
    14968
    14969
    14970
    14971
    14972
    14973
    14974
    14975
    14976
    14977
    14978
    14979
    14980
    14981
    14982
    14983
    14984
    14985
    14986
    14987
    14988
    14989
    14990
    14991
    14992
    14993
    14994
    14995
    14996
    14997
    14998
    14999
    15000
    15001
    15002
    15003
    15004
    15005
    15006
    15007
    15008
    15009
    15010
    15011
    15012
    15013
    15014
    15015
    15016
    15017
    15018
    15019
    15020
    15021
    15022
    15023
    15024
    15025
    15026
    15027
    15028
    15029
    15030
    15031
    15032
    15033
    15034
    15035
    15036
    15037
    15038
    15039
    15040
    15041
    15042
    15043
    15044
    15045
    15046
    15047
    15048
    15049
    15050
    15051
    15052
    15053
    15054
    15055
    15056
    15057
    15058
    15059
    15060
    15061
    15062
    15063
    15064
    15065
    15066
    15067
    15068
    15069
    15070
    15071
    15072
    15073
    15074
    15075
    15076
    15077
    15078
    15079
    15080
    15081
    15082
    15083
    15084
    15085
    15086
    15087
    15088
    15089
    15090
    15091
    15092
    15093
    15094
    15095
    15096
    15097
    15098
    15099
    15100
    15101
    15102
    15103
    15104
    15105
    15106
    15107
    15108
    15109
    15110
    15111
    15112
    15113
    15114
    15115
    15116
    15117
    15118
    15119
    15120
    15121
    15122
    15123
    15124
    15125
    15126
    15127
    15128
    15129
    15130
    15131
    15132
    15133
    15134
    15135
    15136
    15137
    15138
    15139
    15140
    15141
    15142
    15143
    15144
    15145
    15146
    15147
    15148
    15149
    15150
    15151
    15152
    15153
    15154
    15155
    15156
    15157
    15158
    15159
    15160
    15161
    15162
    15163
    15164
    15165
    15166
    15167
    15168
    15169
    15170
    15171
    15172
    15173
    15174
    15175
    15176
    15177
    15178
    15179
    15180
    15181
    15182
    15183
    15184
    15185
    15186
    15187
    15188
    15189
    15190
    15191
    15192
    15193
    15194
    15195
    15196
    15197
    15198
    15199
    15200
    15201
    15202
    15203
    15204
    15205
    15206
    15207
    15208
    15209
    15210
    15211
    15212
    15213
    15214
    15215
    15216
    15217
    15218
    15219
    15220
    15221
    15222
    15223
    15224
    15225
    15226
    15227
    15228
    15229
    15230
    15231
    15232
    15233
    15234
    15235
    15236
    15237
    15238
    15239
    15240
    15241
    15242
    15243
    15244
    15245
    15246
    15247
    15248
    15249
    15250
    15251
    15252
    15253
    15254
    15255
    15256
    15257
    15258
    15259
    15260
    15261
    15262
    15263
    15264
    15265
    15266
    15267
    15268
    15269
    15270
    15271
    15272
    15273
    15274
    15275
    15276
    15277
    15278
    15279
    15280
    15281
    15282
    15283
    15284
    15285
    15286
    15287
    15288
    15289
    15290
    15291
    15292
    15293
    15294
    15295
    15296
    15297
    15298
    15299
    15300
    15301
    15302
    15303
    15304
    15305
    15306
    15307
    15308
    15309
    15310
    15311
    15312
    15313
    15314
    15315
    15316
    15317
    15318
    15319
    15320
    15321
    15322
    15323
    15324
    15325
    15326
    15327
    15328
    15329
    15330
    15331
    15332
    15333
    15334
    15335
    15336
    15337
    15338
    15339
    15340
    15341
    15342
    15343
    15344
    15345
    15346
    15347
    15348
    15349
    15350
    15351
    15352
    15353
    15354
    15355
    15356
    15357
    15358
    15359
    15360
    15361
    15362
    15363
    15364
    15365
    15366
    15367
    15368
    15369
    15370
    15371
    15372
    15373
    15374
    15375
    15376
    15377
    15378
    15379
    15380
    15381
    15382
    15383
    15384
    15385
    15386
    15387
    15388
    15389
    15390
    15391
    15392
    15393
    15394
    15395
    15396
    15397
    15398
    15399
    15400
    15401
    15402
    15403
    15404
    15405
    15406
    15407
    15408
    15409
    15410
    15411
    15412
    15413
    15414
    15415
    15416
    15417
    15418
    15419
    15420
    15421
    15422
    15423
    15424
    15425
    15426
    15427
    15428
    15429
    15430
    15431
    15432
    15433
    15434
    15435
    15436
    15437
    15438
    15439
    15440
    15441
    15442
    15443
    15444
    15445
    15446
    15447
    15448
    15449
    15450
    15451
    15452
    15453
    15454
    15455
    15456
    15457
    15458
    15459
    15460
    15461
    15462
    15463
    15464
    15465
    15466
    15467
    15468
    15469
    15470
    15471
    15472
    15473
    15474
    15475
    15476
    15477
    15478
    15479
    15480
    15481
    15482
    15483
    15484
    15485
    15486
    15487
    15488
    15489
    15490
    15491
    15492
    15493
    15494
    15495
    15496
    15497
    15498
    15499
    15500
    15501
    15502
    15503
    15504
    15505
    15506
    15507
    15508
    15509
    15510
    15511
    15512
    15513
    15514
    15515
    15516
    15517
    15518
    15519
    15520
    15521
    15522
    15523
    15524
    15525
    15526
    15527
    15528
    15529
    15530
    15531
    15532
    15533
    15534
    15535
    15536
    15537
    15538
    15539
    15540
    15541
    15542
    15543
    15544
    15545
    15546
    15547
    15548
    15549
    15550
    15551
    15552
    15553
    15554
    15555
    15556
    15557
    15558
    15559
    15560
    15561
    15562
    15563
    15564
    15565
    15566
    15567
    15568
    15569
    15570
    15571
    15572
    15573
    15574
    15575
    15576
    15577
    15578
    15579
    15580
    15581
    15582
    15583
    15584
    15585
    15586
    15587
    15588
    15589
    15590
    15591
    15592
    15593
    15594
    15595
    15596
    15597
    15598
    15599
    15600
    15601
    15602
    15603
    15604
    15605
    15606
    15607
    15608
    15609
    15610
    15611
    15612
    15613
    15614
    15615
    15616
    15617
    15618
    15619
    15620
    15621
    15622
    15623
    15624
    15625
    15626
    15627
    15628
    15629
    15630
    15631
    15632
    15633
    15634
    15635
    15636
    15637
    15638
    15639
    15640
    15641
    15642
    15643
    15644
    15645
    15646
    15647
    15648
    15649
    15650
    15651
    15652
    15653
    15654
    15655
    15656
    15657
    15658
    15659
    15660
    15661
    15662
    15663
    15664
    15665
    15666
    15667
    15668
    15669
    15670
    15671
    15672
    15673
    15674
    15675
    15676
    15677
    15678
    15679
    15680
    15681
    15682
    15683
    15684
    15685
    15686
    15687
    15688
    15689
    15690
    15691
    15692
    15693
    15694
    15695
    15696
    15697
    15698
    15699
    15700
    15701
    15702
    15703
    15704
    15705
    15706
    15707
    15708
    15709
    15710
    15711
    15712
    15713
    15714
    15715
    15716
    15717
    15718
    15719
    15720
    15721
    15722
    15723
    15724
    15725
    15726
    15727
    15728
    15729
    15730
    15731
    15732
    15733
    15734
    15735
    15736
    15737
    15738
    15739
    15740
    15741
    15742
    15743
    15744
    15745
    15746
    15747
    15748
    15749
    15750
    15751
    15752
    15753
    15754
    15755
    15756
    15757
    15758
    15759
    15760
    15761
    15762
    15763
    15764
    15765
    15766
    15767
    15768
    15769
    15770
    15771
    15772
    15773
    15774
    15775
    15776
    15777
    15778
    15779
    15780
    15781
    15782
    15783
    15784
    15785
    15786
    15787
    15788
    15789
    15790
    15791
    15792
    15793
    15794
    15795
    15796
    15797
    15798
    15799
    15800
    15801
    15802
    15803
    15804
    15805
    15806
    15807
    15808
    15809
    15810
    15811
    15812
    15813
    15814
    15815
    15816
    15817
    15818
    15819
    15820
    15821
    15822
    15823
    15824
    15825
    15826
    15827
    15828
    15829
    15830
    15831
    15832
    15833
    15834
    15835
    15836
    15837
    15838
    15839
    15840
    15841
    15842
    15843
    15844
    15845
    15846
    15847
    15848
    15849
    15850
    15851
    15852
    15853
    15854
    15855
    15856
    15857
    15858
    15859
    15860
    15861
    15862
    15863
    15864
    15865
    15866
    15867
    15868
    15869
    15870
    15871
    15872
    15873
    15874
    15875
    15876
    15877
    15878
    15879
    15880
    15881
    15882
    15883
    15884
    15885
    15886
    15887
    15888
    15889
    15890
    15891
    15892
    15893
    15894
    15895
    15896
    15897
    15898
    15899
    15900
    15901
    15902
    15903
    15904
    15905
    15906
    15907
    15908
    15909
    15910
    15911
    15912
    15913
    15914
    15915
    15916
    15917
    15918
    15919
    15920
    15921
    15922
    15923
    15924
    15925
    15926
    15927
    15928
    15929
    15930
    15931
    15932
    15933
    15934
    15935
    15936
    15937
    15938
    15939
    15940
    15941
    15942
    15943
    15944
    15945
    15946
    15947
    15948
    15949
    15950
    15951
    15952
    15953
    15954
    15955
    15956
    15957
    15958
    15959
    15960
    15961
    15962
    15963
    15964
    15965
    15966
    15967
    15968
    15969
    15970
    15971
    15972
    15973
    15974
    15975
    15976
    15977
    15978
    15979
    15980
    15981
    15982
    15983
    15984
    15985
    15986
    15987
    15988
    15989
    15990
    15991
    15992
    15993
    15994
    15995
    15996
    15997
    15998
    15999
    16000
    16001
    16002
    16003
    16004
    16005
    16006
    16007
    16008
    16009
    16010
    16011
    16012
    16013
    16014
    16015
    16016
    16017
    16018
    16019
    16020
    16021
    16022
    16023
    16024
    16025
    16026
    16027
    16028
    16029
    16030
    16031
    16032
    16033
    16034
    16035
    16036
    16037
    16038
    16039
    16040
    16041
    16042
    16043
    16044
    16045
    16046
    16047
    16048
    16049
    16050
    16051
    16052
    16053
    16054
    16055
    16056
    16057
    16058
    16059
    16060
    16061
    16062
    16063
    16064
    16065
    16066
    16067
    16068
    16069
    16070
    16071
    16072
    16073
    16074
    16075
    16076
    16077
    16078
    16079
    16080
    16081
    16082
    16083
    16084
    16085
    16086
    16087
    16088
    16089
    16090
    16091
    16092
    16093
    16094
    16095
    16096
    16097
    16098
    16099
    16100
    16101
    16102
    16103
    16104
    16105
    16106
    16107
    16108
    16109
    16110
    16111
    16112
    16113
    16114
    16115
    16116
    16117
    16118
    16119
    16120
    16121
    16122
    16123
    16124
    16125
    16126
    16127
    16128
    16129
    16130
    16131
    16132
    16133
    16134
    16135
    16136
    16137
    16138
    16139
    16140
    16141
    16142
    16143
    16144
    16145
    16146
    16147
    16148
    16149
    16150
    16151
    16152
    16153
    16154
    16155
    16156
    16157
    16158
    16159
    16160
    16161
    16162
    16163
    16164
    16165
    16166
    16167
    16168
    16169
    16170
    16171
    16172
    16173
    16174
    16175
    16176
    16177
    16178
    16179
    16180
    16181
    16182
    16183
    16184
    16185
    16186
    16187
    16188
    16189
    16190
    16191
    16192
    16193
    16194
    16195
    16196
    16197
    16198
    16199
    16200
    16201
    16202
    16203
    16204
    16205
    16206
    16207
    16208
    16209
    16210
    16211
    16212
    16213
    16214
    16215
    16216
    16217
    16218
    16219
    16220
    16221
    16222
    16223
    16224
    16225
    16226
    16227
    16228
    16229
    16230
    16231
    16232
    16233
    16234
    16235
    16236
    16237
    16238
    16239
    16240
    16241
    16242
    16243
    16244
    16245
    16246
    16247
    16248
    16249
    16250
    16251
    16252
    16253
    16254
    16255
    16256
    16257
    16258
    16259
    16260
    16261
    16262
    16263
    16264
    16265
    16266
    16267
    16268
    16269
    16270
    16271
    16272
    16273
    16274
    16275
    16276
    16277
    16278
    16279
    16280
    16281
    16282
    16283
    16284
    16285
    16286
    16287
    16288
    16289
    16290
    16291
    16292
    16293
    16294
    16295
    16296
    16297
    16298
    16299
    16300
    16301
    16302
    16303
    16304
    16305
    16306
    16307
    16308
    16309
    16310
    16311
    16312
    16313
    16314
    16315
    16316
    16317
    16318
    16319
    16320
    16321
    16322
    16323
    16324
    16325
    16326
    16327
    16328
    16329
    16330
    16331
    16332
    16333
    16334
    16335
    16336
    16337
    16338
    16339
    16340
    16341
    16342
    16343
    16344
    16345
    16346
    16347
    16348
    16349
    16350
    16351
    16352
    16353
    16354
    16355
    16356
    16357
    16358
    16359
    16360
    16361
    16362
    16363
    16364
    16365
    16366
    16367
    16368
    16369
    16370
    16371
    16372
    16373
    16374
    16375
    16376
    16377
    16378
    16379
    16380
    16381
    16382
    16383
    16384
    16385
    16386
    16387
    16388
    16389
    16390
    16391
    16392
    16393
    16394
    16395
    16396
    16397
    16398
    16399
    16400
    16401
    16402
    16403
    16404
    16405
    16406
    16407
    16408
    16409
    16410
    16411
    16412
    16413
    16414
    16415
    16416
    16417
    16418
    16419
    16420
    16421
    16422
    16423
    16424
    16425
    16426
    16427
    16428
    16429
    16430
    16431
    16432
    16433
    16434
    16435
    16436
    16437
    16438
    16439
    16440
    16441
    16442
    16443
    16444
    16445
    16446
    16447
    16448
    16449
    16450
    16451
    16452
    16453
    16454
    16455
    16456
    16457
    16458
    16459
    16460
    16461
    16462
    16463
    16464
    16465
    16466
    16467
    16468
    16469
    16470
    16471
    16472
    16473
    16474
    16475
    16476
    16477
    16478
    16479
    16480
    16481
    16482
    16483
    16484
    16485
    16486
    16487
    16488
    16489
    16490
    16491
    16492
    16493
    16494
    16495
    16496
    16497
    16498
    16499
    16500
    16501
    16502
    16503
    16504
    16505
    16506
    16507
    16508
    16509
    16510
    16511
    16512
    16513
    16514
    16515
    16516
    16517
    16518
    16519
    16520
    16521
    16522
    16523
    16524
    16525
    16526
    16527
    16528
    16529
    16530
    16531
    16532
    16533
    16534
    16535
    16536
    16537
    16538
    16539
    16540
    16541
    16542
    16543
    16544
    16545
    16546
    16547
    16548
    16549
    16550
    16551
    16552
    16553
    16554
    16555
    16556
    16557
    16558
    16559
    16560
    16561
    16562
    16563
    16564
    16565
    16566
    16567
    16568
    16569
    16570
    16571
    16572
    16573
    16574
    16575
    16576
    16577
    16578
    16579
    16580
    16581
    16582
    16583
    16584
    16585
    16586
    16587
    16588
    16589
    16590
    16591
    16592
    16593
    16594
    16595
    16596
    16597
    16598
    16599
    16600
    16601
    16602
    16603
    16604
    16605
    16606
    16607
    16608
    16609
    16610
    16611
    16612
    16613
    16614
    16615
    16616
    16617
    16618
    16619
    16620
    16621
    16622
    16623
    16624
    16625
    16626
    16627
    16628
    16629
    16630
    16631
    16632
    16633
    16634
    16635
    16636
    16637
    16638
    16639
    16640
    16641
    16642
    16643
    16644
    16645
    16646
    16647
    16648
    16649
    16650
    16651
    16652
    16653
    16654
    16655
    16656
    16657
    16658
    16659
    16660
    16661
    16662
    16663
    16664
    16665
    16666
    16667
    16668
    16669
    16670
    16671
    16672
    16673
    16674
    16675
    16676
    16677
    16678
    16679
    16680
    16681
    16682
    16683
    16684
    16685
    16686
    16687
    16688
    16689
    16690
    16691
    16692
    16693
    16694
    16695
    16696
    16697
    16698
    16699
    16700
    16701
    16702
    16703
    16704
    16705
    16706
    16707
    16708
    16709
    16710
    16711
    16712
    16713
    16714
    16715
    16716
    16717
    16718
    16719
    16720
    16721
    16722
    16723
    16724
    16725
    16726
    16727
    16728
    16729
    16730
    16731
    16732
    16733
    16734
    16735
    16736
    16737
    16738
    16739
    16740
    16741
    16742
    16743
    16744
    16745
    16746
    16747
    16748
    16749
    16750
    16751
    16752
    16753
    16754
    16755
    16756
    16757
    16758
    16759
    16760
    16761
    16762
    16763
    16764
    16765
    16766
    16767
    16768
    16769
    16770
    16771
    16772
    16773
    16774
    16775
    16776
    16777
    16778
    16779
    16780
    16781
    16782
    16783
    16784
    16785
    16786
    16787
    16788
    16789
    16790
    16791
    16792
    16793
    16794
    16795
    16796
    16797
    16798
    16799
    16800
    16801
    16802
    16803
    16804
    16805
    16806
    16807
    16808
    16809
    16810
    16811
    16812
    16813
    16814
    16815
    16816
    16817
    16818
    16819
    16820
    16821
    16822
    16823
    16824
    16825
    16826
    16827
    16828
    16829
    16830
    16831
    16832
    16833
    16834
    16835
    16836
    16837
    16838
    16839
    16840
    16841
    16842
    16843
    16844
    16845
    16846
    16847
    16848
    16849
    16850
    16851
    16852
    16853
    16854
    16855
    16856
    16857
    16858
    16859
    16860
    16861
    16862
    16863
    16864
    16865
    16866
    16867
    16868
    16869
    16870
    16871
    16872
    16873
    16874
    16875
    16876
    16877
    16878
    16879
    16880
    16881
    16882
    16883
    16884
    16885
    16886
    16887
    16888
    16889
    16890
    16891
    16892
    16893
    16894
    16895
    16896
    16897
    16898
    16899
    16900
    16901
    16902
    16903
    16904
    16905
    16906
    16907
    16908
    16909
    16910
    16911
    16912
    16913
    16914
    16915
    16916
    16917
    16918
    16919
    16920
    16921
    16922
    16923
    16924
    16925
    16926
    16927
    16928
    16929
    16930
    16931
    16932
    16933
    16934
    16935
    16936
    16937
    16938
    16939
    16940
    16941
    16942
    16943
    16944
    16945
    16946
    16947
    16948
    16949
    16950
    16951
    16952
    16953
    16954
    16955
    16956
    16957
    16958
    16959
    16960
    16961
    16962
    16963
    16964
    16965
    16966
    16967
    16968
    16969
    16970
    16971
    16972
    16973
    16974
    16975
    16976
    16977
    16978
    16979
    16980
    16981
    16982
    16983
    16984
    16985
    16986
    16987
    16988
    16989
    16990
    16991
    16992
    16993
    16994
    16995
    16996
    16997
    16998
    16999
    17000
    17001
    17002
    17003
    17004
    17005
    17006
    17007
    17008
    17009
    17010
    17011
    17012
    17013
    17014
    17015
    17016
    17017
    17018
    17019
    17020
    17021
    17022
    17023
    17024
    17025
    17026
    17027
    17028
    17029
    17030
    17031
    17032
    17033
    17034
    17035
    17036
    17037
    17038
    17039
    17040
    17041
    17042
    17043
    17044
    17045
    17046
    17047
    17048
    17049
    17050
    17051
    17052
    17053
    17054
    17055
    17056
    17057
    17058
    17059
    17060
    17061
    17062
    17063
    17064
    17065
    17066
    17067
    17068
    17069
    17070
    17071
    17072
    17073
    17074
    17075
    17076
    17077
    17078
    17079
    17080
    17081
    17082
    17083
    17084
    17085
    17086
    17087
    17088
    17089
    17090
    17091
    17092
    17093
    17094
    17095
    17096
    17097
    17098
    17099
    17100
    17101
    17102
    17103
    17104
    17105
    17106
    17107
    17108
    17109
    17110
    17111
    17112
    17113
    17114
    17115
    17116
    17117
    17118
    17119
    17120
    17121
    17122
    17123
    17124
    17125
    17126
    17127
    17128
    17129
    17130
    17131
    17132
    17133
    17134
    17135
    17136
    17137
    17138
    17139
    17140
    17141
    17142
    17143
    17144
    17145
    17146
    17147
    17148
    17149
    17150
    17151
    17152
    17153
    17154
    17155
    17156
    17157
    17158
    17159
    17160
    17161
    17162
    17163
    17164
    17165
    17166
    17167
    17168
    17169
    17170
    17171
    17172
    17173
    17174
    17175
    17176
    17177
    17178
    17179
    17180
    17181
    17182
    17183
    17184
    17185
    17186
    17187
    17188
    17189
    17190
    17191
    17192
    17193
    17194
    17195
    17196
    17197
    17198
    17199
    17200
    17201
    17202
    17203
    17204
    17205
    17206
    17207
    17208
    17209
    17210
    17211
    17212
    17213
    17214
    17215
    17216
    17217
    17218
    17219
    17220
    17221
    17222
    17223
    17224
    17225
    17226
    17227
    17228
    17229
    17230
    17231
    17232
    17233
    17234
    17235
    17236
    17237
    17238
    17239
    17240
    17241
    17242
    17243
    17244
    17245
    17246
    17247
    17248
    17249
    17250
    17251
    17252
    17253
    17254
    17255
    17256
    17257
    17258
    17259
    17260
    17261
    17262
    17263
    17264
    17265
    17266
    17267
    17268
    17269
    17270
    17271
    17272
    17273
    17274
    17275
    17276
    17277
    17278
    17279
    17280
    17281
    17282
    17283
    17284
    17285
    17286
    17287
    17288
    17289
    17290
    17291
    17292
    17293
    17294
    17295
    17296
    17297
    17298
    17299
    17300
    17301
    17302
    17303
    17304
    17305
    17306
    17307
    17308
    17309
    17310
    17311
    17312
    17313
    17314
    17315
    17316
    17317
    17318
    17319
    17320
    17321
    17322
    17323
    17324
    17325
    17326
    17327
    17328
    17329
    17330
    17331
    17332
    17333
    17334
    17335
    17336
    17337
    17338
    17339
    17340
    17341
    17342
    17343
    17344
    17345
    17346
    17347
    17348
    17349
    17350
    17351
    17352
    17353
    17354
    17355
    17356
    17357
    17358
    17359
    17360
    17361
    17362
    17363
    17364
    17365
    17366
    17367
    17368
    17369
    17370
    17371
    17372
    17373
    17374
    17375
    17376
    17377
    17378
    17379
    17380
    17381
    17382
    17383
    17384
    17385
    17386
    17387
    17388
    17389
    17390
    17391
    17392
    17393
    17394
    17395
    17396
    17397
    17398
    17399
    17400
    17401
    17402
    17403
    17404
    17405
    17406
    17407
    17408
    17409
    17410
    17411
    17412
    17413
    17414
    17415
    17416
    17417
    17418
    17419
    17420
    17421
    17422
    17423
    17424
    17425
    17426
    17427
    17428
    17429
    17430
    17431
    17432
    17433
    17434
    17435
    17436
    17437
    17438
    17439
    17440
    17441
    17442
    17443
    17444
    17445
    17446
    17447
    17448
    17449
    17450
    17451
    17452
    17453
    17454
    17455
    17456
    17457
    17458
    17459
    17460
    17461
    17462
    17463
    17464
    17465
    17466
    17467
    17468
    17469
    17470
    17471
    17472
    17473
    17474
    17475
    17476
    17477
    17478
    17479
    17480
    17481
    17482
    17483
    17484
    17485
    17486
    17487
    17488
    17489
    17490
    17491
    17492
    17493
    17494
    17495
    17496
    17497
    17498
    17499
    17500
    17501
    17502
    17503
    17504
    17505
    17506
    17507
    17508
    17509
    17510
    17511
    17512
    17513
    17514
    17515
    17516
    17517
    17518
    17519
    17520
    17521
    17522
    17523
    17524
    17525
    17526
    17527
    17528
    17529
    17530
    17531
    17532
    17533
    17534
    17535
    17536
    17537
    17538
    17539
    17540
    17541
    17542
    17543
    17544
    17545
    17546
    17547
    17548
    17549
    17550
    17551
    17552
    17553
    17554
    17555
    17556
    17557
    17558
    17559
    17560
    17561
    17562
    17563
    17564
    17565
    17566
    17567
    17568
    17569
    17570
    17571
    17572
    17573
    17574
    17575
    17576
    17577
    17578
    17579
    17580
    17581
    17582
    17583
    17584
    17585
    17586
    17587
    17588
    17589
    17590
    17591
    17592
    17593
    17594
    17595
    17596
    17597
    17598
    17599
    17600
    17601
    17602
    17603
    17604
    17605
    17606
    17607
    17608
    17609
    17610
    17611
    17612
    17613
    17614
    17615
    17616
    17617
    17618
    17619
    17620
    17621
    17622
    17623
    17624
    17625
    17626
    17627
    17628
    17629
    17630
    17631
    17632
    17633
    17634
    17635
    17636
    17637
    17638
    17639
    17640
    17641
    17642
    17643
    17644
    17645
    17646
    17647
    17648
    17649
    17650
    17651
    17652
    17653
    17654
    17655
    17656
    17657
    17658
    17659
    17660
    17661
    17662
    17663
    17664
    17665
    17666
    17667
    17668
    17669
    17670
    17671
    17672
    17673
    17674
    17675
    17676
    17677
    17678
    17679
    17680
    17681
    17682
    17683
    17684
    17685
    17686
    17687
    17688
    17689
    17690
    17691
    17692
    17693
    17694
    17695
    17696
    17697
    17698
    17699
    17700
    17701
    17702
    17703
    17704
    17705
    17706
    17707
    17708
    17709
    17710
    17711
    17712
    17713
    17714
    17715
    17716
    17717
    17718
    17719
    17720
    17721
    17722
    17723
    17724
    17725
    17726
    17727
    17728
    17729
    17730
    17731
    17732
    17733
    17734
    17735
    17736
    17737
    17738
    17739
    17740
    17741
    17742
    17743
    17744
    17745
    17746
    17747
    17748
    17749
    17750
    17751
    17752
    17753
    17754
    17755
    17756
    17757
    17758
    17759
    17760
    17761
    17762
    17763
    17764
    17765
    17766
    17767
    17768
    17769
    17770
    17771
    17772
    17773
    17774
    17775
    17776
    17777
    17778
    17779
    17780
    17781
    17782
    17783
    17784
    17785
    17786
    17787
    17788
    17789
    17790
    17791
    17792
    17793
    17794
    17795
    17796
    17797
    17798
    17799
    17800
    17801
    17802
    17803
    17804
    17805
    17806
    17807
    17808
    17809
    17810
    17811
    17812
    17813
    17814
    17815
    17816
    17817
    17818
    17819
    17820
    17821
    17822
    17823
    17824
    17825
    17826
    17827
    17828
    17829
    17830
    17831
    17832
    17833
    17834
    17835
    17836
    17837
    17838
    17839
    17840
    17841
    17842
    17843
    17844
    17845
    17846
    17847
    17848
    17849
    17850
    17851
    17852
    17853
    17854
    17855
    17856
    17857
    17858
    17859
    17860
    17861
    17862
    17863
    17864
    17865
    17866
    17867
    17868
    17869
    17870
    17871
    17872
    17873
    17874
    17875
    17876
    17877
    17878
    17879
    17880
    17881
    17882
    17883
    17884
    17885
    17886
    17887
    17888
    17889
    17890
    17891
    17892
    17893
    17894
    17895
    17896
    17897
    17898
    17899
    17900
    17901
    17902
    17903
    17904
    17905
    17906
    17907
    17908
    17909
    17910
    17911
    17912
    17913
    17914
    17915
    17916
    17917
    17918
    17919
    17920
    17921
    17922
    17923
    17924
    17925
    17926
    17927
    17928
    17929
    17930
    17931
    17932
    17933
    17934
    17935
    17936
    17937
    17938
    17939
    17940
    17941
    17942
    17943
    17944
    17945
    17946
    17947
    17948
    17949
    17950
    17951
    17952
    17953
    17954
    17955
    17956
    17957
    17958
    17959
    17960
    17961
    17962
    17963
    17964
    17965
    17966
    17967
    17968
    17969
    17970
    17971
    17972
    17973
    17974
    17975
    17976
    17977
    17978
    17979
    17980
    17981
    17982
    17983
    17984
    17985
    17986
    17987
    17988
    17989
    17990
    17991
    17992
    17993
    17994
    17995
    17996
    17997
    17998
    17999
    18000
    18001
    18002
    18003
    18004
    18005
    18006
    18007
    18008
    18009
    18010
    18011
    18012
    18013
    18014
    18015
    18016
    18017
    18018
    18019
    18020
    18021
    18022
    18023
    18024
    18025
    18026
    18027
    18028
    18029
    18030
    18031
    18032
    18033
    18034
    18035
    18036
    18037
    18038
    18039
    18040
    18041
    18042
    18043
    18044
    18045
    18046
    18047
    18048
    18049
    18050
    18051
    18052
    18053
    18054
    18055
    18056
    18057
    18058
    18059
    18060
    18061
    18062
    18063
    18064
    18065
    18066
    18067
    18068
    18069
    18070
    18071
    18072
    18073
    18074
    18075
    18076
    18077
    18078
    18079
    18080
    18081
    18082
    18083
    18084
    18085
    18086
    18087
    18088
    18089
    18090
    18091
    18092
    18093
    18094
    18095
    18096
    18097
    18098
    18099
    18100
    18101
    18102
    18103
    18104
    18105
    18106
    18107
    18108
    18109
    18110
    18111
    18112
    18113
    18114
    18115
    18116
    18117
    18118
    18119
    18120
    18121
    18122
    18123
    18124
    18125
    18126
    18127
    18128
    18129
    18130
    18131
    18132
    18133
    18134
    18135
    18136
    18137
    18138
    18139
    18140
    18141
    18142
    18143
    18144
    18145
    18146
    18147
    18148
    18149
    18150
    18151
    18152
    18153
    18154
    18155
    18156
    18157
    18158
    18159
    18160
    18161
    18162
    18163
    18164
    18165
    18166
    18167
    18168
    18169
    18170
    18171
    18172
    18173
    18174
    18175
    18176
    18177
    18178
    18179
    18180
    18181
    18182
    18183
    18184
    18185
    18186
    18187
    18188
    18189
    18190
    18191
    18192
    18193
    18194
    18195
    18196
    18197
    18198
    18199
    18200
    18201
    18202
    18203
    18204
    18205
    18206
    18207
    18208
    18209
    18210
    18211
    18212
    18213
    18214
    18215
    18216
    18217
    18218
    18219
    18220
    18221
    18222
    18223
    18224
    18225
    18226
    18227
    18228
    18229
    18230
    18231
    18232
    18233
    18234
    18235
    18236
    18237
    18238
    18239
    18240
    18241
    18242
    18243
    18244
    18245
    18246
    18247
    18248
    18249
    18250
    18251
    18252
    18253
    18254
    18255
    18256
    18257
    18258
    18259
    18260
    18261
    18262
    18263
    18264
    18265
    18266
    18267
    18268
    18269
    18270
    18271
    18272
    18273
    18274
    18275
    18276
    18277
    18278
    18279
    18280
    18281
    18282
    18283
    18284
    18285
    18286
    18287
    18288
    18289
    18290
    18291
    18292
    18293
    18294
    18295
    18296
    18297
    18298
    18299
    18300
    18301
    18302
    18303
    18304
    18305
    18306
    18307
    18308
    18309
    18310
    18311
    18312
    18313
    18314
    18315
    18316
    18317
    18318
    18319
    18320
    18321
    18322
    18323
    18324
    18325
    18326
    18327
    18328
    18329
    18330
    18331
    18332
    18333
    18334
    18335
    18336
    18337
    18338
    18339
    18340
    18341
    18342
    18343
    18344
    18345
    18346
    18347
    18348
    18349
    18350
    18351
    18352
    18353
    18354
    18355
    18356
    18357
    18358
    18359
    18360
    18361
    18362
    18363
    18364
    18365
    18366
    18367
    18368
    18369
    18370
    18371
    18372
    18373
    18374
    18375
    18376
    18377
    18378
    18379
    18380
    18381
    18382
    18383
    18384
    18385
    18386
    18387
    18388
    18389
    18390
    18391
    18392
    18393
    18394
    18395
    18396
    18397
    18398
    18399
    18400
    18401
    18402
    18403
    18404
    18405
    18406
    18407
    18408
    18409
    18410
    18411
    18412
    18413
    18414
    18415
    18416
    18417
    18418
    18419
    18420
    18421
    18422
    18423
    18424
    18425
    18426
    18427
    18428
    18429
    18430
    18431
    18432
    18433
    18434
    18435
    18436
    18437
    18438
    18439
    18440
    18441
    18442
    18443
    18444
    18445
    18446
    18447
    18448
    18449
    18450
    18451
    18452
    18453
    18454
    18455
    18456
    18457
    18458
    18459
    18460
    18461
    18462
    18463
    18464
    18465
    18466
    18467
    18468
    18469
    18470
    18471
    18472
    18473
    18474
    18475
    18476
    18477
    18478
    18479
    18480
    18481
    18482
    18483
    18484
    18485
    18486
    18487
    18488
    18489
    18490
    18491
    18492
    18493
    18494
    18495
    18496
    18497
    18498
    18499
    18500
    18501
    18502
    18503
    18504
    18505
    18506
    18507
    18508
    18509
    18510
    18511
    18512
    18513
    18514
    18515
    18516
    18517
    18518
    18519
    18520
    18521
    18522
    18523
    18524
    18525
    18526
    18527
    18528
    18529
    18530
    18531
    18532
    18533
    18534
    18535
    18536
    18537
    18538
    18539
    18540
    18541
    18542
    18543
    18544
    18545
    18546
    18547
    18548
    18549
    18550
    18551
    18552
    18553
    18554
    18555
    18556
    18557
    18558
    18559
    18560
    18561
    18562
    18563
    18564
    18565
    18566
    18567
    18568
    18569
    18570
    18571
    18572
    18573
    18574
    18575
    18576
    18577
    18578
    18579
    18580
    18581
    18582
    18583
    18584
    18585
    18586
    18587
    18588
    18589
    18590
    18591
    18592
    18593
    18594
    18595
    18596
    18597
    18598
    18599
    18600
    18601
    18602
    18603
    18604
    18605
    18606
    18607
    18608
    18609
    18610
    18611
    18612
    18613
    18614
    18615
    18616
    18617
    18618
    18619
    18620
    18621
    18622
    18623
    18624
    18625
    18626
    18627
    18628
    18629
    18630
    18631
    18632
    18633
    18634
    18635
    18636
    18637
    18638
    18639
    18640
    18641
    18642
    18643
    18644
    18645
    18646
    18647
    18648
    18649
    18650
    18651
    18652
    18653
    18654
    18655
    18656
    18657
    18658
    18659
    18660
    18661
    18662
    18663
    18664
    18665
    18666
    18667
    18668
    18669
    18670
    18671
    18672
    18673
    18674
    18675
    18676
    18677
    18678
    18679
    18680
    18681
    18682
    18683
    18684
    18685
    18686
    18687
    18688
    18689
    18690
    18691
    18692
    18693
    18694
    18695
    18696
    18697
    18698
    18699
    18700
    18701
    18702
    18703
    18704
    18705
    18706
    18707
    18708
    18709
    18710
    18711
    18712
    18713
    18714
    18715
    18716
    18717
    18718
    18719
    18720
    18721
    18722
    18723
    18724
    18725
    18726
    18727
    18728
    18729
    18730
    18731
    18732
    18733
    18734
    18735
    18736
    18737
    18738
    18739
    18740
    18741
    18742
    18743
    18744
    18745
    18746
    18747
    18748
    18749
    18750
    18751
    18752
    18753
    18754
    18755
    18756
    18757
    18758
    18759
    18760
    18761
    18762
    18763
    18764
    18765
    18766
    18767
    18768
    18769
    18770
    18771
    18772
    18773
    18774
    18775
    18776
    18777
    18778
    18779
    18780
    18781
    18782
    18783
    18784
    18785
    18786
    18787
    18788
    18789
    18790
    18791
    18792
    18793
    18794
    18795
    18796
    18797
    18798
    18799
    18800
    18801
    18802
    18803
    18804
    18805
    18806
    18807
    18808
    18809
    18810
    18811
    18812
    18813
    18814
    18815
    18816
    18817
    18818
    18819
    18820
    18821
    18822
    18823
    18824
    18825
    18826
    18827
    18828
    18829
    18830
    18831
    18832
    18833
    18834
    18835
    18836
    18837
    18838
    18839
    18840
    18841
    18842
    18843
    18844
    18845
    18846
    18847
    18848
    18849
    18850
    18851
    18852
    18853
    18854
    18855
    18856
    18857
    18858
    18859
    18860
    18861
    18862
    18863
    18864
    18865
    18866
    18867
    18868
    18869
    18870
    18871
    18872
    18873
    18874
    18875
    18876
    18877
    18878
    18879
    18880
    18881
    18882
    18883
    18884
    18885
    18886
    18887
    18888
    18889
    18890
    18891
    18892
    18893
    18894
    18895
    18896
    18897
    18898
    18899
    18900
    18901
    18902
    18903
    18904
    18905
    18906
    18907
    18908
    18909
    18910
    18911
    18912
    18913
    18914
    18915
    18916
    18917
    18918
    18919
    18920
    18921
    18922
    18923
    18924
    18925
    18926
    18927
    18928
    18929
    18930
    18931
    18932
    18933
    18934
    18935
    18936
    18937
    18938
    18939
    18940
    18941
    18942
    18943
    18944
    18945
    18946
    18947
    18948
    18949
    18950
    18951
    18952
    18953
    18954
    18955
    18956
    18957
    18958
    18959
    18960
    18961
    18962
    18963
    18964
    18965
    18966
    18967
    18968
    18969
    18970
    18971
    18972
    18973
    18974
    18975
    18976
    18977
    18978
    18979
    18980
    18981
    18982
    18983
    18984
    18985
    18986
    18987
    18988
    18989
    18990
    18991
    18992
    18993
    18994
    18995
    18996
    18997
    18998
    18999
    19000
    19001
    19002
    19003
    19004
    19005
    19006
    19007
    19008
    19009
    19010
    19011
    19012
    19013
    19014
    19015
    19016
    19017
    19018
    19019
    19020
    19021
    19022
    19023
    19024
    19025
    19026
    19027
    19028
    19029
    19030
    19031
    19032
    19033
    19034
    19035
    19036
    19037
    19038
    19039
    19040
    19041
    19042
    19043
    19044
    19045
    19046
    19047
    19048
    19049
    19050
    19051
    19052
    19053
    19054
    19055
    19056
    19057
    19058
    19059
    19060
    19061
    19062
    19063
    19064
    19065
    19066
    19067
    19068
    19069
    19070
    19071
    19072
    19073
    19074
    19075
    19076
    19077
    19078
    19079
    19080
    19081
    19082
    19083
    19084
    19085
    19086
    19087
    19088
    19089
    19090
    19091
    19092
    19093
    19094
    19095
    19096
    19097
    19098
    19099
    19100
    19101
    19102
    19103
    19104
    19105
    19106
    19107
    19108
    19109
    19110
    19111
    19112
    19113
    19114
    19115
    19116
    19117
    19118
    19119
    19120
    19121
    19122
    19123
    19124
    19125
    19126
    19127
    19128
    19129
    19130
    19131
    19132
    19133
    19134
    19135
    19136
    19137
    19138
    19139
    19140
    19141
    19142
    19143
    19144
    19145
    19146
    19147
    19148
    19149
    19150
    19151
    19152
    19153
    19154
    19155
    19156
    19157
    19158
    19159
    19160
    19161
    19162
    19163
    19164
    19165
    19166
    19167
    19168
    19169
    19170
    19171
    19172
    19173
    19174
    19175
    19176
    19177
    19178
    19179
    19180
    19181
    19182
    19183
    19184
    19185
    19186
    19187
    19188
    19189
    19190
    19191
    19192
    19193
    19194
    19195
    19196
    19197
    19198
    19199
    19200
    19201
    19202
    19203
    19204
    19205
    19206
    19207
    19208
    19209
    19210
    19211
    19212
    19213
    19214
    19215
    19216
    19217
    19218
    19219
    19220
    19221
    19222
    19223
    19224
    19225
    19226
    19227
    19228
    19229
    19230
    19231
    19232
    19233
    19234
    19235
    19236
    19237
    19238
    19239
    19240
    19241
    19242
    19243
    19244
    19245
    19246
    19247
    19248
    19249
    19250
    19251
    19252
    19253
    19254
    19255
    19256
    19257
    19258
    19259
    19260
    19261
    19262
    19263
    19264
    19265
    19266
    19267
    19268
    19269
    19270
    19271
    19272
    19273
    19274
    19275
    19276
    19277
    19278
    19279
    19280
    19281
    19282
    19283
    19284
    19285
    19286
    19287
    19288
    19289
    19290
    19291
    19292
    19293
    19294
    19295
    19296
    19297
    19298
    19299
    19300
    19301
    19302
    19303
    19304
    19305
    19306
    19307
    19308
    19309
    19310
    19311
    19312
    19313
    19314
    19315
    19316
    19317
    19318
    19319
    19320
    19321
    19322
    19323
    19324
    19325
    19326
    19327
    19328
    19329
    19330
    19331
    19332
    19333
    19334
    19335
    19336
    19337
    19338
    19339
    19340
    19341
    19342
    19343
    19344
    19345
    19346
    19347
    19348
    19349
    19350
    19351
    19352
    19353
    19354
    19355
    19356
    19357
    19358
    19359
    19360
    19361
    19362
    19363
    19364
    19365
    19366
    19367
    19368
    19369
    19370
    19371
    19372
    19373
    19374
    19375
    19376
    19377
    19378
    19379
    19380
    19381
    19382
    19383
    19384
    19385
    19386
    19387
    19388
    19389
    19390
    19391
    19392
    19393
    19394
    19395
    19396
    19397
    19398
    19399
    19400
    19401
    19402
    19403
    19404
    19405
    19406
    19407
    19408
    19409
    19410
    19411
    19412
    19413
    19414
    19415
    19416
    19417
    19418
    19419
    19420
    19421
    19422
    19423
    19424
    19425
    19426
    19427
    19428
    19429
    19430
    19431
    19432
    19433
    19434
    19435
    19436
    19437
    19438
    19439
    19440
    19441
    19442
    19443
    19444
    19445
    19446
    19447
    19448
    19449
    19450
    19451
    19452
    19453
    19454
    19455
    19456
    19457
    19458
    19459
    19460
    19461
    19462
    19463
    19464
    19465
    19466
    19467
    19468
    19469
    19470
    19471
    19472
    19473
    19474
    19475
    19476
    19477
    19478
    19479
    19480
    19481
    19482
    19483
    19484
    19485
    19486
    19487
    19488
    19489
    19490
    19491
    19492
    19493
    19494
    19495
    19496
    19497
    19498
    19499
    19500
    19501
    19502
    19503
    19504
    19505
    19506
    19507
    19508
    19509
    19510
    19511
    19512
    19513
    19514
    19515
    19516
    19517
    19518
    19519
    19520
    19521
    19522
    19523
    19524
    19525
    19526
    19527
    19528
    19529
    19530
    19531
    19532
    19533
    19534
    19535
    19536
    19537
    19538
    19539
    19540
    19541
    19542
    19543
    19544
    19545
    19546
    19547
    19548
    19549
    19550
    19551
    19552
    19553
    19554
    19555
    19556
    19557
    19558
    19559
    19560
    19561
    19562
    19563
    19564
    19565
    19566
    19567
    19568
    19569
    19570
    19571
    19572
    19573
    19574
    19575
    19576
    19577
    19578
    19579
    19580
    19581
    19582
    19583
    19584
    19585
    19586
    19587
    19588
    19589
    19590
    19591
    19592
    19593
    19594
    19595
    19596
    19597
    19598
    19599
    19600
    19601
    19602
    19603
    19604
    19605
    19606
    19607
    19608
    19609
    19610
    19611
    19612
    19613
    19614
    19615
    19616
    19617
    19618
    19619
    19620
    19621
    19622
    19623
    19624
    19625
    19626
    19627
    19628
    19629
    19630
    19631
    19632
    19633
    19634
    19635
    19636
    19637
    19638
    19639
    19640
    19641
    19642
    19643
    19644
    19645
    19646
    19647
    19648
    19649
    19650
    19651
    19652
    19653
    19654
    19655
    19656
    19657
    19658
    19659
    19660
    19661
    19662
    19663
    19664
    19665
    19666
    19667
    19668
    19669
    19670
    19671
    19672
    19673
    19674
    19675
    19676
    19677
    19678
    19679
    19680
    19681
    19682
    19683
    19684
    19685
    19686
    19687
    19688
    19689
    19690
    19691
    19692
    19693
    19694
    19695
    19696
    19697
    19698
    19699
    19700
    19701
    19702
    19703
    19704
    19705
    19706
    19707
    19708
    19709
    19710
    19711
    19712
    19713
    19714
    19715
    19716
    19717
    19718
    19719
    19720
    19721
    19722
    19723
    19724
    19725
    19726
    19727
    19728
    19729
    19730
    19731
    19732
    19733
    19734
    19735
    19736
    19737
    19738
    19739
    19740
    19741
    19742
    19743
    19744
    19745
    19746
    19747
    19748
    19749
    19750
    19751
    19752
    19753
    19754
    19755
    19756
    19757
    19758
    19759
    19760
    19761
    19762
    19763
    19764
    19765
    19766
    19767
    19768
    19769
    19770
    19771
    19772
    19773
    19774
    19775
    19776
    19777
    19778
    19779
    19780
    19781
    19782
    19783
    19784
    19785
    19786
    19787
    19788
    19789
    19790
    19791
    19792
    19793
    19794
    19795
    19796
    19797
    19798
    19799
    19800
    19801
    19802
    19803
    19804
    19805
    19806
    19807
    19808
    19809
    19810
    19811
    19812
    19813
    19814
    19815
    19816
    19817
    19818
    19819
    19820
    19821
    19822
    19823
    19824
    19825
    19826
    19827
    19828
    19829
    19830
    19831
    19832
    19833
    19834
    19835
    19836
    19837
    19838
    19839
    19840
    19841
    19842
    19843
    19844
    19845
    19846
    19847
    19848
    19849
    19850
    19851
    19852
    19853
    19854
    19855
    19856
    19857
    19858
    19859
    19860
    19861
    19862
    19863
    19864
    19865
    19866
    19867
    19868
    19869
    19870
    19871
    19872
    19873
    19874
    19875
    19876
    19877
    19878
    19879
    19880
    19881
    19882
    19883
    19884
    19885
    19886
    19887
    19888
    19889
    19890
    19891
    19892
    19893
    19894
    19895
    19896
    19897
    19898
    19899
    19900
    19901
    19902
    19903
    19904
    19905
    19906
    19907
    19908
    19909
    19910
    19911
    19912
    19913
    19914
    19915
    19916
    19917
    19918
    19919
    19920
    19921
    19922
    19923
    19924
    19925
    19926
    19927
    19928
    19929
    19930
    19931
    19932
    19933
    19934
    19935
    19936
    19937
    19938
    19939
    19940
    19941
    19942
    19943
    19944
    19945
    19946
    19947
    19948
    19949
    19950
    19951
    19952
    19953
    19954
    19955
    19956
    19957
    19958
    19959
    19960
    19961
    19962
    19963
    19964
    19965
    19966
    19967
    19968
    19969
    19970
    19971
    19972
    19973
    19974
    19975
    19976
    19977
    19978
    19979
    19980
    19981
    19982
    19983
    19984
    19985
    19986
    19987
    19988
    19989
    19990
    19991
    19992
    19993
    19994
    19995
    19996
    19997
    19998
    19999
    20000
    20001
    20002
    20003
    20004
    20005
    20006
    20007
    20008
    20009
    20010
    20011
    20012
    20013
    20014
    20015
    20016
    20017
    20018
    20019
    20020
    20021
    20022
    20023
    20024
    20025
    20026
    20027
    20028
    20029
    20030
    20031
    20032
    20033
    20034
    20035
    20036
    20037
    20038
    20039
    20040
    20041
    20042
    20043
    20044
    20045
    20046
    20047
    20048
    20049
    20050
    20051
    20052
    20053
    20054
    20055
    20056
    20057
    20058
    20059
    20060
    20061
    20062
    20063
    20064
    20065
    20066
    20067
    20068
    20069
    20070
    20071
    20072
    20073
    20074
    20075
    20076
    20077
    20078
    20079
    20080
    20081
    20082
    20083
    20084
    20085
    20086
    20087
    20088
    20089
    20090
    20091
    20092
    20093
    20094
    20095
    20096
    20097
    20098
    20099
    20100
    20101
    20102
    20103
    20104
    20105
    20106
    20107
    20108
    20109
    20110
    20111
    20112
    20113
    20114
    20115
    20116
    20117
    20118
    20119
    20120
    20121
    20122
    20123
    20124
    20125
    20126
    20127
    20128
    20129
    20130
    20131
    20132
    20133
    20134
    20135
    20136
    20137
    20138
    20139
    20140
    20141
    20142
    20143
    20144
    20145
    20146
    20147
    20148
    20149
    20150
    20151
    20152
    20153
    20154
    20155
    20156
    20157
    20158
    20159
    20160
    20161
    20162
    20163
    20164
    20165
    20166
    20167
    20168
    20169
    20170
    20171
    20172
    20173
    20174
    20175
    20176
    20177
    20178
    20179
    20180
    20181
    20182
    20183
    20184
    20185
    20186
    20187
    20188
    20189
    20190
    20191
    20192
    20193
    20194
    20195
    20196
    20197
    20198
    20199
    20200
    20201
    20202
    20203
    20204
    20205
    20206
    20207
    20208
    20209
    20210
    20211
    20212
    20213
    20214
    20215
    20216
    20217
    20218
    20219
    20220
    20221
    20222
    20223
    20224
    20225
    20226
    20227
    20228
    20229
    20230
    20231
    20232
    20233
    20234
    20235
    20236
    20237
    20238
    20239
    20240
    20241
    20242
    20243
    20244
    20245
    20246
    20247
    20248
    20249
    20250
    20251
    20252
    20253
    20254
    20255
    20256
    20257
    20258
    20259
    20260
    20261
    20262
    20263
    20264
    20265
    20266
    20267
    20268
    20269
    20270
    20271
    20272
    20273
    20274
    20275
    20276
    20277
    20278
    20279
    20280
    20281
    20282
    20283
    20284
    20285
    20286
    20287
    20288
    20289
    20290
    20291
    20292
    20293
    20294
    20295
    20296
    20297
    20298
    20299
    20300
    20301
    20302
    20303
    20304
    20305
    20306
    20307
    20308
    20309
    20310
    20311
    20312
    20313
    20314
    20315
    20316
    20317
    20318
    20319
    20320
    20321
    20322
    20323
    20324
    20325
    20326
    20327
    20328
    20329
    20330
    20331
    20332
    20333
    20334
    20335
    20336
    20337
    20338
    20339
    20340
    20341
    20342
    20343
    20344
    20345
    20346
    20347
    20348
    20349
    20350
    20351
    20352
    20353
    20354
    20355
    20356
    20357
    20358
    20359
    20360
    20361
    20362
    20363
    20364
    20365
    20366
    20367
    20368
    20369
    20370
    20371
    20372
    20373
    20374
    20375
    20376
    20377
    20378
    20379
    20380
    20381
    20382
    20383
    20384
    20385
    20386
    20387
    20388
    20389
    20390
    20391
    20392
    20393
    20394
    20395
    20396
    20397
    20398
    20399
    20400
    20401
    20402
    20403
    20404
    20405
    20406
    20407
    20408
    20409
    20410
    20411
    20412
    20413
    20414
    20415
    20416
    20417
    20418
    20419
    20420
    20421
    20422
    20423
    20424
    20425
    20426
    20427
    20428
    20429
    20430
    20431
    20432
    20433
    20434
    20435
    20436
    20437
    20438
    20439
    20440
    20441
    20442
    20443
    20444
    20445
    20446
    20447
    20448
    20449
    20450
    20451
    20452
    20453
    20454
    20455
    20456
    20457
    20458
    20459
    20460
    20461
    20462
    20463
    20464
    20465
    20466
    20467
    20468
    20469
    20470
    20471
    20472
    20473
    20474
    20475
    20476
    20477
    20478
    20479
    20480
    20481
    20482
    20483
    20484
    20485
    20486
    20487
    20488
    20489
    20490
    20491
    20492
    20493
    20494
    20495
    20496
    20497
    20498
    20499
    20500
    20501
    20502
    20503
    20504
    20505
    20506
    20507
    20508
    20509
    20510
    20511
    20512
    20513
    20514
    20515
    20516
    20517
    20518
    20519
    20520
    20521
    20522
    20523
    20524
    20525
    20526
    20527
    20528
    20529
    20530
    20531
    20532
    20533
    20534
    20535
    20536
    20537
    20538
    20539
    20540
    20541
    20542
    20543
    20544
    20545
    20546
    20547
    20548
    20549
    20550
    20551
    20552
    20553
    20554
    20555
    20556
    20557
    20558
    20559
    20560
    20561
    20562
    20563
    20564
    20565
    20566
    20567
    20568
    20569
    20570
    20571
    20572
    20573
    20574
    20575
    20576
    20577
    20578
    20579
    20580
    20581
    20582
    20583
    20584
    20585
    20586
    20587
    20588
    20589
    20590
    20591
    20592
    20593
    20594
    20595
    20596
    20597
    20598
    20599
    20600
    20601
    20602
    20603
    20604
    20605
    20606
    20607
    20608
    20609
    20610
    20611
    20612
    20613
    20614
    20615
    20616
    20617
    20618
    20619
    20620
    20621
    20622
    20623
    20624
    20625
    20626
    20627
    20628
    20629
    20630
    20631
    20632
    20633
    20634
    20635
    20636
    20637
    20638
    20639
    20640
    20641
    20642
    20643
    20644
    20645
    20646
    20647
    20648
    20649
    20650
    20651
    20652
    20653
    20654
    20655
    20656
    20657
    20658
    20659
    20660
    20661
    20662
    20663
    20664
    20665
    20666
    20667
    20668
    20669
    20670
    20671
    20672
    20673
    20674
    20675
    20676
    20677
    20678
    20679
    20680
    20681
    20682
    20683
    20684
    20685
    20686
    20687
    20688
    20689
    20690
    20691
    20692
    20693
    20694
    20695
    20696
    20697
    20698
    20699
    20700
    20701
    20702
    20703
    20704
    20705
    20706
    20707
    20708
    20709
    20710
    20711
    20712
    20713
    20714
    20715
    20716
    20717
    20718
    20719
    20720
    20721
    20722
    20723
    20724
    20725
    20726
    20727
    20728
    20729
    20730
    20731
    20732
    20733
    20734
    20735
    20736
    20737
    20738
    20739
    20740
    20741
    20742
    20743
    20744
    20745
    20746
    20747
    20748
    20749
    20750
    20751
    20752
    20753
    20754
    20755
    20756
    20757
    20758
    20759
    20760
    20761
    20762
    20763
    20764
    20765
    20766
    20767
    20768
    20769
    20770
    20771
    20772
    20773
    20774
    20775
    20776
    20777
    20778
    20779
    20780
    20781
    20782
    20783
    20784
    20785
    20786
    20787
    20788
    20789
    20790
    20791
    20792
    20793
    20794
    20795
    20796
    20797
    20798
    20799
    20800
    20801
    20802
    20803
    20804
    20805
    20806
    20807
    20808
    20809
    20810
    20811
    20812
    20813
    20814
    20815
    20816
    20817
    20818
    20819
    20820
    20821
    20822
    20823
    20824
    20825
    20826
    20827
    20828
    20829
    20830
    20831
    20832
    20833
    20834
    20835
    20836
    20837
    20838
    20839
    20840
    20841
    20842
    20843
    20844
    20845
    20846
    20847
    20848
    20849
    20850
    20851
    20852
    20853
    20854
    20855
    20856
    20857
    20858
    20859
    20860
    20861
    20862
    20863
    20864
    20865
    20866
    20867
    20868
    20869
    20870
    20871
    20872
    20873
    20874
    20875
    20876
    20877
    20878
    20879
    20880
    20881
    20882
    20883
    20884
    20885
    20886
    20887
    20888
    20889
    20890
    20891
    20892
    20893
    20894
    20895
    20896
    20897
    20898
    20899
    20900
    20901
    20902
    20903
    20904
    20905
    20906
    20907
    20908
    20909
    20910
    20911
    20912
    20913
    20914
    20915
    20916
    20917
    20918
    20919
    20920
    20921
    20922
    20923
    20924
    20925
    20926
    20927
    20928
    20929
    20930
    20931
    20932
    20933
    20934
    20935
    20936
    20937
    20938
    20939
    20940
    20941
    20942
    20943
    20944
    20945
    20946
    20947
    20948
    20949
    20950
    20951
    20952
    20953
    20954
    20955
    20956
    20957
    20958
    20959
    20960
    20961
    20962
    20963
    20964
    20965
    20966
    20967
    20968
    20969
    20970
    20971
    20972
    20973
    20974
    20975
    20976
    20977
    20978
    20979
    20980
    20981
    20982
    20983
    20984
    20985
    20986
    20987
    20988
    20989
    20990
    20991
    20992
    20993
    20994
    20995
    20996
    20997
    20998
    20999
    21000
    21001
    21002
    21003
    21004
    21005
    21006
    21007
    21008
    21009
    21010
    21011
    21012
    21013
    21014
    21015
    21016
    21017
    21018
    21019
    21020
    21021
    21022
    21023
    21024
    21025
    21026
    21027
    21028
    21029
    21030
    21031
    21032
    21033
    21034
    21035
    21036
    21037
    21038
    21039
    21040
    21041
    21042
    21043
    21044
    21045
    21046
    21047
    21048
    21049
    21050
    21051
    21052
    21053
    21054
    21055
    21056
    21057
    21058
    21059
    21060
    21061
    21062
    21063
    21064
    21065
    21066
    21067
    21068
    21069
    21070
    21071
    21072
    21073
    21074
    21075
    21076
    21077
    21078
    21079
    21080
    21081
    21082
    21083
    21084
    21085
    21086
    21087
    21088
    21089
    21090
    21091
    21092
    21093
    21094
    21095
    21096
    21097
    21098
    21099
    21100
    21101
    21102
    21103
    21104
    21105
    21106
    21107
    21108
    21109
    21110
    21111
    21112
    21113
    21114
    21115
    21116
    21117
    21118
    21119
    21120
    21121
    21122
    21123
    21124
    21125
    21126
    21127
    21128
    21129
    21130
    21131
    21132
    21133
    21134
    21135
    21136
    21137
    21138
    21139
    21140
    21141
    21142
    21143
    21144
    21145
    21146
    21147
    21148
    21149
    21150
    21151
    21152
    21153
    21154
    21155
    21156
    21157
    21158
    21159
    21160
    21161
    21162
    21163
    21164
    21165
    21166
    21167
    21168
    21169
    21170
    21171
    21172
    21173
    21174
    21175
    21176
    21177
    21178
    21179
    21180
    21181
    21182
    21183
    21184
    21185
    21186
    21187
    21188
    21189
    21190
    21191
    21192
    21193
    21194
    21195
    21196
    21197
    21198
    21199
    21200
    21201
    21202
    21203
    21204
    21205
    21206
    21207
    21208
    21209
    21210
    21211
    21212
    21213
    21214
    21215
    21216
    21217
    21218
    21219
    21220
    21221
    21222
    21223
    21224
    21225
    21226
    21227
    21228
    21229
    21230
    21231
    21232
    21233
    21234
    21235
    21236
    21237
    21238
    21239
    21240
    21241
    21242
    21243
    21244
    21245
    21246
    21247
    21248
    21249
    21250
    21251
    21252
    21253
    21254
    21255
    21256
    21257
    21258
    21259
    21260
    21261
    21262
    21263
    21264
    21265
    21266
    21267
    21268
    21269
    21270
    21271
    21272
    21273
    21274
    21275
    21276
    21277
    21278
    21279
    21280
    21281
    21282
    21283
    21284
    21285
    21286
    21287
    21288
    21289
    21290
    21291
    21292
    21293
    21294
    21295
    21296
    21297
    21298
    21299
    21300
    21301
    21302
    21303
    21304
    21305
    21306
    21307
    21308
    21309
    21310
    21311
    21312
    21313
    21314
    21315
    21316
    21317
    21318
    21319
    21320
    21321
    21322
    21323
    21324
    21325
    21326
    21327
    21328
    21329
    21330
    21331
    21332
    21333
    21334
    21335
    21336
    21337
    21338
    21339
    21340
    21341
    21342
    21343
    21344
    21345
    21346
    21347
    21348
    21349
    21350
    21351
    21352
    21353
    21354
    21355
    21356
    21357
    21358
    21359
    21360
    21361
    21362
    21363
    21364
    21365
    21366
    21367
    21368
    21369
    21370
    21371
    21372
    21373
    21374
    21375
    21376
    21377
    21378
    21379
    21380
    21381
    21382
    21383
    21384
    21385
    21386
    21387
    21388
    21389
    21390
    21391
    21392
    21393
    21394
    21395
    21396
    21397
    21398
    21399
    21400
    21401
    21402
    21403
    21404
    21405
    21406
    21407
    21408
    21409
    21410
    21411
    21412
    21413
    21414
    21415
    21416
    21417
    21418
    21419
    21420
    21421
    21422
    21423
    21424
    21425
    21426
    21427
    21428
    21429
    21430
    21431
    21432
    21433
    21434
    21435
    21436
    21437
    21438
    21439
    21440
    21441
    21442
    21443
    21444
    21445
    21446
    21447
    21448
    21449
    21450
    21451
    21452
    21453
    21454
    21455
    21456
    21457
    21458
    21459
    21460
    21461
    21462
    21463
    21464
    21465
    21466
    21467
    21468
    21469
    21470
    21471
    21472
    21473
    21474
    21475
    21476
    21477
    21478
    21479
    21480
    21481
    21482
    21483
    21484
    21485
    21486
    21487
    21488
    21489
    21490
    21491
    21492
    21493
    21494
    21495
    21496
    21497
    21498
    21499
    21500
    21501
    21502
    21503
    21504
    21505
    21506
    21507
    21508
    21509
    21510
    21511
    21512
    21513
    21514
    21515
    21516
    21517
    21518
    21519
    21520
    21521
    21522
    21523
    21524
    21525
    21526
    21527
    21528
    21529
    21530
    21531
    21532
    21533
    21534
    21535
    21536
    21537
    21538
    21539
    21540
    21541
    21542
    21543
    21544
    21545
    21546
    21547
    21548
    21549
    21550
    21551
    21552
    21553
    21554
    21555
    21556
    21557
    21558
    21559
    21560
    21561
    21562
    21563
    21564
    21565
    21566
    21567
    21568
    21569
    21570
    21571
    21572
    21573
    21574
    21575
    21576
    21577
    21578
    21579
    21580
    21581
    21582
    21583
    21584
    21585
    21586
    21587
    21588
    21589
    21590
    21591
    21592
    21593
    21594
    21595
    21596
    21597
    21598
    21599
    21600
    21601
    21602
    21603
    21604
    21605
    21606
    21607
    21608
    21609
    21610
    21611
    21612
    21613
    21614
    21615
    21616
    21617
    21618
    21619
    21620
    21621
    21622
    21623
    21624
    21625
    21626
    21627
    21628
    21629
    21630
    21631
    21632
    21633
    21634
    21635
    21636
    21637
    21638
    21639
    21640
    21641
    21642
    21643
    21644
    21645
    21646
    21647
    21648
    21649
    21650
    21651
    21652
    21653
    21654
    21655
    21656
    21657
    21658
    21659
    21660
    21661
    21662
    21663
    21664
    21665
    21666
    21667
    21668
    21669
    21670
    21671
    21672
    21673
    21674
    21675
    21676
    21677
    21678
    21679
    21680
    21681
    21682
    21683
    21684
    21685
    21686
    21687
    21688
    21689
    21690
    21691
    21692
    21693
    21694
    21695
    21696
    21697
    21698
    21699
    21700
    21701
    21702
    21703
    21704
    21705
    21706
    21707
    21708
    21709
    21710
    21711
    21712
    21713
    21714
    21715
    21716
    21717
    21718
    21719
    21720
    21721
    21722
    21723
    21724
    21725
    21726
    21727
    21728
    21729
    21730
    21731
    21732
    21733
    21734
    21735
    21736
    21737
    21738
    21739
    21740
    21741
    21742
    21743
    21744
    21745
    21746
    21747
    21748
    21749
    21750
    21751
    21752
    21753
    21754
    21755
    21756
    21757
    21758
    21759
    21760
    21761
    21762
    21763
    21764
    21765
    21766
    21767
    21768
    21769
    21770
    21771
    21772
    21773
    21774
    21775
    21776
    21777
    21778
    21779
    21780
    21781
    21782
    21783
    21784
    21785
    21786
    21787
    21788
    21789
    21790
    21791
    21792
    21793
    21794
    21795
    21796
    21797
    21798
    21799
    21800
    21801
    21802
    21803
    21804
    21805
    21806
    21807
    21808
    21809
    21810
    21811
    21812
    21813
    21814
    21815
    21816
    21817
    21818
    21819
    21820
    21821
    21822
    21823
    21824
    21825
    21826
    21827
    21828
    21829
    21830
    21831
    21832
    21833
    21834
    21835
    21836
    21837
    21838
    21839
    21840
    21841
    21842
    21843
    21844
    21845
    21846
    21847
    21848
    21849
    21850
    21851
    21852
    21853
    21854
    21855
    21856
    21857
    21858
    21859
    21860
    21861
    21862
    21863
    21864
    21865
    21866
    21867
    21868
    21869
    21870
    21871
    21872
    21873
    21874
    21875
    21876
    21877
    21878
    21879
    21880
    21881
    21882
    21883
    21884
    21885
    21886
    21887
    21888
    21889
    21890
    21891
    21892
    21893
    21894
    21895
    21896
    21897
    21898
    21899
    21900
    21901
    21902
    21903
    21904
    21905
    21906
    21907
    21908
    21909
    21910
    21911
    21912
    21913
    21914
    21915
    21916
    21917
    21918
    21919
    21920
    21921
    21922
    21923
    21924
    21925
    21926
    21927
    21928
    21929
    21930
    21931
    21932
    21933
    21934
    21935
    21936
    21937
    21938
    21939
    21940
    21941
    21942
    21943
    21944
    21945
    21946
    21947
    21948
    21949
    21950
    21951
    21952
    21953
    21954
    21955
    21956
    21957
    21958
    21959
    21960
    21961
    21962
    21963
    21964
    21965
    21966
    21967
    21968
    21969
    21970
    21971
    21972
    21973
    21974
    21975
    21976
    21977
    21978
    21979
    21980
    21981
    21982
    21983
    21984
    21985
    21986
    21987
    21988
    21989
    21990
    21991
    21992
    21993
    21994
    21995
    21996
    21997
    21998
    21999
    22000
    22001
    22002
    22003
    22004
    22005
    22006
    22007
    22008
    22009
    22010
    22011
    22012
    22013
    22014
    22015
    22016
    22017
    22018
    22019
    22020
    22021
    22022
    22023
    22024
    22025
    22026
    22027
    22028
    22029
    22030
    22031
    22032
    22033
    22034
    22035
    22036
    22037
    22038
    22039
    22040
    22041
    22042
    22043
    22044
    22045
    22046
    22047
    22048
    22049
    22050
    22051
    22052
    22053
    22054
    22055
    22056
    22057
    22058
    22059
    22060
    22061
    22062
    22063
    22064
    22065
    22066
    22067
    22068
    22069
    22070
    22071
    22072
    22073
    22074
    22075
    22076
    22077
    22078
    22079
    22080
    22081
    22082
    22083
    22084
    22085
    22086
    22087
    22088
    22089
    22090
    22091
    22092
    22093
    22094
    22095
    22096
    22097
    22098
    22099
    22100
    22101
    22102
    22103
    22104
    22105
    22106
    22107
    22108
    22109
    22110
    22111
    22112
    22113
    22114
    22115
    22116
    22117
    22118
    22119
    22120
    22121
    22122
    22123
    22124
    22125
    22126
    22127
    22128
    22129
    22130
    22131
    22132
    22133
    22134
    22135
    22136
    22137
    22138
    22139
    22140
    22141
    22142
    22143
    22144
    22145
    22146
    22147
    22148
    22149
    22150
    22151
    22152
    22153
    22154
    22155
    22156
    22157
    22158
    22159
    22160
    22161
    22162
    22163
    22164
    22165
    22166
    22167
    22168
    22169
    22170
    22171
    22172
    22173
    22174
    22175
    22176
    22177
    22178
    22179
    22180
    22181
    22182
    22183
    22184
    22185
    22186
    22187
    22188
    22189
    22190
    22191
    22192
    22193
    22194
    22195
    22196
    22197
    22198
    22199
    22200
    22201
    22202
    22203
    22204
    22205
    22206
    22207
    22208
    22209
    22210
    22211
    22212
    22213
    22214
    22215
    22216
    22217
    22218
    22219
    22220
    22221
    22222
    22223
    22224
    22225
    22226
    22227
    22228
    22229
    22230
    22231
    22232
    22233
    22234
    22235
    22236
    22237
    22238
    22239
    22240
    22241
    22242
    22243
    22244
    22245
    22246
    22247
    22248
    22249
    22250
    22251
    22252
    22253
    22254
    22255
    22256
    22257
    22258
    22259
    22260
    22261
    22262
    22263
    22264
    22265
    22266
    22267
    22268
    22269
    22270
    22271
    22272
    22273
    22274
    22275
    22276
    22277
    22278
    22279
    22280
    22281
    22282
    22283
    22284
    22285
    22286
    22287
    22288
    22289
    22290
    22291
    22292
    22293
    22294
    22295
    22296
    22297
    22298
    22299
    22300
    22301
    22302
    22303
    22304
    22305
    22306
    22307
    22308
    22309
    22310
    22311
    22312
    22313
    22314
    22315
    22316
    22317
    22318
    22319
    22320
    22321
    22322
    22323
    22324
    22325
    22326
    22327
    22328
    22329
    22330
    22331
    22332
    22333
    22334
    22335
    22336
    22337
    22338
    22339
    22340
    22341
    22342
    22343
    22344
    22345
    22346
    22347
    22348
    22349
    22350
    22351
    22352
    22353
    22354
    22355
    22356
    22357
    22358
    22359
    22360
    22361
    22362
    22363
    22364
    22365
    22366
    22367
    22368
    22369
    22370
    22371
    22372
    22373
    22374
    22375
    22376
    22377
    22378
    22379
    22380
    22381
    22382
    22383
    22384
    22385
    22386
    22387
    22388
    22389
    22390
    22391
    22392
    22393
    22394
    22395
    22396
    22397
    22398
    22399
    22400
    22401
    22402
    22403
    22404
    22405
    22406
    22407
    22408
    22409
    22410
    22411
    22412
    22413
    22414
    22415
    22416
    22417
    22418
    22419
    22420
    22421
    22422
    22423
    22424
    22425
    22426
    22427
    22428
    22429
    22430
    22431
    22432
    22433
    22434
    22435
    22436
    22437
    22438
    22439
    22440
    22441
    22442
    22443
    22444
    22445
    22446
    22447
    22448
    22449
    22450
    22451
    22452
    22453
    22454
    22455
    22456
    22457
    22458
    22459
    22460
    22461
    22462
    22463
    22464
    22465
    22466
    22467
    22468
    22469
    22470
    22471
    22472
    22473
    22474
    22475
    22476
    22477
    22478
    22479
    22480
    22481
    22482
    22483
    22484
    22485
    22486
    22487
    22488
    22489
    22490
    22491
    22492
    22493
    22494
    22495
    22496
    22497
    22498
    22499
    22500
    22501
    22502
    22503
    22504
    22505
    22506
    22507
    22508
    22509
    22510
    22511
    22512
    22513
    22514
    22515
    22516
    22517
    22518
    22519
    22520
    22521
    22522
    22523
    22524
    22525
    22526
    22527
    22528
    22529
    22530
    22531
    22532
    22533
    22534
    22535
    22536
    22537
    22538
    22539
    22540
    22541
    22542
    22543
    22544
    22545
    22546
    22547
    22548
    22549
    22550
    22551
    22552
    22553
    22554
    22555
    22556
    22557
    22558
    22559
    22560
    22561
    22562
    22563
    22564
    22565
    22566
    22567
    22568
    22569
    22570
    22571
    22572
    22573
    22574
    22575
    22576
    22577
    22578
    22579
    22580
    22581
    22582
    22583
    22584
    22585
    22586
    22587
    22588
    22589
    22590
    22591
    22592
    22593
    22594
    22595
    22596
    22597
    22598
    22599
    22600
    22601
    22602
    22603
    22604
    22605
    22606
    22607
    22608
    22609
    22610
    22611
    22612
    22613
    22614
    22615
    22616
    22617
    22618
    22619
    22620
    22621
    22622
    22623
    22624
    22625
    22626
    22627
    22628
    22629
    22630
    22631
    22632
    22633
    22634
    22635
    22636
    22637
    22638
    22639
    22640
    22641
    22642
    22643
    22644
    22645
    22646
    22647
    22648
    22649
    22650
    22651
    22652
    22653
    22654
    22655
    22656
    22657
    22658
    22659
    22660
    22661
    22662
    22663
    22664
    22665
    22666
    22667
    22668
    22669
    22670
    22671
    22672
    22673
    22674
    22675
    22676
    22677
    22678
    22679
    22680
    22681
    22682
    22683
    22684
    22685
    22686
    22687
    22688
    22689
    22690
    22691
    22692
    22693
    22694
    22695
    22696
    22697
    22698
    22699
    22700
    22701
    22702
    22703
    22704
    22705
    22706
    22707
    22708
    22709
    22710
    22711
    22712
    22713
    22714
    22715
    22716
    22717
    22718
    22719
    22720
    22721
    22722
    22723
    22724
    22725
    22726
    22727
    22728
    22729
    22730
    22731
    22732
    22733
    22734
    22735
    22736
    22737
    22738
    22739
    22740
    22741
    22742
    22743
    22744
    22745
    22746
    22747
    22748
    22749
    22750
    22751
    22752
    22753
    22754
    22755
    22756
    22757
    22758
    22759
    22760
    22761
    22762
    22763
    22764
    22765
    22766
    22767
    22768
    22769
    22770
    22771
    22772
    22773
    22774
    22775
    22776
    22777
    22778
    22779
    22780
    22781
    22782
    22783
    22784
    22785
    22786
    22787
    22788
    22789
    22790
    22791
    22792
    22793
    22794
    22795
    22796
    22797
    22798
    22799
    22800
    22801
    22802
    22803
    22804
    22805
    22806
    22807
    22808
    22809
    22810
    22811
    22812
    22813
    22814
    22815
    22816
    22817
    22818
    22819
    22820
    22821
    22822
    22823
    22824
    22825
    22826
    22827
    22828
    22829
    22830
    22831
    22832
    22833
    22834
    22835
    22836
    22837
    22838
    22839
    22840
    22841
    22842
    22843
    22844
    22845
    22846
    22847
    22848
    22849
    22850
    22851
    22852
    22853
    22854
    22855
    22856
    22857
    22858
    22859
    22860
    22861
    22862
    22863
    22864
    22865
    22866
    22867
    22868
    22869
    22870
    22871
    22872
    22873
    22874
    22875
    22876
    22877
    22878
    22879
    22880
    22881
    22882
    22883
    22884
    22885
    22886
    22887
    22888
    22889
    22890
    22891
    22892
    22893
    22894
    22895
    22896
    22897
    22898
    22899
    22900
    22901
    22902
    22903
    22904
    22905
    22906
    22907
    22908
    22909
    22910
    22911
    22912
    22913
    22914
    22915
    22916
    22917
    22918
    22919
    22920
    22921
    22922
    22923
    22924
    22925
    22926
    22927
    22928
    22929
    22930
    22931
    22932
    22933
    22934
    22935
    22936
    22937
    22938
    22939
    22940
    22941
    22942
    22943
    22944
    22945
    22946
    22947
    22948
    22949
    22950
    22951
    22952
    22953
    22954
    22955
    22956
    22957
    22958
    22959
    22960
    22961
    22962
    22963
    22964
    22965
    22966
    22967
    22968
    22969
    22970
    22971
    22972
    22973
    22974
    22975
    22976
    22977
    22978
    22979
    22980
    22981
    22982
    22983
    22984
    22985
    22986
    22987
    22988
    22989
    22990
    22991
    22992
    22993
    22994
    22995
    22996
    22997
    22998
    22999
    23000
    23001
    23002
    23003
    23004
    23005
    23006
    23007
    23008
    23009
    23010
    23011
    23012
    23013
    23014
    23015
    23016
    23017
    23018
    23019
    23020
    23021
    23022
    23023
    23024
    23025
    23026
    23027
    23028
    23029
    23030
    23031
    23032
    23033
    23034
    23035
    23036
    23037
    23038
    23039
    23040
    23041
    23042
    23043
    23044
    23045
    23046
    23047
    23048
    23049
    23050
    23051
    23052
    23053
    23054
    23055
    23056
    23057
    23058
    23059
    23060
    23061
    23062
    23063
    23064
    23065
    23066
    23067
    23068
    23069
    23070
    23071
    23072
    23073
    23074
    23075
    23076
    23077
    23078
    23079
    23080
    23081
    23082
    23083
    23084
    23085
    23086
    23087
    23088
    23089
    23090
    23091
    23092
    23093
    23094
    23095
    23096
    23097
    23098
    23099
    23100
    23101
    23102
    23103
    23104
    23105
    23106
    23107
    23108
    23109
    23110
    23111
    23112
    23113
    23114
    23115
    23116
    23117
    23118
    23119
    23120
    23121
    23122
    23123
    23124
    23125
    23126
    23127
    23128
    23129
    23130
    23131
    23132
    23133
    23134
    23135
    23136
    23137
    23138
    23139
    23140
    23141
    23142
    23143
    23144
    23145
    23146
    23147
    23148
    23149
    23150
    23151
    23152
    23153
    23154
    23155
    23156
    23157
    23158
    23159
    23160
    23161
    23162
    23163
    23164
    23165
    23166
    23167
    23168
    23169
    23170
    23171
    23172
    23173
    23174
    23175
    23176
    23177
    23178
    23179
    23180
    23181
    23182
    23183
    23184
    23185
    23186
    23187
    23188
    23189
    23190
    23191
    23192
    23193
    23194
    23195
    23196
    23197
    23198
    23199
    23200
    23201
    23202
    23203
    23204
    23205
    23206
    23207
    23208
    23209
    23210
    23211
    23212
    23213
    23214
    23215
    23216
    23217
    23218
    23219
    23220
    23221
    23222
    23223
    23224
    23225
    23226
    23227
    23228
    23229
    23230
    23231
    23232
    23233
    23234
    23235
    23236
    23237
    23238
    23239
    23240
    23241
    23242
    23243
    23244
    23245
    23246
    23247
    23248
    23249
    23250
    23251
    23252
    23253
    23254
    23255
    23256
    23257
    23258
    23259
    23260
    23261
    23262
    23263
    23264
    23265
    23266
    23267
    23268
    23269
    23270
    23271
    23272
    23273
    23274
    23275
    23276
    23277
    23278
    23279
    23280
    23281
    23282
    23283
    23284
    23285
    23286
    23287
    23288
    23289
    23290
    23291
    23292
    23293
    23294
    23295
    23296
    23297
    23298
    23299
    23300
    23301
    23302
    23303
    23304
    23305
    23306
    23307
    23308
    23309
    23310
    23311
    23312
    23313
    23314
    23315
    23316
    23317
    23318
    23319
    23320
    23321
    23322
    23323
    23324
    23325
    23326
    23327
    23328
    23329
    23330
    23331
    23332
    23333
    23334
    23335
    23336
    23337
    23338
    23339
    23340
    23341
    23342
    23343
    23344
    23345
    23346
    23347
    23348
    23349
    23350
    23351
    23352
    23353
    23354
    23355
    23356
    23357
    23358
    23359
    23360
    23361
    23362
    23363
    23364
    23365
    23366
    23367
    23368
    23369
    23370
    23371
    23372
    23373
    23374
    23375
    23376
    23377
    23378
    23379
    23380
    23381
    23382
    23383
    23384
    23385
    23386
    23387
    23388
    23389
    23390
    23391
    23392
    23393
    23394
    23395
    23396
    23397
    23398
    23399
    23400
    23401
    23402
    23403
    23404
    23405
    23406
    23407
    23408
    23409
    23410
    23411
    23412
    23413
    23414
    23415
    23416
    23417
    23418
    23419
    23420
    23421
    23422
    23423
    23424
    23425
    23426
    23427
    23428
    23429
    23430
    23431
    23432
    23433
    23434
    23435
    23436
    23437
    23438
    23439
    23440
    23441
    23442
    23443
    23444
    23445
    23446
    23447
    23448
    23449
    23450
    23451
    23452
    23453
    23454
    23455
    23456
    23457
    23458
    23459
    23460
    23461
    23462
    23463
    23464
    23465
    23466
    23467
    23468
    23469
    23470
    23471
    23472
    23473
    23474
    23475
    23476
    23477
    23478
    23479
    23480
    23481
    23482
    23483
    23484
    23485
    23486
    23487
    23488
    23489
    23490
    23491
    23492
    23493
    23494
    23495
    23496
    23497
    23498
    23499
    23500
    23501
    23502
    23503
    23504
    23505
    23506
    23507
    23508
    23509
    23510
    23511
    23512
    23513
    23514
    23515
    23516
    23517
    23518
    23519
    23520
    23521
    23522
    23523
    23524
    23525
    23526
    23527
    23528
    23529
    23530
    23531
    23532
    23533
    23534
    23535
    23536
    23537
    23538
    23539
    23540
    23541
    23542
    23543
    23544
    23545
    23546
    23547
    23548
    23549
    23550
    23551
    23552
    23553
    23554
    23555
    23556
    23557
    23558
    23559
    23560
    23561
    23562
    23563
    23564
    23565
    23566
    23567
    23568
    23569
    23570
    23571
    23572
    23573
    23574
    23575
    23576
    23577
    23578
    23579
    23580
    23581
    23582
    23583
    23584
    23585
    23586
    23587
    23588
    23589
    23590
    23591
    23592
    23593
    23594
    23595
    23596
    23597
    23598
    23599
    23600
    23601
    23602
    23603
    23604
    23605
    23606
    23607
    23608
    23609
    23610
    23611
    23612
    23613
    23614
    23615
    23616
    23617
    23618
    23619
    23620
    23621
    23622
    23623
    23624
    23625
    23626
    23627
    23628
    23629
    23630
    23631
    23632
    23633
    23634
    23635
    23636
    23637
    23638
    23639
    23640
    23641
    23642
    23643
    23644
    23645
    23646
    23647
    23648
    23649
    23650
    23651
    23652
    23653
    23654
    23655
    23656
    23657
    23658
    23659
    23660
    23661
    23662
    23663
    23664
    23665
    23666
    23667
    23668
    23669
    23670
    23671
    23672
    23673
    23674
    23675
    23676
    23677
    23678
    23679
    23680
    23681
    23682
    23683
    23684
    23685
    23686
    23687
    23688
    23689
    23690
    23691
    23692
    23693
    23694
    23695
    23696
    23697
    23698
    23699
    23700
    23701
    23702
    23703
    23704
    23705
    23706
    23707
    23708
    23709
    23710
    23711
    23712
    23713
    23714
    23715
    23716
    23717
    23718
    23719
    23720
    23721
    23722
    23723
    23724
    23725
    23726
    23727
    23728
    23729
    23730
    23731
    23732
    23733
    23734
    23735
    23736
    23737
    23738
    23739
    23740
    23741
    23742
    23743
    23744
    23745
    23746
    23747
    23748
    23749
    23750
    23751
    23752
    23753
    23754
    23755
    23756
    23757
    23758
    23759
    23760
    23761
    23762
    23763
    23764
    23765
    23766
    23767
    23768
    23769
    23770
    23771
    23772
    23773
    23774
    23775
    23776
    23777
    23778
    23779
    23780
    23781
    23782
    23783
    23784
    23785
    23786
    23787
    23788
    23789
    23790
    23791
    23792
    23793
    23794
    23795
    23796
    23797
    23798
    23799
    23800
    23801
    23802
    23803
    23804
    23805
    23806
    23807
    23808
    23809
    23810
    23811
    23812
    23813
    23814
    23815
    23816
    23817
    23818
    23819
    23820
    23821
    23822
    23823
    23824
    23825
    23826
    23827
    23828
    23829
    23830
    23831
    23832
    23833
    23834
    23835
    23836
    23837
    23838
    23839
    23840
    23841
    23842
    23843
    23844
    23845
    23846
    23847
    23848
    23849
    23850
    23851
    23852
    23853
    23854
    23855
    23856
    23857
    23858
    23859
    23860
    23861
    23862
    23863
    23864
    23865
    23866
    23867
    23868
    23869
    23870
    23871
    23872
    23873
    23874
    23875
    23876
    23877
    23878
    23879
    23880
    23881
    23882
    23883
    23884
    23885
    23886
    23887
    23888
    23889
    23890
    23891
    23892
    23893
    23894
    23895
    23896
    23897
    23898
    23899
    23900
    23901
    23902
    23903
    23904
    23905
    23906
    23907
    23908
    23909
    23910
    23911
    23912
    23913
    23914
    23915
    23916
    23917
    23918
    23919
    23920
    23921
    23922
    23923
    23924
    23925
    23926
    23927
    23928
    23929
    23930
    23931
    23932
    23933
    23934
    23935
    23936
    23937
    23938
    23939
    23940
    23941
    23942
    23943
    23944
    23945
    23946
    23947
    23948
    23949
    23950
    23951
    23952
    23953
    23954
    23955
    23956
    23957
    23958
    23959
    23960
    23961
    23962
    23963
    23964
    23965
    23966
    23967
    23968
    23969
    23970
    23971
    23972
    23973
    23974
    23975
    23976
    23977
    23978
    23979
    23980
    23981
    23982
    23983
    23984
    23985
    23986
    23987
    23988
    23989
    23990
    23991
    23992
    23993
    23994
    23995
    23996
    23997
    23998
    23999
    24000
    24001
    24002
    24003
    24004
    24005
    24006
    24007
    24008
    24009
    24010
    24011
    24012
    24013
    24014
    24015
    24016
    24017
    24018
    24019
    24020
    24021
    24022
    24023
    24024
    24025
    24026
    24027
    24028
    24029
    24030
    24031
    24032
    24033
    24034
    24035
    24036
    24037
    24038
    24039
    24040
    24041
    24042
    24043
    24044
    24045
    24046
    24047
    24048
    24049
    24050
    24051
    24052
    24053
    24054
    24055
    24056
    24057
    24058
    24059
    24060
    24061
    24062
    24063
    24064
    24065
    24066
    24067
    24068
    24069
    24070
    24071
    24072
    24073
    24074
    24075
    24076
    24077
    24078
    24079
    24080
    24081
    24082
    24083
    24084
    24085
    24086
    24087
    24088
    24089
    24090
    24091
    24092
    24093
    24094
    24095
    24096
    24097
    24098
    24099
    24100
    24101
    24102
    24103
    24104
    24105
    24106
    24107
    24108
    24109
    24110
    24111
    24112
    24113
    24114
    24115
    24116
    24117
    24118
    24119
    24120
    24121
    24122
    24123
    24124
    24125
    24126
    24127
    24128
    24129
    24130
    24131
    24132
    24133
    24134
    24135
    24136
    24137
    24138
    24139
    24140
    24141
    24142
    24143
    24144
    24145
    24146
    24147
    24148
    24149
    24150
    24151
    24152
    24153
    24154
    24155
    24156
    24157
    24158
    24159
    24160
    24161
    24162
    24163
    24164
    24165
    24166
    24167
    24168
    24169
    24170
    24171
    24172
    24173
    24174
    24175
    24176
    24177
    24178
    24179
    24180
    24181
    24182
    24183
    24184
    24185
    24186
    24187
    24188
    24189
    24190
    24191
    24192
    24193
    24194
    24195
    24196
    24197
    24198
    24199
    24200
    24201
    24202
    24203
    24204
    24205
    24206
    24207
    24208
    24209
    24210
    24211
    24212
    24213
    24214
    24215
    24216
    24217
    24218
    24219
    24220
    24221
    24222
    24223
    24224
    24225
    24226
    24227
    24228
    24229
    24230
    24231
    24232
    24233
    24234
    24235
    24236
    24237
    24238
    24239
    24240
    24241
    24242
    24243
    24244
    24245
    24246
    24247
    24248
    24249
    24250
    24251
    24252
    24253
    24254
    24255
    24256
    24257
    24258
    24259
    24260
    24261
    24262
    24263
    24264
    24265
    24266
    24267
    24268
    24269
    24270
    24271
    24272
    24273
    24274
    24275
    24276
    24277
    24278
    24279
    24280
    24281
    24282
    24283
    24284
    24285
    24286
    24287
    24288
    24289
    24290
    24291
    24292
    24293
    24294
    24295
    24296
    24297
    24298
    24299
    24300
    24301
    24302
    24303
    24304
    24305
    24306
    24307
    24308
    24309
    24310
    24311
    24312
    24313
    24314
    24315
    24316
    24317
    24318
    24319
    24320
    24321
    24322
    24323
    24324
    24325
    24326
    24327
    24328
    24329
    24330
    24331
    24332
    24333
    24334
    24335
    24336
    24337
    24338
    24339
    24340
    24341
    24342
    24343
    24344
    24345
    24346
    24347
    24348
    24349
    24350
    24351
    24352
    24353
    24354
    24355
    24356
    24357
    24358
    24359
    24360
    24361
    24362
    24363
    24364
    24365
    24366
    24367
    24368
    24369
    24370
    24371
    24372
    24373
    24374
    24375
    24376
    24377
    24378
    24379
    24380
    24381
    24382
    24383
    24384
    24385
    24386
    24387
    24388
    24389
    24390
    24391
    24392
    24393
    24394
    24395
    24396
    24397
    24398
    24399
    24400
    24401
    24402
    24403
    24404
    24405
    24406
    24407
    24408
    24409
    24410
    24411
    24412
    24413
    24414
    24415
    24416
    24417
    24418
    24419
    24420
    24421
    24422
    24423
    24424
    24425
    24426
    24427
    24428
    24429
    24430
    24431
    24432
    24433
    24434
    24435
    24436
    24437
    24438
    24439
    24440
    24441
    24442
    24443
    24444
    24445
    24446
    24447
    24448
    24449
    24450
    24451
    24452
    24453
    24454
    24455
    24456
    24457
    24458
    24459
    24460
    24461
    24462
    24463
    24464
    24465
    24466
    24467
    24468
    24469
    24470
    24471
    24472
    24473
    24474
    24475
    24476
    24477
    24478
    24479
    24480
    24481
    24482
    24483
    24484
    24485
    24486
    24487
    24488
    24489
    24490
    24491
    24492
    24493
    24494
    24495
    24496
    24497
    24498
    24499
    24500
    24501
    24502
    24503
    24504
    24505
    24506
    24507
    24508
    24509
    24510
    24511
    24512
    24513
    24514
    24515
    24516
    24517
    24518
    24519
    24520
    24521
    24522
    24523
    24524
    24525
    24526
    24527
    24528
    24529
    24530
    24531
    24532
    24533
    24534
    24535
    24536
    24537
    24538
    24539
    24540
    24541
    24542
    24543
    24544
    24545
    24546
    24547
    24548
    24549
    24550
    24551
    24552
    24553
    24554
    24555
    24556
    24557
    24558
    24559
    24560
    24561
    24562
    24563
    24564
    24565
    24566
    24567
    24568
    24569
    24570
    24571
    24572
    24573
    24574
    24575
    24576
    24577
    24578
    24579
    24580
    24581
    24582
    24583
    24584
    24585
    24586
    24587
    24588
    24589
    24590
    24591
    24592
    24593
    24594
    24595
    24596
    24597
    24598
    24599
    24600
    24601
    24602
    24603
    24604
    24605
    24606
    24607
    24608
    24609
    24610
    24611
    24612
    24613
    24614
    24615
    24616
    24617
    24618
    24619
    24620
    24621
    24622
    24623
    24624
    24625
    24626
    24627
    24628
    24629
    24630
    24631
    24632
    24633
    24634
    24635
    24636
    24637
    24638
    24639
    24640
    24641
    24642
    24643
    24644
    24645
    24646
    24647
    24648
    24649
    24650
    24651
    24652
    24653
    24654
    24655
    24656
    24657
    24658
    24659
    24660
    24661
    24662
    24663
    24664
    24665
    24666
    24667
    24668
    24669
    24670
    24671
    24672
    24673
    24674
    24675
    24676
    24677
    24678
    24679
    24680
    24681
    24682
    24683
    24684
    24685
    24686
    24687
    24688
    24689
    24690
    24691
    24692
    24693
    24694
    24695
    24696
    24697
    24698
    24699
    24700
    24701
    24702
    24703
    24704
    24705
    24706
    24707
    24708
    24709
    24710
    24711
    24712
    24713
    24714
    24715
    24716
    24717
    24718
    24719
    24720
    24721
    24722
    24723
    24724
    24725
    24726
    24727
    24728
    24729
    24730
    24731
    24732
    24733
    24734
    24735
    24736
    24737
    24738
    24739
    24740
    24741
    24742
    24743
    24744
    24745
    24746
    24747
    24748
    24749
    24750
    24751
    24752
    24753
    24754
    24755
    24756
    24757
    24758
    24759
    24760
    24761
    24762
    24763
    24764
    24765
    24766
    24767
    24768
    24769
    24770
    24771
    24772
    24773
    24774
    24775
    24776
    24777
    24778
    24779
    24780
    24781
    24782
    24783
    24784
    24785
    24786
    24787
    24788
    24789
    24790
    24791
    24792
    24793
    24794
    24795
    24796
    24797
    24798
    24799
    24800
    24801
    24802
    24803
    24804
    24805
    24806
    24807
    24808
    24809
    24810
    24811
    24812
    24813
    24814
    24815
    24816
    24817
    24818
    24819
    24820
    24821
    24822
    24823
    24824
    24825
    24826
    24827
    24828
    24829
    24830
    24831
    24832
    24833
    24834
    24835
    24836
    24837
    24838
    24839
    24840
    24841
    24842
    24843
    24844
    24845
    24846
    24847
    24848
    24849
    24850
    24851
    24852
    24853
    24854
    24855
    24856
    24857
    24858
    24859
    24860
    24861
    24862
    24863
    24864
    24865
    24866
    24867
    24868
    24869
    24870
    24871
    24872
    24873
    24874
    24875
    24876
    24877
    24878
    24879
    24880
    24881
    24882
    24883
    24884
    24885
    24886
    24887
    24888
    24889
    24890
    24891
    24892
    24893
    24894
    24895
    24896
    24897
    24898
    24899
    24900
    24901
    24902
    24903
    24904
    24905
    24906
    24907
    24908
    24909
    24910
    24911
    24912
    24913
    24914
    24915
    24916
    24917
    24918
    24919
    24920
    24921
    24922
    24923
    24924
    24925
    24926
    24927
    24928
    24929
    24930
    24931
    24932
    24933
    24934
    24935
    24936
    24937
    24938
    24939
    24940
    24941
    24942
    24943
    24944
    24945
    24946
    24947
    24948
    24949
    24950
    24951
    24952
    24953
    24954
    24955
    24956
    24957
    24958
    24959
    24960
    24961
    24962
    24963
    24964
    24965
    24966
    24967
    24968
    24969
    24970
    24971
    24972
    24973
    24974
    24975
    24976
    24977
    24978
    24979
    24980
    24981
    24982
    24983
    24984
    24985
    24986
    24987
    24988
    24989
    24990
    24991
    24992
    24993
    24994
    24995
    24996
    24997
    24998
    24999
    25000
    25001
    25002
    25003
    25004
    25005
    25006
    25007
    25008
    25009
    25010
    25011
    25012
    25013
    25014
    25015
    25016
    25017
    25018
    25019
    25020
    25021
    25022
    25023
    25024
    25025
    25026
    25027
    25028
    25029
    25030
    25031
    25032
    25033
    25034
    25035
    25036
    25037
    25038
    25039
    25040
    25041
    25042
    25043
    25044
    25045
    25046
    25047
    25048
    25049
    25050
    25051
    25052
    25053
    25054
    25055
    25056
    25057
    25058
    25059
    25060
    25061
    25062
    25063
    25064
    25065
    25066
    25067
    25068
    25069
    25070
    25071
    25072
    25073
    25074
    25075
    25076
    25077
    25078
    25079
    25080
    25081
    25082
    25083
    25084
    25085
    25086
    25087
    25088
    25089
    25090
    25091
    25092
    25093
    25094
    25095
    25096
    25097
    25098
    25099
    25100
    25101
    25102
    25103
    25104
    25105
    25106
    25107
    25108
    25109
    25110
    25111
    25112
    25113
    25114
    25115
    25116
    25117
    25118
    25119
    25120
    25121
    25122
    25123
    25124
    25125
    25126
    25127
    25128
    25129
    25130
    25131
    25132
    25133
    25134
    25135
    25136
    25137
    25138
    25139
    25140
    25141
    25142
    25143
    25144
    25145
    25146
    25147
    25148
    25149
    25150
    25151
    25152
    25153
    25154
    25155
    25156
    25157
    25158
    25159
    25160
    25161
    25162
    25163
    25164
    25165
    25166
    25167
    25168
    25169
    25170
    25171
    25172
    25173
    25174
    25175
    25176
    25177
    25178
    25179
    25180
    25181
    25182
    25183
    25184
    25185
    25186
    25187
    25188
    25189
    25190
    25191
    25192
    25193
    25194
    25195
    25196
    25197
    25198
    25199
    25200
    25201
    25202
    25203
    25204
    25205
    25206
    25207
    25208
    25209
    25210
    25211
    25212
    25213
    25214
    25215
    25216
    25217
    25218
    25219
    25220
    25221
    25222
    25223
    25224
    25225
    25226
    25227
    25228
    25229
    25230
    25231
    25232
    25233
    25234
    25235
    25236
    25237
    25238
    25239
    25240
    25241
    25242
    25243
    25244
    25245
    25246
    25247
    25248
    25249
    25250
    25251
    25252
    25253
    25254
    25255
    25256
    25257
    25258
    25259
    25260
    25261
    25262
    25263
    25264
    25265
    25266
    25267
    25268
    25269
    25270
    25271
    25272
    25273
    25274
    25275
    25276
    25277
    25278
    25279
    25280
    25281
    25282
    25283
    25284
    25285
    25286
    25287
    25288
    25289
    25290
    25291
    25292
    25293
    25294
    25295
    25296
    25297
    25298
    25299
    25300
    25301
    25302
    25303
    25304
    25305
    25306
    25307
    25308
    25309
    25310
    25311
    25312
    25313
    25314
    25315
    25316
    25317
    25318
    25319
    25320
    25321
    25322
    25323
    25324
    25325
    25326
    25327
    25328
    25329
    25330
    25331
    25332
    25333
    25334
    25335
    25336
    25337
    25338
    25339
    25340
    25341
    25342
    25343
    25344
    25345
    25346
    25347
    25348
    25349
    25350
    25351
    25352
    25353
    25354
    25355
    25356
    25357
    25358
    25359
    25360
    25361
    25362
    25363
    25364
    25365
    25366
    25367
    25368
    25369
    25370
    25371
    25372
    25373
    25374
    25375
    25376
    25377
    25378
    25379
    25380
    25381
    25382
    25383
    25384
    25385
    25386
    25387
    25388
    25389
    25390
    25391
    25392
    25393
    25394
    25395
    25396
    25397
    25398
    25399
    25400
    25401
    25402
    25403
    25404
    25405
    25406
    25407
    25408
    25409
    25410
    25411
    25412
    25413
    25414
    25415
    25416
    25417
    25418
    25419
    25420
    25421
    25422
    25423
    25424
    25425
    25426
    25427
    25428
    25429
    25430
    25431
    25432
    25433
    25434
    25435
    25436
    25437
    25438
    25439
    25440
    25441
    25442
    25443
    25444
    25445
    25446
    25447
    25448
    25449
    25450
    25451
    25452
    25453
    25454
    25455
    25456
    25457
    25458
    25459
    25460
    25461
    25462
    25463
    25464
    25465
    25466
    25467
    25468
    25469
    25470
    25471
    25472
    25473
    25474
    25475
    25476
    25477
    25478
    25479
    25480
    25481
    25482
    25483
    25484
    25485
    25486
    25487
    25488
    25489
    25490
    25491
    25492
    25493
    25494
    25495
    25496
    25497
    25498
    25499
    25500
    25501
    25502
    25503
    25504
    25505
    25506
    25507
    25508
    25509
    25510
    25511
    25512
    25513
    25514
    25515
    25516
    25517
    25518
    25519
    25520
    25521
    25522
    25523
    25524
    25525
    25526
    25527
    25528
    25529
    25530
    25531
    25532
    25533
    25534
    25535
    25536
    25537
    25538
    25539
    25540
    25541
    25542
    25543
    25544
    25545
    25546
    25547
    25548
    25549
    25550
    25551
    25552
    25553
    25554
    25555
    25556
    25557
    25558
    25559
    25560
    25561
    25562
    25563
    25564
    25565
    25566
    25567
    25568
    25569
    25570
    25571
    25572
    25573
    25574
    25575
    25576
    25577
    25578
    25579
    25580
    25581
    25582
    25583
    25584
    25585
    25586
    25587
    25588
    25589
    25590
    25591
    25592
    25593
    25594
    25595
    25596
    25597
    25598
    25599
    25600
    25601
    25602
    25603
    25604
    25605
    25606
    25607
    25608
    25609
    25610
    25611
    25612
    25613
    25614
    25615
    25616
    25617
    25618
    25619
    25620
    25621
    25622
    25623
    25624
    25625
    25626
    25627
    25628
    25629
    25630
    25631
    25632
    25633
    25634
    25635
    25636
    25637
    25638
    25639
    25640
    25641
    25642
    25643
    25644
    25645
    25646
    25647
    25648
    25649
    25650
    25651
    25652
    25653
    25654
    25655
    25656
    25657
    25658
    25659
    25660
    25661
    25662
    25663
    25664
    25665
    25666
    25667
    25668
    25669
    25670
    25671
    25672
    25673
    25674
    25675
    25676
    25677
    25678
    25679
    25680
    25681
    25682
    25683
    25684
    25685
    25686
    25687
    25688
    25689
    25690
    25691
    25692
    25693
    25694
    25695
    25696
    25697
    25698
    25699
    25700
    25701
    25702
    25703
    25704
    25705
    25706
    25707
    25708
    25709
    25710
    25711
    25712
    25713
    25714
    25715
    25716
    25717
    25718
    25719
    25720
    25721
    25722
    25723
    25724
    25725
    25726
    25727
    25728
    25729
    25730
    25731
    25732
    25733
    25734
    25735
    25736
    25737
    25738
    25739
    25740
    25741
    25742
    25743
    25744
    25745
    25746
    25747
    25748
    25749
    25750
    25751
    25752
    25753
    25754
    25755
    25756
    25757
    25758
    25759
    25760
    25761
    25762
    25763
    25764
    25765
    25766
    25767
    25768
    25769
    25770
    25771
    25772
    25773
    25774
    25775
    25776
    25777
    25778
    25779
    25780
    25781
    25782
    25783
    25784
    25785
    25786
    25787
    25788
    25789
    25790
    25791
    25792
    25793
    25794
    25795
    25796
    25797
    25798
    25799
    25800
    25801
    25802
    25803
    25804
    25805
    25806
    25807
    25808
    25809
    25810
    25811
    25812
    25813
    25814
    25815
    25816
    25817
    25818
    25819
    25820
    25821
    25822
    25823
    25824
    25825
    25826
    25827
    25828
    25829
    25830
    25831
    25832
    25833
    25834
    25835
    25836
    25837
    25838
    25839
    25840
    25841
    25842
    25843
    25844
    25845
    25846
    25847
    25848
    25849
    25850
    25851
    25852
    25853
    25854
    25855
    25856
    25857
    25858
    25859
    25860
    25861
    25862
    25863
    25864
    25865
    25866
    25867
    25868
    25869
    25870
    25871
    25872
    25873
    25874
    25875
    25876
    25877
    25878
    25879
    25880
    25881
    25882
    25883
    25884
    25885
    25886
    25887
    25888
    25889
    25890
    25891
    25892
    25893
    25894
    25895
    25896
    25897
    25898
    25899
    25900
    25901
    25902
    25903
    25904
    25905
    25906
    25907
    25908
    25909
    25910
    25911
    25912
    25913
    25914
    25915
    25916
    25917
    25918
    25919
    25920
    25921
    25922
    25923
    25924
    25925
    25926
    25927
    25928
    25929
    25930
    25931
    25932
    25933
    25934
    25935
    25936
    25937
    25938
    25939
    25940
    25941
    25942
    25943
    25944
    25945
    25946
    25947
    25948
    25949
    25950
    25951
    25952
    25953
    25954
    25955
    25956
    25957
    25958
    25959
    25960
    25961
    25962
    25963
    25964
    25965
    25966
    25967
    25968
    25969
    25970
    25971
    25972
    25973
    25974
    25975
    25976
    25977
    25978
    25979
    25980
    25981
    25982
    25983
    25984
    25985
    25986
    25987
    25988
    25989
    25990
    25991
    25992
    25993
    25994
    25995
    25996
    25997
    25998
    25999
    26000
    26001
    26002
    26003
    26004
    26005
    26006
    26007
    26008
    26009
    26010
    26011
    26012
    26013
    26014
    26015
    26016
    26017
    26018
    26019
    26020
    26021
    26022
    26023
    26024
    26025
    26026
    26027
    26028
    26029
    26030
    26031
    26032
    26033
    26034
    26035
    26036
    26037
    26038
    26039
    26040
    26041
    26042
    26043
    26044
    26045
    26046
    26047
    26048
    26049
    26050
    26051
    26052
    26053
    26054
    26055
    26056
    26057
    26058
    26059
    26060
    26061
    26062
    26063
    26064
    26065
    26066
    26067
    26068
    26069
    26070
    26071
    26072
    26073
    26074
    26075
    26076
    26077
    26078
    26079
    26080
    26081
    26082
    26083
    26084
    26085
    26086
    26087
    26088
    26089
    26090
    26091
    26092
    26093
    26094
    26095
    26096
    26097
    26098
    26099
    26100
    26101
    26102
    26103
    26104
    26105
    26106
    26107
    26108
    26109
    26110
    26111
    26112
    26113
    26114
    26115
    26116
    26117
    26118
    26119
    26120
    26121
    26122
    26123
    26124
    26125
    26126
    26127
    26128
    26129
    26130
    26131
    26132
    26133
    26134
    26135
    26136
    26137
    26138
    26139
    26140
    26141
    26142
    26143
    26144
    26145
    26146
    26147
    26148
    26149
    26150
    26151
    26152
    26153
    26154
    26155
    26156
    26157
    26158
    26159
    26160
    26161
    26162
    26163
    26164
    26165
    26166
    26167
    26168
    26169
    26170
    26171
    26172
    26173
    26174
    26175
    26176
    26177
    26178
    26179
    26180
    26181
    26182
    26183
    26184
    26185
    26186
    26187
    26188
    26189
    26190
    26191
    26192
    26193
    26194
    26195
    26196
    26197
    26198
    26199
    26200
    26201
    26202
    26203
    26204
    26205
    26206
    26207
    26208
    26209
    26210
    26211
    26212
    26213
    26214
    26215
    26216
    26217
    26218
    26219
    26220
    26221
    26222
    26223
    26224
    26225
    26226
    26227
    26228
    26229
    26230
    26231
    26232
    26233
    26234
    26235
    26236
    26237
    26238
    26239
    26240
    26241
    26242
    26243
    26244
    26245
    26246
    26247
    26248
    26249
    26250
    26251
    26252
    26253
    26254
    26255
    26256
    26257
    26258
    26259
    26260
    26261
    26262
    26263
    26264
    26265
    26266
    26267
    26268
    26269
    26270
    26271
    26272
    26273
    26274
    26275
    26276
    26277
    26278
    26279
    26280
    26281
    26282
    26283
    26284
    26285
    26286
    26287
    26288
    26289
    26290
    26291
    26292
    26293
    26294
    26295
    26296
    26297
    26298
    26299
    26300
    26301
    26302
    26303
    26304
    26305
    26306
    26307
    26308
    26309
    26310
    26311
    26312
    26313
    26314
    26315
    26316
    26317
    26318
    26319
    26320
    26321
    26322
    26323
    26324
    26325
    26326
    26327
    26328
    26329
    26330
    26331
    26332
    26333
    26334
    26335
    26336
    26337
    26338
    26339
    26340
    26341
    26342
    26343
    26344
    26345
    26346
    26347
    26348
    26349
    26350
    26351
    26352
    26353
    26354
    26355
    26356
    26357
    26358
    26359
    26360
    26361
    26362
    26363
    26364
    26365
    26366
    26367
    26368
    26369
    26370
    26371
    26372
    26373
    26374
    26375
    26376
    26377
    26378
    26379
    26380
    26381
    26382
    26383
    26384
    26385
    26386
    26387
    26388
    26389
    26390
    26391
    26392
    26393
    26394
    26395
    26396
    26397
    26398
    26399
    26400
    26401
    26402
    26403
    26404
    26405
    26406
    26407
    26408
    26409
    26410
    26411
    26412
    26413
    26414
    26415
    26416
    26417
    26418
    26419
    26420
    26421
    26422
    26423
    26424
    26425
    26426
    26427
    26428
    26429
    26430
    26431
    26432
    26433
    26434
    26435
    26436
    26437
    26438
    26439
    26440
    26441
    26442
    26443
    26444
    26445
    26446
    26447
    26448
    26449
    26450
    26451
    26452
    26453
    26454
    26455
    26456
    26457
    26458
    26459
    26460
    26461
    26462
    26463
    26464
    26465
    26466
    26467
    26468
    26469
    26470
    26471
    26472
    26473
    26474
    26475
    26476
    26477
    26478
    26479
    26480
    26481
    26482
    26483
    26484
    26485
    26486
    26487
    26488
    26489
    26490
    26491
    26492
    26493
    26494
    26495
    26496
    26497
    26498
    26499
    26500
    26501
    26502
    26503
    26504
    26505
    26506
    26507
    26508
    26509
    26510
    26511
    26512
    26513
    26514
    26515
    26516
    26517
    26518
    26519
    26520
    26521
    26522
    26523
    26524
    26525
    26526
    26527
    26528
    26529
    26530
    26531
    26532
    26533
    26534
    26535
    26536
    26537
    26538
    26539
    26540
    26541
    26542
    26543
    26544
    26545
    26546
    26547
    26548
    26549
    26550
    26551
    26552
    26553
    26554
    26555
    26556
    26557
    26558
    26559
    26560
    26561
    26562
    26563
    26564
    26565
    26566
    26567
    26568
    26569
    26570
    26571
    26572
    26573
    26574
    26575
    26576
    26577
    26578
    26579
    26580
    26581
    26582
    26583
    26584
    26585
    26586
    26587
    26588
    26589
    26590
    26591
    26592
    26593
    26594
    26595
    26596
    26597
    26598
    26599
    26600
    26601
    26602
    26603
    26604
    26605
    26606
    26607
    26608
    26609
    26610
    26611
    26612
    26613
    26614
    26615
    26616
    26617
    26618
    26619
    26620
    26621
    26622
    26623
    26624
    26625
    26626
    26627
    26628
    26629
    26630
    26631
    26632
    26633
    26634
    26635
    26636
    26637
    26638
    26639
    26640
    26641
    26642
    26643
    26644
    26645
    26646
    26647
    26648
    26649
    26650
    26651
    26652
    26653
    26654
    26655
    26656
    26657
    26658
    26659
    26660
    26661
    26662
    26663
    26664
    26665
    26666
    26667
    26668
    26669
    26670
    26671
    26672
    26673
    26674
    26675
    26676
    26677
    26678
    26679
    26680
    26681
    26682
    26683
    26684
    26685
    26686
    26687
    26688
    26689
    26690
    26691
    26692
    26693
    26694
    26695
    26696
    26697
    26698
    26699
    26700
    26701
    26702
    26703
    26704
    26705
    26706
    26707
    26708
    26709
    26710
    26711
    26712
    26713
    26714
    26715
    26716
    26717
    26718
    26719
    26720
    26721
    26722
    26723
    26724
    26725
    26726
    26727
    26728
    26729
    26730
    26731
    26732
    26733
    26734
    26735
    26736
    26737
    26738
    26739
    26740
    26741
    26742
    26743
    26744
    26745
    26746
    26747
    26748
    26749
    26750
    26751
    26752
    26753
    26754
    26755
    26756
    26757
    26758
    26759
    26760
    26761
    26762
    26763
    26764
    26765
    26766
    26767
    26768
    26769
    26770
    26771
    26772
    26773
    26774
    26775
    26776
    26777
    26778
    26779
    26780
    26781
    26782
    26783
    26784
    26785
    26786
    26787
    26788
    26789
    26790
    26791
    26792
    26793
    26794
    26795
    26796
    26797
    26798
    26799
    26800
    26801
    26802
    26803
    26804
    26805
    26806
    26807
    26808
    26809
    26810
    26811
    26812
    26813
    26814
    26815
    26816
    26817
    26818
    26819
    26820
    26821
    26822
    26823
    26824
    26825
    26826
    26827
    26828
    26829
    26830
    26831
    26832
    26833
    26834
    26835
    26836
    26837
    26838
    26839
    26840
    26841
    26842
    26843
    26844
    26845
    26846
    26847
    26848
    26849
    26850
    26851
    26852
    26853
    26854
    26855
    26856
    26857
    26858
    26859
    26860
    26861
    26862
    26863
    26864
    26865
    26866
    26867
    26868
    26869
    26870
    26871
    26872
    26873
    26874
    26875
    26876
    26877
    26878
    26879
    26880
    26881
    26882
    26883
    26884
    26885
    26886
    26887
    26888
    26889
    26890
    26891
    26892
    26893
    26894
    26895
    26896
    26897
    26898
    26899
    26900
    26901
    26902
    26903
    26904
    26905
    26906
    26907
    26908
    26909
    26910
    26911
    26912
    26913
    26914
    26915
    26916
    26917
    26918
    26919
    26920
    26921
    26922
    26923
    26924
    26925
    26926
    26927
    26928
    26929
    26930
    26931
    26932
    26933
    26934
    26935
    26936
    26937
    26938
    26939
    26940
    26941
    26942
    26943
    26944
    26945
    26946
    26947
    26948
    26949
    26950
    26951
    26952
    26953
    26954
    26955
    26956
    26957
    26958
    26959
    26960
    26961
    26962
    26963
    26964
    26965
    26966
    26967
    26968
    26969
    26970
    26971
    26972
    26973
    26974
    26975
    26976
    26977
    26978
    26979
    26980
    26981
    26982
    26983
    26984
    26985
    26986
    26987
    26988
    26989
    26990
    26991
    26992
    26993
    26994
    26995
    26996
    26997
    26998
    26999
    27000
    27001
    27002
    27003
    27004
    27005
    27006
    27007
    27008
    27009
    27010
    27011
    27012
    27013
    27014
    27015
    27016
    27017
    27018
    27019
    27020
    27021
    27022
    27023
    27024
    27025
    27026
    27027
    27028
    27029
    27030
    27031
    27032
    27033
    27034
    27035
    27036
    27037
    27038
    27039
    27040
    27041
    27042
    27043
    27044
    27045
    27046
    27047
    27048
    27049
    27050
    27051
    27052
    27053
    27054
    27055
    27056
    27057
    27058
    27059
    27060
    27061
    27062
    27063
    27064
    27065
    27066
    27067
    27068
    27069
    27070
    27071
    27072
    27073
    27074
    27075
    27076
    27077
    27078
    27079
    27080
    27081
    27082
    27083
    27084
    27085
    27086
    27087
    27088
    27089
    27090
    27091
    27092
    27093
    27094
    27095
    27096
    27097
    27098
    27099
    27100
    27101
    27102
    27103
    27104
    27105
    27106
    27107
    27108
    27109
    27110
    27111
    27112
    27113
    27114
    27115
    27116
    27117
    27118
    27119
    27120
    27121
    27122
    27123
    27124
    27125
    27126
    27127
    27128
    27129
    27130
    27131
    27132
    27133
    27134
    27135
    27136
    27137
    27138
    27139
    27140
    27141
    27142
    27143
    27144
    27145
    27146
    27147
    27148
    27149
    27150
    27151
    27152
    27153
    27154
    27155
    27156
    27157
    27158
    27159
    27160
    27161
    27162
    27163
    27164
    27165
    27166
    27167
    27168
    27169
    27170
    27171
    27172
    27173
    27174
    27175
    27176
    27177
    27178
    27179
    27180
    27181
    27182
    27183
    27184
    27185
    27186
    27187
    27188
    27189
    27190
    27191
    27192
    27193
    27194
    27195
    27196
    27197
    27198
    27199
    27200
    27201
    27202
    27203
    27204
    27205
    27206
    27207
    27208
    27209
    27210
    27211
    27212
    27213
    27214
    27215
    27216
    27217
    27218
    27219
    27220
    27221
    27222
    27223
    27224
    27225
    27226
    27227
    27228
    27229
    27230
    27231
    27232
    27233
    27234
    27235
    27236
    27237
    27238
    27239
    27240
    27241
    27242
    27243
    27244
    27245
    27246
    27247
    27248
    27249
    27250
    27251
    27252
    27253
    27254
    27255
    27256
    27257
    27258
    27259
    27260
    27261
    27262
    27263
    27264
    27265
    27266
    27267
    27268
    27269
    27270
    27271
    27272
    27273
    27274
    27275
    27276
    27277
    27278
    27279
    27280
    27281
    27282
    27283
    27284
    27285
    27286
    27287
    27288
    27289
    27290
    27291
    27292
    27293
    27294
    27295
    27296
    27297
    27298
    27299
    27300
    27301
    27302
    27303
    27304
    27305
    27306
    27307
    27308
    27309
    27310
    27311
    27312
    27313
    27314
    27315
    27316
    27317
    27318
    27319
    27320
    27321
    27322
    27323
    27324
    27325
    27326
    27327
    27328
    27329
    27330
    27331
    27332
    27333
    27334
    27335
    27336
    27337
    27338
    27339
    27340
    27341
    27342
    27343
    27344
    27345
    27346
    27347
    27348
    27349
    27350
    27351
    27352
    27353
    27354
    27355
    27356
    27357
    27358
    27359
    27360
    27361
    27362
    27363
    27364
    27365
    27366
    27367
    27368
    27369
    27370
    27371
    27372
    27373
    27374
    27375
    27376
    27377
    27378
    27379
    27380
    27381
    27382
    27383
    27384
    27385
    27386
    27387
    27388
    27389
    27390
    27391
    27392
    27393
    27394
    27395
    27396
    27397
    27398
    27399
    27400
    27401
    27402
    27403
    27404
    27405
    27406
    27407
    27408
    27409
    27410
    27411
    27412
    27413
    27414
    27415
    27416
    27417
    27418
    27419
    27420
    27421
    27422
    27423
    27424
    27425
    27426
    27427
    27428
    27429
    27430
    27431
    27432
    27433
    27434
    27435
    27436
    27437
    27438
    27439
    27440
    27441
    27442
    27443
    27444
    27445
    27446
    27447
    27448
    27449
    27450
    27451
    27452
    27453
    27454
    27455
    27456
    27457
    27458
    27459
    27460
    27461
    27462
    27463
    27464
    27465
    27466
    27467
    27468
    27469
    27470
    27471
    27472
    27473
    27474
    27475
    27476
    27477
    27478
    27479
    27480
    27481
    27482
    27483
    27484
    27485
    27486
    27487
    27488
    27489
    27490
    27491
    27492
    27493
    27494
    27495
    27496
    27497
    27498
    27499
    27500
    27501
    27502
    27503
    27504
    27505
    27506
    27507
    27508
    27509
    27510
    27511
    27512
    27513
    27514
    27515
    27516
    27517
    27518
    27519
    27520
    27521
    27522
    27523
    27524
    27525
    27526
    27527
    27528
    27529
    27530
    27531
    27532
    27533
    27534
    27535
    27536
    27537
    27538
    27539
    27540
    27541
    27542
    27543
    27544
    27545
    27546
    27547
    27548
    27549
    27550
    27551
    27552
    27553
    27554
    27555
    27556
    27557
    27558
    27559
    27560
    27561
    27562
    27563
    27564
    27565
    27566
    27567
    27568
    27569
    27570
    27571
    27572
    27573
    27574
    27575
    27576
    27577
    27578
    27579
    27580
    27581
    27582
    27583
    27584
    27585
    27586
    27587
    27588
    27589
    27590
    27591
    27592
    27593
    27594
    27595
    27596
    27597
    27598
    27599
    27600
    27601
    27602
    27603
    27604
    27605
    27606
    27607
    27608
    27609
    27610
    27611
    27612
    27613
    27614
    27615
    27616
    27617
    27618
    27619
    27620
    27621
    27622
    27623
    27624
    27625
    27626
    27627
    27628
    27629
    27630
    27631
    27632
    27633
    27634
    27635
    27636
    27637
    27638
    27639
    27640
    27641
    27642
    27643
    27644
    27645
    27646
    27647
    27648
    27649
    27650
    27651
    27652
    27653
    27654
    27655
    27656
    27657
    27658
    27659
    27660
    27661
    27662
    27663
    27664
    27665
    27666
    27667
    27668
    27669
    27670
    27671
    27672
    27673
    27674
    27675
    27676
    27677
    27678
    27679
    27680
    27681
    27682
    27683
    27684
    27685
    27686
    27687
    27688
    27689
    27690
    27691
    27692
    27693
    27694
    27695
    27696
    27697
    27698
    27699
    27700
    27701
    27702
    27703
    27704
    27705
    27706
    27707
    27708
    27709
    27710
    27711
    27712
    27713
    27714
    27715
    27716
    27717
    27718
    27719
    27720
    27721
    27722
    27723
    27724
    27725
    27726
    27727
    27728
    27729
    27730
    27731
    27732
    27733
    27734
    27735
    27736
    27737
    27738
    27739
    27740
    27741
    27742
    27743
    27744
    27745
    27746
    27747
    27748
    27749
    27750
    27751
    27752
    27753
    27754
    27755
    27756
    27757
    27758
    27759
    27760
    27761
    27762
    27763
    27764
    27765
    27766
    27767
    27768
    27769
    27770
    27771
    27772
    27773
    27774
    27775
    27776
    27777
    27778
    27779
    27780
    27781
    27782
    27783
    27784
    27785
    27786
    27787
    27788
    27789
    27790
    27791
    27792
    27793
    27794
    27795
    27796
    27797
    27798
    27799
    27800
    27801
    27802
    27803
    27804
    27805
    27806
    27807
    27808
    27809
    27810
    27811
    27812
    27813
    27814
    27815
    27816
    27817
    27818
    27819
    27820
    27821
    27822
    27823
    27824
    27825
    27826
    27827
    27828
    27829
    27830
    27831
    27832
    27833
    27834
    27835
    27836
    27837
    27838
    27839
    27840
    27841
    27842
    27843
    27844
    27845
    27846
    27847
    27848
    27849
    27850
    27851
    27852
    27853
    27854
    27855
    27856
    27857
    27858
    27859
    27860
    27861
    27862
    27863
    27864
    27865
    27866
    27867
    27868
    27869
    27870
    27871
    27872
    27873
    27874
    27875
    27876
    27877
    27878
    27879
    27880
    27881
    27882
    27883
    27884
    27885
    27886
    27887
    27888
    27889
    27890
    27891
    27892
    27893
    27894
    27895
    27896
    27897
    27898
    27899
    27900
    27901
    27902
    27903
    27904
    27905
    27906
    27907
    27908
    27909
    27910
    27911
    27912
    27913
    27914
    27915
    27916
    27917
    27918
    27919
    27920
    27921
    27922
    27923
    27924
    27925
    27926
    27927
    27928
    27929
    27930
    27931
    27932
    27933
    27934
    27935
    27936
    27937
    27938
    27939
    27940
    27941
    27942
    27943
    27944
    27945
    27946
    27947
    27948
    27949
    27950
    27951
    27952
    27953
    27954
    27955
    27956
    27957
    27958
    27959
    27960
    27961
    27962
    27963
    27964
    27965
    27966
    27967
    27968
    27969
    27970
    27971
    27972
    27973
    27974
    27975
    27976
    27977
    27978
    27979
    27980
    27981
    27982
    27983
    27984
    27985
    27986
    27987
    27988
    27989
    27990
    27991
    27992
    27993
    27994
    27995
    27996
    27997
    27998
    27999
    28000
    28001
    28002
    28003
    28004
    28005
    28006
    28007
    28008
    28009
    28010
    28011
    28012
    28013
    28014
    28015
    28016
    28017
    28018
    28019
    28020
    28021
    28022
    28023
    28024
    28025
    28026
    28027
    28028
    28029
    28030
    28031
    28032
    28033
    28034
    28035
    28036
    28037
    28038
    28039
    28040
    28041
    28042
    28043
    28044
    28045
    28046
    28047
    28048
    28049
    28050
    28051
    28052
    28053
    28054
    28055
    28056
    28057
    28058
    28059
    28060
    28061
    28062
    28063
    28064
    28065
    28066
    28067
    28068
    28069
    28070
    28071
    28072
    28073
    28074
    28075
    28076
    28077
    28078
    28079
    28080
    28081
    28082
    28083
    28084
    28085
    28086
    28087
    28088
    28089
    28090
    28091
    28092
    28093
    28094
    28095
    28096
    28097
    28098
    28099
    28100
    28101
    28102
    28103
    28104
    28105
    28106
    28107
    28108
    28109
    28110
    28111
    28112
    28113
    28114
    28115
    28116
    28117
    28118
    28119
    28120
    28121
    28122
    28123
    28124
    28125
    28126
    28127
    28128
    28129
    28130
    28131
    28132
    28133
    28134
    28135
    28136
    28137
    28138
    28139
    28140
    28141
    28142
    28143
    28144
    28145
    28146
    28147
    28148
    28149
    28150
    28151
    28152
    28153
    28154
    28155
    28156
    28157
    28158
    28159
    28160
    28161
    28162
    28163
    28164
    28165
    28166
    28167
    28168
    28169
    28170
    28171
    28172
    28173
    28174
    28175
    28176
    28177
    28178
    28179
    28180
    28181
    28182
    28183
    28184
    28185
    28186
    28187
    28188
    28189
    28190
    28191
    28192
    28193
    28194
    28195
    28196
    28197
    28198
    28199
    28200
    28201
    28202
    28203
    28204
    28205
    28206
    28207
    28208
    28209
    28210
    28211
    28212
    28213
    28214
    28215
    28216
    28217
    28218
    28219
    28220
    28221
    28222
    28223
    28224
    28225
    28226
    28227
    28228
    28229
    28230
    28231
    28232
    28233
    28234
    28235
    28236
    28237
    28238
    28239
    28240
    28241
    28242
    28243
    28244
    28245
    28246
    28247
    28248
    28249
    28250
    28251
    28252
    28253
    28254
    28255
    28256
    28257
    28258
    28259
    28260
    28261
    28262
    28263
    28264
    28265
    28266
    28267
    28268
    28269
    28270
    28271
    28272
    28273
    28274
    28275
    28276
    28277
    28278
    28279
    28280
    28281
    28282
    28283
    28284
    28285
    28286
    28287
    28288
    28289
    28290
    28291
    28292
    28293
    28294
    28295
    28296
    28297
    28298
    28299
    28300
    28301
    28302
    28303
    28304
    28305
    28306
    28307
    28308
    28309
    28310
    28311
    28312
    28313
    28314
    28315
    28316
    28317
    28318
    28319
    28320
    28321
    28322
    28323
    28324
    28325
    28326
    28327
    28328
    28329
    28330
    28331
    28332
    28333
    28334
    28335
    28336
    28337
    28338
    28339
    28340
    28341
    28342
    28343
    28344
    28345
    28346
    28347
    28348
    28349
    28350
    28351
    28352
    28353
    28354
    28355
    28356
    28357
    28358
    28359
    28360
    28361
    28362
    28363
    28364
    28365
    28366
    28367
    28368
    28369
    28370
    28371
    28372
    28373
    28374
    28375
    28376
    28377
    28378
    28379
    28380
    28381
    28382
    28383
    28384
    28385
    28386
    28387
    28388
    28389
    28390
    28391
    28392
    28393
    28394
    28395
    28396
    28397
    28398
    28399
    28400
    28401
    28402
    28403
    28404
    28405
    28406
    28407
    28408
    28409
    28410
    28411
    28412
    28413
    28414
    28415
    28416
    28417
    28418
    28419
    28420
    28421
    28422
    28423
    28424
    28425
    28426
    28427
    28428
    28429
    28430
    28431
    28432
    28433
    28434
    28435
    28436
    28437
    28438
    28439
    28440
    28441
    28442
    28443
    28444
    28445
    28446
    28447
    28448
    28449
    28450
    28451
    28452
    28453
    28454
    28455
    28456
    28457
    28458
    28459
    28460
    28461
    28462
    28463
    28464
    28465
    28466
    28467
    28468
    28469
    28470
    28471
    28472
    28473
    28474
    28475
    28476
    28477
    28478
    28479
    28480
    28481
    28482
    28483
    28484
    28485
    28486
    28487
    28488
    28489
    28490
    28491
    28492
    28493
    28494
    28495
    28496
    28497
    28498
    28499
    28500
    28501
    28502
    28503
    28504
    28505
    28506
    28507
    28508
    28509
    28510
    28511
    28512
    28513
    28514
    28515
    28516
    28517
    28518
    28519
    28520
    28521
    28522
    28523
    28524
    28525
    28526
    28527
    28528
    28529
    28530
    28531
    28532
    28533
    28534
    28535
    28536
    28537
    28538
    28539
    28540
    28541
    28542
    28543
    28544
    28545
    28546
    28547
    28548
    28549
    28550
    28551
    28552
    28553
    28554
    28555
    28556
    28557
    28558
    28559
    28560
    28561
    28562
    28563
    28564
    28565
    28566
    28567
    28568
    28569
    28570
    28571
    28572
    28573
    28574
    28575
    28576
    28577
    28578
    28579
    28580
    28581
    28582
    28583
    28584
    28585
    28586
    28587
    28588
    28589
    28590
    28591
    28592
    28593
    28594
    28595
    28596
    28597
    28598
    28599
    28600
    28601
    28602
    28603
    28604
    28605
    28606
    28607
    28608
    28609
    28610
    28611
    28612
    28613
    28614
    28615
    28616
    28617
    28618
    28619
    28620
    28621
    28622
    28623
    28624
    28625
    28626
    28627
    28628
    28629
    28630
    28631
    28632
    28633
    28634
    28635
    28636
    28637
    28638
    28639
    28640
    28641
    28642
    28643
    28644
    28645
    28646
    28647
    28648
    28649
    28650
    28651
    28652
    28653
    28654
    28655
    28656
    28657
    28658
    28659
    28660
    28661
    28662
    28663
    28664
    28665
    28666
    28667
    28668
    28669
    28670
    28671
    28672
    28673
    28674
    28675
    28676
    28677
    28678
    28679
    28680
    28681
    28682
    28683
    28684
    28685
    28686
    28687
    28688
    28689
    28690
    28691
    28692
    28693
    28694
    28695
    28696
    28697
    28698
    28699
    28700
    28701
    28702
    28703
    28704
    28705
    28706
    28707
    28708
    28709
    28710
    28711
    28712
    28713
    28714
    28715
    28716
    28717
    28718
    28719
    28720
    28721
    28722
    28723
    28724
    28725
    28726
    28727
    28728
    28729
    28730
    28731
    28732
    28733
    28734
    28735
    28736
    28737
    28738
    28739
    28740
    28741
    28742
    28743
    28744
    28745
    28746
    28747
    28748
    28749
    28750
    28751
    28752
    28753
    28754
    28755
    28756
    28757
    28758
    28759
    28760
    28761
    28762
    28763
    28764
    28765
    28766
    28767
    28768
    28769
    28770
    28771
    28772
    28773
    28774
    28775
    28776
    28777
    28778
    28779
    28780
    28781
    28782
    28783
    28784
    28785
    28786
    28787
    28788
    28789
    28790
    28791
    28792
    28793
    28794
    28795
    28796
    28797
    28798
    28799
    28800
    28801
    28802
    28803
    28804
    28805
    28806
    28807
    28808
    28809
    28810
    28811
    28812
    28813
    28814
    28815
    28816
    28817
    28818
    28819
    28820
    28821
    28822
    28823
    28824
    28825
    28826
    28827
    28828
    28829
    28830
    28831
    28832
    28833
    28834
    28835
    28836
    28837
    28838
    28839
    28840
    28841
    28842
    28843
    28844
    28845
    28846
    28847
    28848
    28849
    28850
    28851
    28852
    28853
    28854
    28855
    28856
    28857
    28858
    28859
    28860
    28861
    28862
    28863
    28864
    28865
    28866
    28867
    28868
    28869
    28870
    28871
    28872
    28873
    28874
    28875
    28876
    28877
    28878
    28879
    28880
    28881
    28882
    28883
    28884
    28885
    28886
    28887
    28888
    28889
    28890
    28891
    28892
    28893
    28894
    28895
    28896
    28897
    28898
    28899
    28900
    28901
    28902
    28903
    28904
    28905
    28906
    28907
    28908
    28909
    28910
    28911
    28912
    28913
    28914
    28915
    28916
    28917
    28918
    28919
    28920
    28921
    28922
    28923
    28924
    28925
    28926
    28927
    28928
    28929
    28930
    28931
    28932
    28933
    28934
    28935
    28936
    28937
    28938
    28939
    28940
    28941
    28942
    28943
    28944
    28945
    28946
    28947
    28948
    28949
    28950
    28951
    28952
    28953
    28954
    28955
    28956
    28957
    28958
    28959
    28960
    28961
    28962
    28963
    28964
    28965
    28966
    28967
    28968
    28969
    28970
    28971
    28972
    28973
    28974
    28975
    28976
    28977
    28978
    28979
    28980
    28981
    28982
    28983
    28984
    28985
    28986
    28987
    28988
    28989
    28990
    28991
    28992
    28993
    28994
    28995
    28996
    28997
    28998
    28999
    29000
    29001
    29002
    29003
    29004
    29005
    29006
    29007
    29008
    29009
    29010
    29011
    29012
    29013
    29014
    29015
    29016
    29017
    29018
    29019
    29020
    29021
    29022
    29023
    29024
    29025
    29026
    29027
    29028
    29029
    29030
    29031
    29032
    29033
    29034
    29035
    29036
    29037
    29038
    29039
    29040
    29041
    29042
    29043
    29044
    29045
    29046
    29047
    29048
    29049
    29050
    29051
    29052
    29053
    29054
    29055
    29056
    29057
    29058
    29059
    29060
    29061
    29062
    29063
    29064
    29065
    29066
    29067
    29068
    29069
    29070
    29071
    29072
    29073
    29074
    29075
    29076
    29077
    29078
    29079
    29080
    29081
    29082
    29083
    29084
    29085
    29086
    29087
    29088
    29089
    29090
    29091
    29092
    29093
    29094
    29095
    29096
    29097
    29098
    29099
    29100
    29101
    29102
    29103
    29104
    29105
    29106
    29107
    29108
    29109
    29110
    29111
    29112
    29113
    29114
    29115
    29116
    29117
    29118
    29119
    29120
    29121
    29122
    29123
    29124
    29125
    29126
    29127
    29128
    29129
    29130
    29131
    29132
    29133
    29134
    29135
    29136
    29137
    29138
    29139
    29140
    29141
    29142
    29143
    29144
    29145
    29146
    29147
    29148
    29149
    29150
    29151
    29152
    29153
    29154
    29155
    29156
    29157
    29158
    29159
    29160
    29161
    29162
    29163
    29164
    29165
    29166
    29167
    29168
    29169
    29170
    29171
    29172
    29173
    29174
    29175
    29176
    29177
    29178
    29179
    29180
    29181
    29182
    29183
    29184
    29185
    29186
    29187
    29188
    29189
    29190
    29191
    29192
    29193
    29194
    29195
    29196
    29197
    29198
    29199
    29200
    29201
    29202
    29203
    29204
    29205
    29206
    29207
    29208
    29209
    29210
    29211
    29212
    29213
    29214
    29215
    29216
    29217
    29218
    29219
    29220
    29221
    29222
    29223
    29224
    29225
    29226
    29227
    29228
    29229
    29230
    29231
    29232
    29233
    29234
    29235
    29236
    29237
    29238
    29239
    29240
    29241
    29242
    29243
    29244
    29245
    29246
    29247
    29248
    29249
    29250
    29251
    29252
    29253
    29254
    29255
    29256
    29257
    29258
    29259
    29260
    29261
    29262
    29263
    29264
    29265
    29266
    29267
    29268
    29269
    29270
    29271
    29272
    29273
    29274
    29275
    29276
    29277
    29278
    29279
    29280
    29281
    29282
    29283
    29284
    29285
    29286
    29287
    29288
    29289
    29290
    29291
    29292
    29293
    29294
    29295
    29296
    29297
    29298
    29299
    29300
    29301
    29302
    29303
    29304
    29305
    29306
    29307
    29308
    29309
    29310
    29311
    29312
    29313
    29314
    29315
    29316
    29317
    29318
    29319
    29320
    29321
    29322
    29323
    29324
    29325
    29326
    29327
    29328
    29329
    29330
    29331
    29332
    29333
    29334
    29335
    29336
    29337
    29338
    29339
    29340
    29341
    29342
    29343
    29344
    29345
    29346
    29347
    29348
    29349
    29350
    29351
    29352
    29353
    29354
    29355
    29356
    29357
    29358
    29359
    29360
    29361
    29362
    29363
    29364
    29365
    29366
    29367
    29368
    29369
    29370
    29371
    29372
    29373
    29374
    29375
    29376
    29377
    29378
    29379
    29380
    29381
    29382
    29383
    29384
    29385
    29386
    29387
    29388
    29389
    29390
    29391
    29392
    29393
    29394
    29395
    29396
    29397
    29398
    29399
    29400
    29401
    29402
    29403
    29404
    29405
    29406
    29407
    29408
    29409
    29410
    29411
    29412
    29413
    29414
    29415
    29416
    29417
    29418
    29419
    29420
    29421
    29422
    29423
    29424
    29425
    29426
    29427
    29428
    29429
    29430
    29431
    29432
    29433
    29434
    29435
    29436
    29437
    29438
    29439
    29440
    29441
    29442
    29443
    29444
    29445
    29446
    29447
    29448
    29449
    29450
    29451
    29452
    29453
    29454
    29455
    29456
    29457
    29458
    29459
    29460
    29461
    29462
    29463
    29464
    29465
    29466
    29467
    29468
    29469
    29470
    29471
    29472
    29473
    29474
    29475
    29476
    29477
    29478
    29479
    29480
    29481
    29482
    29483
    29484
    29485
    29486
    29487
    29488
    29489
    29490
    29491
    29492
    29493
    29494
    29495
    29496
    29497
    29498
    29499
    29500
    29501
    29502
    29503
    29504
    29505
    29506
    29507
    29508
    29509
    29510
    29511
    29512
    29513
    29514
    29515
    29516
    29517
    29518
    29519
    29520
    29521
    29522
    29523
    29524
    29525
    29526
    29527
    29528
    29529
    29530
    29531
    29532
    29533
    29534
    29535
    29536
    29537
    29538
    29539
    29540
    29541
    29542
    29543
    29544
    29545
    29546
    29547
    29548
    29549
    29550
    29551
    29552
    29553
    29554
    29555
    29556
    29557
    29558
    29559
    29560
    29561
    29562
    29563
    29564
    29565
    29566
    29567
    29568
    29569
    29570
    29571
    29572
    29573
    29574
    29575
    29576
    29577
    29578
    29579
    29580
    29581
    29582
    29583
    29584
    29585
    29586
    29587
    29588
    29589
    29590
    29591
    29592
    29593
    29594
    29595
    29596
    29597
    29598
    29599
    29600
    29601
    29602
    29603
    29604
    29605
    29606
    29607
    29608
    29609
    29610
    29611
    29612
    29613
    29614
    29615
    29616
    29617
    29618
    29619
    29620
    29621
    29622
    29623
    29624
    29625
    29626
    29627
    29628
    29629
    29630
    29631
    29632
    29633
    29634
    29635
    29636
    29637
    29638
    29639
    29640
    29641
    29642
    29643
    29644
    29645
    29646
    29647
    29648
    29649
    29650
    29651
    29652
    29653
    29654
    29655
    29656
    29657
    29658
    29659
    29660
    29661
    29662
    29663
    29664
    29665
    29666
    29667
    29668
    29669
    29670
    29671
    29672
    29673
    29674
    29675
    29676
    29677
    29678
    29679
    29680
    29681
    29682
    29683
    29684
    29685
    29686
    29687
    29688
    29689
    29690
    29691
    29692
    29693
    29694
    29695
    29696
    29697
    29698
    29699
    29700
    29701
    29702
    29703
    29704
    29705
    29706
    29707
    29708
    29709
    29710
    29711
    29712
    29713
    29714
    29715
    29716
    29717
    29718
    29719
    29720
    29721
    29722
    29723
    29724
    29725
    29726
    29727
    29728
    29729
    29730
    29731
    29732
    29733
    29734
    29735
    29736
    29737
    29738
    29739
    29740
    29741
    29742
    29743
    29744
    29745
    29746
    29747
    29748
    29749
    29750
    29751
    29752
    29753
    29754
    29755
    29756
    29757
    29758
    29759
    29760
    29761
    29762
    29763
    29764
    29765
    29766
    29767
    29768
    29769
    29770
    29771
    29772
    29773
    29774
    29775
    29776
    29777
    29778
    29779
    29780
    29781
    29782
    29783
    29784
    29785
    29786
    29787
    29788
    29789
    29790
    29791
    29792
    29793
    29794
    29795
    29796
    29797
    29798
    29799
    29800
    29801
    29802
    29803
    29804
    29805
    29806
    29807
    29808
    29809
    29810
    29811
    29812
    29813
    29814
    29815
    29816
    29817
    29818
    29819
    29820
    29821
    29822
    29823
    29824
    29825
    29826
    29827
    29828
    29829
    29830
    29831
    29832
    29833
    29834
    29835
    29836
    29837
    29838
    29839
    29840
    29841
    29842
    29843
    29844
    29845
    29846
    29847
    29848
    29849
    29850
    29851
    29852
    29853
    29854
    29855
    29856
    29857
    29858
    29859
    29860
    29861
    29862
    29863
    29864
    29865
    29866
    29867
    29868
    29869
    29870
    29871
    29872
    29873
    29874
    29875
    29876
    29877
    29878
    29879
    29880
    29881
    29882
    29883
    29884
    29885
    29886
    29887
    29888
    29889
    29890
    29891
    29892
    29893
    29894
    29895
    29896
    29897
    29898
    29899
    29900
    29901
    29902
    29903
    29904
    29905
    29906
    29907
    29908
    29909
    29910
    29911
    29912
    29913
    29914
    29915
    29916
    29917
    29918
    29919
    29920
    29921
    29922
    29923
    29924
    29925
    29926
    29927
    29928
    29929
    29930
    29931
    29932
    29933
    29934
    29935
    29936
    29937
    29938
    29939
    29940
    29941
    29942
    29943
    29944
    29945
    29946
    29947
    29948
    29949
    29950
    29951
    29952
    29953
    29954
    29955
    29956
    29957
    29958
    29959
    29960
    29961
    29962
    29963
    29964
    29965
    29966
    29967
    29968
    29969
    29970
    29971
    29972
    29973
    29974
    29975
    29976
    29977
    29978
    29979
    29980
    29981
    29982
    29983
    29984
    29985
    29986
    29987
    29988
    29989
    29990
    29991
    29992
    29993
    29994
    29995
    29996
    29997
    29998
    29999
    30000
    30001
    30002
    30003
    30004
    30005
    30006
    30007
    30008
    30009
    30010
    30011
    30012
    30013
    30014
    30015
    30016
    30017
    30018
    30019
    30020
    30021
    30022
    30023
    30024
    30025
    30026
    30027
    30028
    30029
    30030
    30031
    30032
    30033
    30034
    30035
    30036
    30037
    30038
    30039
    30040
    30041
    30042
    30043
    30044
    30045
    30046
    30047
    30048
    30049
    30050
    30051
    30052
    30053
    30054
    30055
    30056
    30057
    30058
    30059
    30060
    30061
    30062
    30063
    30064
    30065
    30066
    30067
    30068
    30069
    30070
    30071
    30072
    30073
    30074
    30075
    30076
    30077
    30078
    30079
    30080
    30081
    30082
    30083
    30084
    30085
    30086
    30087
    30088
    30089
    30090
    30091
    30092
    30093
    30094
    30095
    30096
    30097
    30098
    30099
    30100
    30101
    30102
    30103
    30104
    30105
    30106
    30107
    30108
    30109
    30110
    30111
    30112
    30113
    30114
    30115
    30116
    30117
    30118
    30119
    30120
    30121
    30122
    30123
    30124
    30125
    30126
    30127
    30128
    30129
    30130
    30131
    30132
    30133
    30134
    30135
    30136
    30137
    30138
    30139
    30140
    30141
    30142
    30143
    30144
    30145
    30146
    30147
    30148
    30149
    30150
    30151
    30152
    30153
    30154
    30155
    30156
    30157
    30158
    30159
    30160
    30161
    30162
    30163
    30164
    30165
    30166
    30167
    30168
    30169
    30170
    30171
    30172
    30173
    30174
    30175
    30176
    30177
    30178
    30179
    30180
    30181
    30182
    30183
    30184
    30185
    30186
    30187
    30188
    30189
    30190
    30191
    30192
    30193
    30194
    30195
    30196
    30197
    30198
    30199
    30200
    30201
    30202
    30203
    30204
    30205
    30206
    30207
    30208
    30209
    30210
    30211
    30212
    30213
    30214
    30215
    30216
    30217
    30218
    30219
    30220
    30221
    30222
    30223
    30224
    30225
    30226
    30227
    30228
    30229
    30230
    30231
    30232
    30233
    30234
    30235
    30236
    30237
    30238
    30239
    30240
    30241
    30242
    30243
    30244
    30245
    30246
    30247
    30248
    30249
    30250
    30251
    30252
    30253
    30254
    30255
    30256
    30257
    30258
    30259
    30260
    30261
    30262
    30263
    30264
    30265
    30266
    30267
    30268
    30269
    30270
    30271
    30272
    30273
    30274
    30275
    30276
    30277
    30278
    30279
    30280
    30281
    30282
    30283
    30284
    30285
    30286
    30287
    30288
    30289
    30290
    30291
    30292
    30293
    30294
    30295
    30296
    30297
    30298
    30299
    30300
    30301
    30302
    30303
    30304
    30305
    30306
    30307
    30308
    30309
    30310
    30311
    30312
    30313
    30314
    30315
    30316
    30317
    30318
    30319
    30320
    30321
    30322
    30323
    30324
    30325
    30326
    30327
    30328
    30329
    30330
    30331
    30332
    30333
    30334
    30335
    30336
    30337
    30338
    30339
    30340
    30341
    30342
    30343
    30344
    30345
    30346
    30347
    30348
    30349
    30350
    30351
    30352
    30353
    30354
    30355
    30356
    30357
    30358
    30359
    30360
    30361
    30362
    30363
    30364
    30365
    30366
    30367
    30368
    30369
    30370
    30371
    30372
    30373
    30374
    30375
    30376
    30377
    30378
    30379
    30380
    30381
    30382
    30383
    30384
    30385
    30386
    30387
    30388
    30389
    30390
    30391
    30392
    30393
    30394
    30395
    30396
    30397
    30398
    30399
    30400
    30401
    30402
    30403
    30404
    30405
    30406
    30407
    30408
    30409
    30410
    30411
    30412
    30413
    30414
    30415
    30416
    30417
    30418
    30419
    30420
    30421
    30422
    30423
    30424
    30425
    30426
    30427
    30428
    30429
    30430
    30431
    30432
    30433
    30434
    30435
    30436
    30437
    30438
    30439
    30440
    30441
    30442
    30443
    30444
    30445
    30446
    30447
    30448
    30449
    30450
    30451
    30452
    30453
    30454
    30455
    30456
    30457
    30458
    30459
    30460
    30461
    30462
    30463
    30464
    30465
    30466
    30467
    30468
    30469
    30470
    30471
    30472
    30473
    30474
    30475
    30476
    30477
    30478
    30479
    30480
    30481
    30482
    30483
    30484
    30485
    30486
    30487
    30488
    30489
    30490
    30491
    30492
    30493
    30494
    30495
    30496
    30497
    30498
    30499
    30500
    30501
    30502
    30503
    30504
    30505
    30506
    30507
    30508
    30509
    30510
    30511
    30512
    30513
    30514
    30515
    30516
    30517
    30518
    30519
    30520
    30521
    30522
    30523
    30524
    30525
    30526
    30527
    30528
    30529
    30530
    30531
    30532
    30533
    30534
    30535
    30536
    30537
    30538
    30539
    30540
    30541
    30542
    30543
    30544
    30545
    30546
    30547
    30548
    30549
    30550
    30551
    30552
    30553
    30554
    30555
    30556
    30557
    30558
    30559
    30560
    30561
    30562
    30563
    30564
    30565
    30566
    30567
    30568
    30569
    30570
    30571
    30572
    30573
    30574
    30575
    30576
    30577
    30578
    30579
    30580
    30581
    30582
    30583
    30584
    30585
    30586
    30587
    30588
    30589
    30590
    30591
    30592
    30593
    30594
    30595
    30596
    30597
    30598
    30599
    30600
    30601
    30602
    30603
    30604
    30605
    30606
    30607
    30608
    30609
    30610
    30611
    30612
    30613
    30614
    30615
    30616
    30617
    30618
    30619
    30620
    30621
    30622
    30623
    30624
    30625
    30626
    30627
    30628
    30629
    30630
    30631
    30632
    30633
    30634
    30635
    30636
    30637
    30638
    30639
    30640
    30641
    30642
    30643
    30644
    30645
    30646
    30647
    30648
    30649
    30650
    30651
    30652
    30653
    30654
    30655
    30656
    30657
    30658
    30659
    30660
    30661
    30662
    30663
    30664
    30665
    30666
    30667
    30668
    30669
    30670
    30671
    30672
    30673
    30674
    30675
    30676
    30677
    30678
    30679
    30680
    30681
    30682
    30683
    30684
    30685
    30686
    30687
    30688
    30689
    30690
    30691
    30692
    30693
    30694
    30695
    30696
    30697
    30698
    30699
    30700
    30701
    30702
    30703
    30704
    30705
    30706
    30707
    30708
    30709
    30710
    30711
    30712
    30713
    30714
    30715
    30716
    30717
    30718
    30719
    30720
    30721
    30722
    30723
    30724
    30725
    30726
    30727
    30728
    30729
    30730
    30731
    30732
    30733
    30734
    30735
    30736
    30737
    30738
    30739
    30740
    30741
    30742
    30743
    30744
    30745
    30746
    30747
    30748
    30749
    30750
    30751
    30752
    30753
    30754
    30755
    30756
    30757
    30758
    30759
    30760
    30761
    30762
    30763
    30764
    30765
    30766
    30767
    30768
    30769
    30770
    30771
    30772
    30773
    30774
    30775
    30776
    30777
    30778
    30779
    30780
    30781
    30782
    30783
    30784
    30785
    30786
    30787
    30788
    30789
    30790
    30791
    30792
    30793
    30794
    30795
    30796
    30797
    30798
    30799
    30800
    30801
    30802
    30803
    30804
    30805
    30806
    30807
    30808
    30809
    30810
    30811
    30812
    30813
    30814
    30815
    30816
    30817
    30818
    30819
    30820
    30821
    30822
    30823
    30824
    30825
    30826
    30827
    30828
    30829
    30830
    30831
    30832
    30833
    30834
    30835
    30836
    30837
    30838
    30839
    30840
    30841
    30842
    30843
    30844
    30845
    30846
    30847
    30848
    30849
    30850
    30851
    30852
    30853
    30854
    30855
    30856
    30857
    30858
    30859
    30860
    30861
    30862
    30863
    30864
    30865
    30866
    30867
    30868
    30869
    30870
    30871
    30872
    30873
    30874
    30875
    30876
    30877
    30878
    30879
    30880
    30881
    30882
    30883
    30884
    30885
    30886
    30887
    30888
    30889
    30890
    30891
    30892
    30893
    30894
    30895
    30896
    30897
    30898
    30899
    30900
    30901
    30902
    30903
    30904
    30905
    30906
    30907
    30908
    30909
    30910
    30911
    30912
    30913
    30914
    30915
    30916
    30917
    30918
    30919
    30920
    30921
    30922
    30923
    30924
    30925
    30926
    30927
    30928
    30929
    30930
    30931
    30932
    30933
    30934
    30935
    30936
    30937
    30938
    30939
    30940
    30941
    30942
    30943
    30944
    30945
    30946
    30947
    30948
    30949
    30950
    30951
    30952
    30953
    30954
    30955
    30956
    30957
    30958
    30959
    30960
    30961
    30962
    30963
    30964
    30965
    30966
    30967
    30968
    30969
    30970
    30971
    30972
    30973
    30974
    30975
    30976
    30977
    30978
    30979
    30980
    30981
    30982
    30983
    30984
    30985
    30986
    30987
    30988
    30989
    30990
    30991
    30992
    30993
    30994
    30995
    30996
    30997
    30998
    30999
    31000
    31001
    31002
    31003
    31004
    31005
    31006
    31007
    31008
    31009
    31010
    31011
    31012
    31013
    31014
    31015
    31016
    31017
    31018
    31019
    31020
    31021
    31022
    31023
    31024
    31025
    31026
    31027
    31028
    31029
    31030
    31031
    31032
    31033
    31034
    31035
    31036
    31037
    31038
    31039
    31040
    31041
    31042
    31043
    31044
    31045
    31046
    31047
    31048
    31049
    31050
    31051
    31052
    31053
    31054
    31055
    31056
    31057
    31058
    31059
    31060
    31061
    31062
    31063
    31064
    31065
    31066
    31067
    31068
    31069
    31070
    31071
    31072
    31073
    31074
    31075
    31076
    31077
    31078
    31079
    31080
    31081
    31082
    31083
    31084
    31085
    31086
    31087
    31088
    31089
    31090
    31091
    31092
    31093
    31094
    31095
    31096
    31097
    31098
    31099
    31100
    31101
    31102
    31103
    31104
    31105
    31106
    31107
    31108
    31109
    31110
    31111
    31112
    31113
    31114
    31115
    31116
    31117
    31118
    31119
    31120
    31121
    31122
    31123
    31124
    31125
    31126
    31127
    31128
    31129
    31130
    31131
    31132
    31133
    31134
    31135
    31136
    31137
    31138
    31139
    31140
    31141
    31142
    31143
    31144
    31145
    31146
    31147
    31148
    31149
    31150
    31151
    31152
    31153
    31154
    31155
    31156
    31157
    31158
    31159
    31160
    31161
    31162
    31163
    31164
    31165
    31166
    31167
    31168
    31169
    31170
    31171
    31172
    31173
    31174
    31175
    31176
    31177
    31178
    31179
    31180
    31181
    31182
    31183
    31184
    31185
    31186
    31187
    31188
    31189
    31190
    31191
    31192
    31193
    31194
    31195
    31196
    31197
    31198
    31199
    31200
    31201
    31202
    31203
    31204
    31205
    31206
    31207
    31208
    31209
    31210
    31211
    31212
    31213
    31214
    31215
    31216
    31217
    31218
    31219
    31220
    31221
    31222
    31223
    31224
    31225
    31226
    31227
    31228
    31229
    31230
    31231
    31232
    31233
    31234
    31235
    31236
    31237
    31238
    31239
    31240
    31241
    31242
    31243
    31244
    31245
    31246
    31247
    31248
    31249
    31250
    31251
    31252
    31253
    31254
    31255
    31256
    31257
    31258
    31259
    31260
    31261
    31262
    31263
    31264
    31265
    31266
    31267
    31268
    31269
    31270
    31271
    31272
    31273
    31274
    31275
    31276
    31277
    31278
    31279
    31280
    31281
    31282
    31283
    31284
    31285
    31286
    31287
    31288
    31289
    31290
    31291
    31292
    31293
    31294
    31295
    31296
    31297
    31298
    31299
    31300
    31301
    31302
    31303
    31304
    31305
    31306
    31307
    31308
    31309
    31310
    31311
    31312
    31313
    31314
    31315
    31316
    31317
    31318
    31319
    31320
    31321
    31322
    31323
    31324
    31325
    31326
    31327
    31328
    31329
    31330
    31331
    31332
    31333
    31334
    31335
    31336
    31337
    31338
    31339
    31340
    31341
    31342
    31343
    31344
    31345
    31346
    31347
    31348
    31349
    31350
    31351
    31352
    31353
    31354
    31355
    31356
    31357
    31358
    31359
    31360
    31361
    31362
    31363
    31364
    31365
    31366
    31367
    31368
    31369
    31370
    31371
    31372
    31373
    31374
    31375
    31376
    31377
    31378
    31379
    31380
    31381
    31382
    31383
    31384
    31385
    31386
    31387
    31388
    31389
    31390
    31391
    31392
    31393
    31394
    31395
    31396
    31397
    31398
    31399
    31400
    31401
    31402
    31403
    31404
    31405
    31406
    31407
    31408
    31409
    31410
    31411
    31412
    31413
    31414
    31415
    31416
    31417
    31418
    31419
    31420
    31421
    31422
    31423
    31424
    31425
    31426
    31427
    31428
    31429
    31430
    31431
    31432
    31433
    31434
    31435
    31436
    31437
    31438
    31439
    31440
    31441
    31442
    31443
    31444
    31445
    31446
    31447
    31448
    31449
    31450
    31451
    31452
    31453
    31454
    31455
    31456
    31457
    31458
    31459
    31460
    31461
    31462
    31463
    31464
    31465
    31466
    31467
    31468
    31469
    31470
    31471
    31472
    31473
    31474
    31475
    31476
    31477
    31478
    31479
    31480
    31481
    31482
    31483
    31484
    31485
    31486
    31487
    31488
    31489
    31490
    31491
    31492
    31493
    31494
    31495
    31496
    31497
    31498
    31499
    31500
    31501
    31502
    31503
    31504
    31505
    31506
    31507
    31508
    31509
    31510
    31511
    31512
    31513
    31514
    31515
    31516
    31517
    31518
    31519
    31520
    31521
    31522
    31523
    31524
    31525
    31526
    31527
    31528
    31529
    31530
    31531
    31532
    31533
    31534
    31535
    31536
    31537
    31538
    31539
    31540
    31541
    31542
    31543
    31544
    31545
    31546
    31547
    31548
    31549
    31550
    31551
    31552
    31553
    31554
    31555
    31556
    31557
    31558
    31559
    31560
    31561
    31562
    31563
    31564
    31565
    31566
    31567
    31568
    31569
    31570
    31571
    31572
    31573
    31574
    31575
    31576
    31577
    31578
    31579
    31580
    31581
    31582
    31583
    31584
    31585
    31586
    31587
    31588
    31589
    31590
    31591
    31592
    31593
    31594
    31595
    31596
    31597
    31598
    31599
    31600
    31601
    31602
    31603
    31604
    31605
    31606
    31607
    31608
    31609
    31610
    31611
    31612
    31613
    31614
    31615
    31616
    31617
    31618
    31619
    31620
    31621
    31622
    31623
    31624
    31625
    31626
    31627
    31628
    31629
    31630
    31631
    31632
    31633
    31634
    31635
    31636
    31637
    31638
    31639
    31640
    31641
    31642
    31643
    31644
    31645
    31646
    31647
    31648
    31649
    31650
    31651
    31652
    31653
    31654
    31655
    31656
    31657
    31658
    31659
    31660
    31661
    31662
    31663
    31664
    31665
    31666
    31667
    31668
    31669
    31670
    31671
    31672
    31673
    31674
    31675
    31676
    31677
    31678
    31679
    31680
    31681
    31682
    31683
    31684
    31685
    31686
    31687
    31688
    31689
    31690
    31691
    31692
    31693
    31694
    31695
    31696
    31697
    31698
    31699
    31700
    31701
    31702
    31703
    31704
    31705
    31706
    31707
    31708
    31709
    31710
    31711
    31712
    31713
    31714
    31715
    31716
    31717
    31718
    31719
    31720
    31721
    31722
    31723
    31724
    31725
    31726
    31727
    31728
    31729
    31730
    31731
    31732
    31733
    31734
    31735
    31736
    31737
    31738
    31739
    31740
    31741
    31742
    31743
    31744
    31745
    31746
    31747
    31748
    31749
    31750
    31751
    31752
    31753
    31754
    31755
    31756
    31757
    31758
    31759
    31760
    31761
    31762
    31763
    31764
    31765
    31766
    31767
    31768
    31769
    31770
    31771
    31772
    31773
    31774
    31775
    31776
    31777
    31778
    31779
    31780
    31781
    31782
    31783
    31784
    31785
    31786
    31787
    31788
    31789
    31790
    31791
    31792
    31793
    31794
    31795
    31796
    31797
    31798
    31799
    31800
    31801
    31802
    31803
    31804
    31805
    31806
    31807
    31808
    31809
    31810
    31811
    31812
    31813
    31814
    31815
    31816
    31817
    31818
    31819
    31820
    31821
    31822
    31823
    31824
    31825
    31826
    31827
    31828
    31829
    31830
    31831
    31832
    31833
    31834
    31835
    31836
    31837
    31838
    31839
    31840
    31841
    31842
    31843
    31844
    31845
    31846
    31847
    31848
    31849
    31850
    31851
    31852
    31853
    31854
    31855
    31856
    31857
    31858
    31859
    31860
    31861
    31862
    31863
    31864
    31865
    31866
    31867
    31868
    31869
    31870
    31871
    31872
    31873
    31874
    31875
    31876
    31877
    31878
    31879
    31880
    31881
    31882
    31883
    31884
    31885
    31886
    31887
    31888
    31889
    31890
    31891
    31892
    31893
    31894
    31895
    31896
    31897
    31898
    31899
    31900
    31901
    31902
    31903
    31904
    31905
    31906
    31907
    31908
    31909
    31910
    31911
    31912
    31913
    31914
    31915
    31916
    31917
    31918
    31919
    31920
    31921
    31922
    31923
    31924
    31925
    31926
    31927
    31928
    31929
    31930
    31931
    31932
    31933
    31934
    31935
    31936
    31937
    31938
    31939
    31940
    31941
    31942
    31943
    31944
    31945
    31946
    31947
    31948
    31949
    31950
    31951
    31952
    31953
    31954
    31955
    31956
    31957
    31958
    31959
    31960
    31961
    31962
    31963
    31964
    31965
    31966
    31967
    31968
    31969
    31970
    31971
    31972
    31973
    31974
    31975
    31976
    31977
    31978
    31979
    31980
    31981
    31982
    31983
    31984
    31985
    31986
    31987
    31988
    31989
    31990
    31991
    31992
    31993
    31994
    31995
    31996
    31997
    31998
    31999
    32000
    32001
    32002
    32003
    32004
    32005
    32006
    32007
    32008
    32009
    32010
    32011
    32012
    32013
    32014
    32015
    32016
    32017
    32018
    32019
    32020
    32021
    32022
    32023
    32024
    32025
    32026
    32027
    32028
    32029
    32030
    32031
    32032
    32033
    32034
    32035
    32036
    32037
    32038
    32039
    32040
    32041
    32042
    32043
    32044
    32045
    32046
    32047
    32048
    32049
    32050
    32051
    32052
    32053
    32054
    32055
    32056
    32057
    32058
    32059
    32060
    32061
    32062
    32063
    32064
    32065
    32066
    32067
    32068
    32069
    32070
    32071
    32072
    32073
    32074
    32075
    32076
    32077
    32078
    32079
    32080
    32081
    32082
    32083
    32084
    32085
    32086
    32087
    32088
    32089
    32090
    32091
    32092
    32093
    32094
    32095
    32096
    32097
    32098
    32099
    32100
    32101
    32102
    32103
    32104
    32105
    32106
    32107
    32108
    32109
    32110
    32111
    32112
    32113
    32114
    32115
    32116
    32117
    32118
    32119
    32120
    32121
    32122
    32123
    32124
    32125
    32126
    32127
    32128
    32129
    32130
    32131
    32132
    32133
    32134
    32135
    32136
    32137
    32138
    32139
    32140
    32141
    32142
    32143
    32144
    32145
    32146
    32147
    32148
    32149
    32150
    32151
    32152
    32153
    32154
    32155
    32156
    32157
    32158
    32159
    32160
    32161
    32162
    32163
    32164
    32165
    32166
    32167
    32168
    32169
    32170
    32171
    32172
    32173
    32174
    32175
    32176
    32177
    32178
    32179
    32180
    32181
    32182
    32183
    32184
    32185
    32186
    32187
    32188
    32189
    32190
    32191
    32192
    32193
    32194
    32195
    32196
    32197
    32198
    32199
    32200
    32201
    32202
    32203
    32204
    32205
    32206
    32207
    32208
    32209
    32210
    32211
    32212
    32213
    32214
    32215
    32216
    32217
    32218
    32219
    32220
    32221
    32222
    32223
    32224
    32225
    32226
    32227
    32228
    32229
    32230
    32231
    32232
    32233
    32234
    32235
    32236
    32237
    32238
    32239
    32240
    32241
    32242
    32243
    32244
    32245
    32246
    32247
    32248
    32249
    32250
    32251
    32252
    32253
    32254
    32255
    32256
    32257
    32258
    32259
    32260
    32261
    32262
    32263
    32264
    32265
    32266
    32267
    32268
    32269
    32270
    32271
    32272
    32273
    32274
    32275
    32276
    32277
    32278
    32279
    32280
    32281
    32282
    32283
    32284
    32285
    32286
    32287
    32288
    32289
    32290
    32291
    32292
    32293
    32294
    32295
    32296
    32297
    32298
    32299
    32300
    32301
    32302
    32303
    32304
    32305
    32306
    32307
    32308
    32309
    32310
    32311
    32312
    32313
    32314
    32315
    32316
    32317
    32318
    32319
    32320
    32321
    32322
    32323
    32324
    32325
    32326
    32327
    32328
    32329
    32330
    32331
    32332
    32333
    32334
    32335
    32336
    32337
    32338
    32339
    32340
    32341
    32342
    32343
    32344
    32345
    32346
    32347
    32348
    32349
    32350
    32351
    32352
    32353
    32354
    32355
    32356
    32357
    32358
    32359
    32360
    32361
    32362
    32363
    32364
    32365
    32366
    32367
    32368
    32369
    32370
    32371
    32372
    32373
    32374
    32375
    32376
    32377
    32378
    32379
    32380
    32381
    32382
    32383
    32384
    32385
    32386
    32387
    32388
    32389
    32390
    32391
    32392
    32393
    32394
    32395
    32396
    32397
    32398
    32399
    32400
    32401
    32402
    32403
    32404
    32405
    32406
    32407
    32408
    32409
    32410
    32411
    32412
    32413
    32414
    32415
    32416
    32417
    32418
    32419
    32420
    32421
    32422
    32423
    32424
    32425
    32426
    32427
    32428
    32429
    32430
    32431
    32432
    32433
    32434
    32435
    32436
    32437
    32438
    32439
    32440
    32441
    32442
    32443
    32444
    32445
    32446
    32447
    32448
    32449
    32450
    32451
    32452
    32453
    32454
    32455
    32456
    32457
    32458
    32459
    32460
    32461
    32462
    32463
    32464
    32465
    32466
    32467
    32468
    32469
    32470
    32471
    32472
    32473
    32474
    32475
    32476
    32477
    32478
    32479
    32480
    32481
    32482
    32483
    32484
    32485
    32486
    32487
    32488
    32489
    32490
    32491
    32492
    32493
    32494
    32495
    32496
    32497
    32498
    32499
    32500
    32501
    32502
    32503
    32504
    32505
    32506
    32507
    32508
    32509
    32510
    32511
    32512
    32513
    32514
    32515
    32516
    32517
    32518
    32519
    32520
    32521
    32522
    32523
    32524
    32525
    32526
    32527
    32528
    32529
    32530
    32531
    32532
    32533
    32534
    32535
    32536
    32537
    32538
    32539
    32540
    32541
    32542
    32543
    32544
    32545
    32546
    32547
    32548
    32549
    32550
    32551
    32552
    32553
    32554
    32555
    32556
    32557
    32558
    32559
    32560
    32561
    32562
    32563
    32564
    32565
    32566
    32567
    32568
    32569
    32570
    32571
    32572
    32573
    32574
    32575
    32576
    32577
    32578
    32579
    32580
    32581
    32582
    32583
    32584
    32585
    32586
    32587
    32588
    32589
    32590
    32591
    32592
    32593
    32594
    32595
    32596
    32597
    32598
    32599
    32600
    32601
    32602
    32603
    32604
    32605
    32606
    32607
    32608
    32609
    32610
    32611
    32612
    32613
    32614
    32615
    32616
    32617
    32618
    32619
    32620
    32621
    32622
    32623
    32624
    32625
    32626
    32627
    32628
    32629
    32630
    32631
    32632
    32633
    32634
    32635
    32636
    32637
    32638
    32639
    32640
    32641
    32642
    32643
    32644
    32645
    32646
    32647
    32648
    32649
    32650
    32651
    32652
    32653
    32654
    32655
    32656
    32657
    32658
    32659
    32660
    32661
    32662
    32663
    32664
    32665
    32666
    32667
    32668
    32669
    32670
    32671
    32672
    32673
    32674
    32675
    32676
    32677
    32678
    32679
    32680
    32681
    32682
    32683
    32684
    32685
    32686
    32687
    32688
    32689
    32690
    32691
    32692
    32693
    32694
    32695
    32696
    32697
    32698
    32699
    32700
    32701
    32702
    32703
    32704
    32705
    32706
    32707
    32708
    32709
    32710
    32711
    32712
    32713
    32714
    32715
    32716
    32717
    32718
    32719
    32720
    32721
    32722
    32723
    32724
    32725
    32726
    32727
    32728
    32729
    32730
    32731
    32732
    32733
    32734
    32735
    32736
    32737
    32738
    32739
    32740
    32741
    32742
    32743
    32744
    32745
    32746
    32747
    32748
    32749
    32750
    32751
    32752
    32753
    32754
    32755
    32756
    32757
    32758
    32759
    32760
    32761
    32762
    32763
    32764
    32765
    32766
    32767
    32768
    32769
    32770
    32771
    32772
    32773
    32774
    32775
    32776
    32777
    32778
    32779
    32780
    32781
    32782
    32783
    32784
    32785
    32786
    32787
    32788
    32789
    32790
    32791
    32792
    32793
    32794
    32795
    32796
    32797
    32798
    32799
    32800
    32801
    32802
    32803
    32804
    32805
    32806
    32807
    32808
    32809
    32810
    32811
    32812
    32813
    32814
    32815
    32816
    32817
    32818
    32819
    32820
    32821
    32822
    32823
    32824
    32825
    32826
    32827
    32828
    32829
    32830
    32831
    32832
    32833
    32834
    32835
    32836
    32837
    32838
    32839
    32840
    32841
    32842
    32843
    32844
    32845
    32846
    32847
    32848
    32849
    32850
    32851
    32852
    32853
    32854
    32855
    32856
    32857
    32858
    32859
    32860
    32861
    32862
    32863
    32864
    32865
    32866
    32867
    32868
    32869
    32870
    32871
    32872
    32873
    32874
    32875
    32876
    32877
    32878
    32879
    32880
    32881
    32882
    32883
    32884
    32885
    32886
    32887
    32888
    32889
    32890
    32891
    32892
    32893
    32894
    32895
    32896
    32897
    32898
    32899
    32900
    32901
    32902
    32903
    32904
    32905
    32906
    32907
    32908
    32909
    32910
    32911
    32912
    32913
    32914
    32915
    32916
    32917
    32918
    32919
    32920
    32921
    32922
    32923
    32924
    32925
    32926
    32927
    32928
    32929
    32930
    32931
    32932
    32933
    32934
    32935
    32936
    32937
    32938
    32939
    32940
    32941
    32942
    32943
    32944
    32945
    32946
    32947
    32948
    32949
    32950
    32951
    32952
    32953
    32954
    32955
    32956
    32957
    32958
    32959
    32960
    32961
    32962
    32963
    32964
    32965
    32966
    32967
    32968
    32969
    32970
    32971
    32972
    32973
    32974
    32975
    32976
    32977
    32978
    32979
    32980
    32981
    32982
    32983
    32984
    32985
    32986
    32987
    32988
    32989
    32990
    32991
    32992
    32993
    32994
    32995
    32996
    32997
    32998
    32999
    33000
    33001
    33002
    33003
    33004
    33005
    33006
    33007
    33008
    33009
    33010
    33011
    33012
    33013
    33014
    33015
    33016
    33017
    33018
    33019
    33020
    33021
    33022
    33023
    33024
    33025
    33026
    33027
    33028
    33029
    33030
    33031
    33032
    33033
    33034
    33035
    33036
    33037
    33038
    33039
    33040
    33041
    33042
    33043
    33044
    33045
    33046
    33047
    33048
    33049
    33050
    33051
    33052
    33053
    33054
    33055
    33056
    33057
    33058
    33059
    33060
    33061
    33062
    33063
    33064
    33065
    33066
    33067
    33068
    33069
    33070
    33071
    33072
    33073
    33074
    33075
    33076
    33077
    33078
    33079
    33080
    33081
    33082
    33083
    33084
    33085
    33086
    33087
    33088
    33089
    33090
    33091
    33092
    33093
    33094
    33095
    33096
    33097
    33098
    33099
    33100
    33101
    33102
    33103
    33104
    33105
    33106
    33107
    33108
    33109
    33110
    33111
    33112
    33113
    33114
    33115
    33116
    33117
    33118
    33119
    33120
    33121
    33122
    33123
    33124
    33125
    33126
    33127
    33128
    33129
    33130
    33131
    33132
    33133
    33134
    33135
    33136
    33137
    33138
    33139
    33140
    33141
    33142
    33143
    33144
    33145
    33146
    33147
    33148
    33149
    33150
    33151
    33152
    33153
    33154
    33155
    33156
    33157
    33158
    33159
    33160
    33161
    33162
    33163
    33164
    33165
    33166
    33167
    33168
    33169
    33170
    33171
    33172
    33173
    33174
    33175
    33176
    33177
    33178
    33179
    33180
    33181
    33182
    33183
    33184
    33185
    33186
    33187
    33188
    33189
    33190
    33191
    33192
    33193
    33194
    33195
    33196
    33197
    33198
    33199
    33200
    33201
    33202
    33203
    33204
    33205
    33206
    33207
    33208
    33209
    33210
    33211
    33212
    33213
    33214
    33215
    33216
    33217
    33218
    33219
    33220
    33221
    33222
    33223
    33224
    33225
    33226
    33227
    33228
    33229
    33230
    33231
    33232
    33233
    33234
    33235
    33236
    33237
    33238
    33239
    33240
    33241
    33242
    33243
    33244
    33245
    33246
    33247
    33248
    33249
    33250
    33251
    33252
    33253
    33254
    33255
    33256
    33257
    33258
    33259
    33260
    33261
    33262
    33263
    33264
    33265
    33266
    33267
    33268
    33269
    33270
    33271
    33272
    33273
    33274
    33275
    33276
    33277
    33278
    33279
    33280
    33281
    33282
    33283
    33284
    33285
    33286
    33287
    33288
    33289
    33290
    33291
    33292
    33293
    33294
    33295
    33296
    33297
    33298
    33299
    33300
    33301
    33302
    33303
    33304
    33305
    33306
    33307
    33308
    33309
    33310
    33311
    33312
    33313
    33314
    33315
    33316
    33317
    33318
    33319
    33320
    33321
    33322
    33323
    33324
    33325
    33326
    33327
    33328
    33329
    33330
    33331
    33332
    33333
    33334
    33335
    33336
    33337
    33338
    33339
    33340
    33341
    33342
    33343
    33344
    33345
    33346
    33347
    33348
    33349
    33350
    33351
    33352
    33353
    33354
    33355
    33356
    33357
    33358
    33359
    33360
    33361
    33362
    33363
    33364
    33365
    33366
    33367
    33368
    33369
    33370
    33371
    33372
    33373
    33374
    33375
    33376
    33377
    33378
    33379
    33380
    33381
    33382
    33383
    33384
    33385
    33386
    33387
    33388
    33389
    33390
    33391
    33392
    33393
    33394
    33395
    33396
    33397
    33398
    33399
    33400
    33401
    33402
    33403
    33404
    33405
    33406
    33407
    33408
    33409
    33410
    33411
    33412
    33413
    33414
    33415
    33416
    33417
    33418
    33419
    33420
    33421
    33422
    33423
    33424
    33425
    33426
    33427
    33428
    33429
    33430
    33431
    33432
    33433
    33434
    33435
    33436
    33437
    33438
    33439
    33440
    33441
    33442
    33443
    33444
    33445
    33446
    33447
    33448
    33449
    33450
    33451
    33452
    33453
    33454
    33455
    33456
    33457
    33458
    33459
    33460
    33461
    33462
    33463
    33464
    33465
    33466
    33467
    33468
    33469
    33470
    33471
    33472
    33473
    33474
    33475
    33476
    33477
    33478
    33479
    33480
    33481
    33482
    33483
    33484
    33485
    33486
    33487
    33488
    33489
    33490
    33491
    33492
    33493
    33494
    33495
    33496
    33497
    33498
    33499
    33500
    33501
    33502
    33503
    33504
    33505
    33506
    33507
    33508
    33509
    33510
    33511
    33512
    33513
    33514
    33515
    33516
    33517
    33518
    33519
    33520
    33521
    33522
    33523
    33524
    33525
    33526
    33527
    33528
    33529
    33530
    33531
    33532
    33533
    33534
    33535
    33536
    33537
    33538
    33539
    33540
    33541
    33542
    33543
    33544
    33545
    33546
    33547
    33548
    33549
    33550
    33551
    33552
    33553
    33554
    33555
    33556
    33557
    33558
    33559
    33560
    33561
    33562
    33563
    33564
    33565
    33566
    33567
    33568
    33569
    33570
    33571
    33572
    33573
    33574
    33575
    33576
    33577
    33578
    33579
    33580
    33581
    33582
    33583
    33584
    33585
    33586
    33587
    33588
    33589
    33590
    33591
    33592
    33593
    33594
    33595
    33596
    33597
    33598
    33599
    33600
    33601
    33602
    33603
    33604
    33605
    33606
    33607
    33608
    33609
    33610
    33611
    33612
    33613
    33614
    33615
    33616
    33617
    33618
    33619
    33620
    33621
    33622
    33623
    33624
    33625
    33626
    33627
    33628
    33629
    33630
    33631
    33632
    33633
    33634
    33635
    33636
    33637
    33638
    33639
    33640
    33641
    33642
    33643
    33644
    33645
    33646
    33647
    33648
    33649
    33650
    33651
    33652
    33653
    33654
    33655
    33656
    33657
    33658
    33659
    33660
    33661
    33662
    33663
    33664
    33665
    33666
    33667
    33668
    33669
    33670
    33671
    33672
    33673
    33674
    33675
    33676
    33677
    33678
    33679
    33680
    33681
    33682
    33683
    33684
    33685
    33686
    33687
    33688
    33689
    33690
    33691
    33692
    33693
    33694
    33695
    33696
    33697
    33698
    33699
    33700
    33701
    33702
    33703
    33704
    33705
    33706
    33707
    33708
    33709
    33710
    33711
    33712
    33713
    33714
    33715
    33716
    33717
    33718
    33719
    33720
    33721
    33722
    33723
    33724
    33725
    33726
    33727
    33728
    33729
    33730
    33731
    33732
    33733
    33734
    33735
    33736
    33737
    33738
    33739
    33740
    33741
    33742
    33743
    33744
    33745
    33746
    33747
    33748
    33749
    33750
    33751
    33752
    33753
    33754
    33755
    33756
    33757
    33758
    33759
    33760
    33761
    33762
    33763
    33764
    33765
    33766
    33767
    33768
    33769
    33770
    33771
    33772
    33773
    33774
    33775
    33776
    33777
    33778
    33779
    33780
    33781
    33782
    33783
    33784
    33785
    33786
    33787
    33788
    33789
    33790
    33791
    33792
    33793
    33794
    33795
    33796
    33797
    33798
    33799
    33800
    33801
    33802
    33803
    33804
    33805
    33806
    33807
    33808
    33809
    33810
    33811
    33812
    33813
    33814
    33815
    33816
    33817
    33818
    33819
    33820
    33821
    33822
    33823
    33824
    33825
    33826
    33827
    33828
    33829
    33830
    33831
    33832
    33833
    33834
    33835
    33836
    33837
    33838
    33839
    33840
    33841
    33842
    33843
    33844
    33845
    33846235
    1

    1
    1

    1

    1

    1
    1

    1

    1

    1
    27
    27
    27
    27
    27

    27

    1
    1

    1

    1

    1

    3219
    16

    3203

    3203

    31301

    31301

    16

    31285

    31285

    31285

    31285
    16217

    31285
    15052

    31285

    3203
    1355

    1848

    1
    31285

    31285
    32031
    32031

    32031
    598
    598

    32031

    31269
    30521

    748
    748

    1
    4182

    4182
    4182

    4182

    3219

    3219

    963

    4182

    4182
    4182

    1
    5

    5

    5
    2

    2
    2
    2

    2
    2

    3

    1
    120

    120
    120

    120

    120

    1
    4302

    4302
    8568

    8568
    4266

    8568

    4302

    4302

    1
    8

    1
    1

    1

    1

    1
    846

    1
    846

    846
    846
    846

    1
    1
    1
    1

    1
    1
    1
    1
    1

    1
    1

    1

    1

    1
    846
    846

    1
    1

    1

    1
    3576

    1
    3576
    3576

    3576
    3576
    3576
    3576
    3576

    1
    1
    1
    1

    1
    1
    1
    1
    1
    1
    3576
    3576

    3576

    3576

    1
    16
    16
    16

    16

    1
    3574
    3574

    3574
    3574

    1

    1

    1

    90752

    90752
    105185

    105185
    67618
    37567
    37567

    105185
    7

    105185
    27674
    3

    27674

    63078
    1

    63078

    1

    3574

    1

    1

    1
    90035

    90035

    5
    5

    5
    2500
    2500

    5

    90030
    4

    90030
    22
    1

    22

    22

    90008

    90008
    62739

    62739

    61524

    1215
    1215

    62739

    27269
    16040
    3

    16040

    14818

    1222
    1222

    16040

    11229
    11229

    11229

    10114

    1115
    1115

    11229

    1
    1

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1
    1
    1
    1

    1

    1

    1

    1

    1
    2
    1

    1

    1
    744

    744

    744
    339
    339
    339

    744
    29

    744
    376

    744

    1
    511

    511
    268

    511

    511
    511

    511
    241

    511

    1
    22

    22
    22

    22
    22

    22
    22

    22

    22
    6
    6

    22
    16
    16

    22

    1
    1011
    1011

    1011
    531

    1011

    1011

    340

    340
    340

    1011
    477

    1011

    1

    14

    14

    14

    14
    27
    20
    20

    14

    1
    1

    1

    1
    1

    1
    256

    256
    2048

    256

    1

    1

    1

    1

    1

    1
    846

    1
    846
    846
    846
    846
    846
    846
    846
    846

    846

    846

    846

    846

    846

    846

    846

    846

    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1

    1
    1
    1
    1
    1
    1
    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1
    2

    1

    2

    2
    2
    2

    2
    2

    1
    1

    1
    723

    723
    723
    723
    719

    723

    723

    723

    723
    1
    1
    1

    723
    723
    723
    723
    723
    723
    723

    723

    723

    1
    13756
    904
    2
    2

    2

    2

    2

    904

    12852

    1
    1815

    1
    82

    1
    263

    1
    2612

    2

    1
    826
    809

    809

    809

    826

    1

    1

    298

    2

    56

    356

    356
    356

    356

    356

    356
    356

    356
    8

    356

    356

    356

    356
    356

    356

    356

    1
    2

    2

    2
    2
    2

    2
    2

    2
    3

    3

    3

    3

    3

    3

    3
    3

    1
    28858

    2466

    1
    96

    96

    96

    96
    96
    96

    96
    96
    96
    96

    1
    12

    12
    12

    12
    1

    1

    1
    1

    1

    1

    11

    10
    10

    10

    4

    6

    1

    11

    7
    7

    4
    4

    11

    1
    1

    1
    1

    1
    3
    3

    3
    3
    3

    3

    1

    1
    74

    74
    1
    1

    73

    74

    74

    1
    88

    113

    113
    4

    4

    4

    4

    2

    2

    2

    109

    113

    113

    88
    88
    88
    88

    88
    88
    88
    88

    88
    82
    76

    82
    82
    23

    82

    82
    82

    82

    82
    82

    88

    88

    1

    1
    5
    5
    5

    1

    178

    178
    178

    178

    178
    235

    235

    235

    35

    1
    1

    1

    1
    1
    3

    3
    3

    1
    1

    1
    1
    1

    1
    5
    4

    3
    3

    1
    2
    2
    2

    1

    32

    32
    32
    32

    235
    10

    10

    10

    10
    10

    10
    16
    10

    10
    10
    10

    235
    190
    23

    23
    23

    23

    11

    2
    2
    2

    9
    9
    9

    12
    12

    167

    5

    5
    2

    3
    3

    5
    5
    5

    5

    2

    2

    2
    2

    2

    2

    6

    1

    6

    6

    1

    1
    1
    2

    5

    1
    1
    2

    4

    6

    6

    1
    1

    1
    2
    1

    1

    1
    1
    1

    1

    1
    1
    1
    1

    1

    1
    9
    27
    5
    5
    5

    9
    1

    1

    8

    8

    8

    8
    3
    3
    3

    3
    5
    2
    2
    2

    3
    3

    8
    5

    1

    1
    1

    4

    2
    2

    8
    5
    5

    8

    1

    1
    1

    1
    1

    1

    1
    1

    1

    1

    1
    1
    1

    1
    1

    1
    1

    1

    1

    1
    1
    1

    1
    1
    1

    1
    1
    1

    3
    3
    3

    2
    2
    2

    134
    87
    87

    134

    178

    1
    224

    1
    636

    636

    636

    636

    636

    636
    636

    636
    265

    426

    426
    426

    426

    265
    428

    428
    4

    4

    4

    2

    2

    424

    265

    263

    263
    263

    263
    263
    263

    636
    636

    1
    204
    204
    204

    1
    6

    6

    6

    4

    2

    2

    4

    4

    4
    4

    4
    4
    4

    4
    4

    2

    2

    6
    2

    1
    11

    11
    47
    47
    4

    7

    1
    1662

    1662
    1
    1
    1661
    1661

    1662
    1662

    1
    1817

    1817

    561

    2
    2

    2

    2

    559
    27599

    27599
    27597

    2

    1256

    1256
    1249

    7

    1815

    1815
    1815

    1815
    1815
    1815

    1815

    1
    28855
    28855

    28855

    28855

    28855

    28846

    28846
    199

    28846

    28846

    203

    28846
    139

    28855
    28848
    11

    11
    9

    9

    2

    2

    2

    28837

    28846

    7

    1
    28791

    1
    425

    1

    1
    28959

    28959
    28959
    28959

    28959
    17
    17

    28959

    1
    539

    539
    539
    539

    539
    2
    2

    1
    113
    113

    1

    1
    33

    33
    33

    33

    33

    1

    1
    1

    1
    1

    1

    1
    6

    6
    2
    2

    1

    1
    27
    27
    27

    1

    5

    5
    5

    38

    38

    33

    5

    1
    3
    3

    1
    2083
    2083
    2083

    2083

    1

    1727
    3

    1727

    1727

    1
    1727

    1727

    1727

    1727
    1727

    1727
    50821

    1727
    1727

    1727
    1

    1

    2

    1

    1726

    3

    3

    1723

    1723
    1723
    1723
    1723

    1723

    1
    1
    1
    1

    1
    1

    1
    1

    1

    1

    1

    1723
    408
    408

    408
    408
    408

    408

    370

    1315

    1723
    1353
    35
    35

    35

    1318
    1318
    1318

    1353

    1723
    78
    78
    78

    1723

    2
    2
    2

    2
    1

    1

    1723
    1

    1
    1

    1723
    2

    2
    2

    1723

    963
    963
    963
    963

    1723
    28
    28

    1723
    2
    2
    2

    1723
    1
    1
    1

    1
    1

    1723
    1
    1
    1

    1723

    1723

    1706
    1706
    3543
    9
    3
    6
    4

    1706

    1706
    6
    6
    6

    6

    6
    222

    222
    840
    840

    108
    72

    36

    840

    768

    198

    6

    1706
    2
    2

    2
    2
    2

    2
    4

    4

    4

    10

    4
    4

    2

    1706
    2
    2

    2
    2
    2

    2
    4

    4
    4

    4

    24

    11

    4

    2

    1723
    17
    17
    17
    17
    17

    1723
    1723
    1723
    1723

    1
    3

    1
    1

    1
    1

    1

    1
    2

    2
    1

    1

    2
    2

    2

    1

    1
    10
    6
    4
    4

    4
    3

    4
    1

    2

    6

    4

    1
    1736
    3
    2

    2
    2

    2

    2

    2

    1

    1733

    1
    1
    1
    1

    1
    1

    1

    1

    1

    1

    78

    78

    77

    149689

    149689
    153758

    153758
    144110
    9648
    9648

    153758
    46250

    103439

    78

    1

    1
    1723

    1723
    1723
    1723

    1723
    890

    441

    441

    395
    395

    395

    395

    890
    22
    22
    22

    22
    22

    22

    17

    17

    22

    22

    10

    890

    890
    2
    2
    2

    2

    2

    1723
    28

    28

    32
    43
    43

    43
    43

    43

    43
    43

    28

    43

    43
    1
    1

    28
    28

    1723

    1
    43

    43
    1

    1
    1
    1

    42

    1
    196
    184

    12

    1
    8

    1
    8

    8

    8
    9
    9
    9
    9
    9

    9

    9

    9
    9

    8

    8

    8

    8

    1

    1
    28855

    28855
    4

    28851
    20
    20

    20
    16
    3
    3

    28855

    1
    29

    29
    29

    29

    29
    28

    16

    16

    12

    1

    29

    29

    29
    29

    29
    29

    29

    29

    1
    12
    12

    1
    1

    1
    1

    1

    1

    1

    1

    1

    1
    100

    100

    99

    1

    1

    1
    1

    1
    100

    100

    1

    1

    1

    1

    1
    1
    1

    1

    1
    1

    1

    1

    1

    1

    1

    1
    1
    1

    1117

    5

    5

    1122

    1122
    1122
    413

    709

    709
    705

    709
    709

    709
    1

    709

    1
    1
    1

    709
    276

    709

    709

    1

    1
    267

    267

    267
    173
    173

    173

    173

    267
    21

    267

    1
    1

    1

    1

    1
    19

    1
    19

    19
    19
    19
    19

    1
    1
    1
    1
    1
    1
    1

    1
    1
    1

    1
    12

    1
    1

    1

    1
    23
    19
    19

    4

    1

    1

    1

    1
    21
    21

    21
    2

    19

    21
    21
    21
    21

    21

    21
    21

    21
    21

    21
    21

    21

    21

    21

    1
    21
    21

    21
    21
    21

    21
    21

    21
    21

    21

    21

    19

    21

    1

    28

    18

    18
    18

    6
    6

    4
    4

    1

    1

    1

    1

    1

    1
    12

    1

    1

    1

    1
    269
    269

    1
    19

    19

    19

    19

    19

    19

    19

    1

    1

    1

    1
    1

    1
    2

    1
    2
    2
    2

    2

    1

    1

    1

    1

    26
    26

    26

    26
    28
    2

    24

    3

    3
    6

    6
    6

    6

    6
    6

    3

    1
    6
    6

    6

    1

    1

    1

    1

    1
    1

    1
    1
    1

    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1
    269

    1
    269
    269
    269
    269
    269

    1

    1

    1

    1

    1

    1
    1

    1
    1
    1
    1
    1

    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    269

    1

    1

    1

    1

    1
    1337

    1337

    1337

    1

    1
    1

    1
    2
    2

    2
    2

    1

    1
    1

    1
    2
    2

    2
    2

    2
    2

    1

    1

    263
    262

    262

    262
    168
    168

    262

    262
    262

    263

    5
    5

    5

    5
    5
    5

    5

    5
    5

    5

    1

    272

    272

    272

    272

    272

    1

    1
    1

    1

    1

    1
    7

    1
    7
    7

    1
    1
    1
    1
    1
    1
    1
    1
    1

    1
    1

    1

    1

    1

    1
    10

    10
    10

    10
    9

    10
    3

    3
    7

    7

    1

    3

    3

    7

    10

    10

    1

    1
    1

    1
    1

    1

    1
    11

    1
    3
    3

    3

    1

    1

    1

    1

    1

    1

    1

    1
    1
    1

    1

    1
    7

    7

    7

    7
    2

    5
    5

    5

    5

    1

    1
    1

    1

    1

    1
    1

    1

    1
    1
    1
    1

    1
    1
    1
    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1
    1
    1
    1

    1

    1
    11

    11

    11
    3

    11

    1

    1
    5

    5

    5
    5
    5
    5

    5
    265
    133

    133
    84
    84

    49

    132

    132
    63
    63

    69

    265

    265
    212

    53
    53
    53

    5

    1

    1

    1

    1
    3

    1
    3

    3
    3
    3
    3
    3

    3

    1
    1
    1
    1
    1
    1
    1

    1
    1
    1
    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    2

    2

    2

    2
    2
    2

    2

    1
    3

    3

    3

    1

    1
    2
    2

    2

    2
    2

    2
    2

    2

    2
    2

    2

    2

    2
    2
    2
    2
    2

    2

    1
    4

    4

    1

    1
    2
    2
    2

    2

    2

    2

    2

    2

    2

    2

    2

    2

    2

    2

    2
    6

    6

    6

    6

    6

    6

    6
    6

    6

    6

    6

    6

    6

    6

    2

    2

    1

    1
    2
    2
    2
    2
    2

    2
    2

    2

    2

    1

    1

    1
    2
    2
    2
    2

    2

    1
    269
    269

    1

    1
    1
    1
    1

    1
    1

    1

    1

    1
    1

    1

    1
    1

    1
    1

    1
    1
    1

    1

    1
    1

    1

    1
    1

    1

    1

    1

    1
    1

    1
    1
    1

    1

    1

    1
    1

    1
    1

    1

    1

    1
    1

    1
    2
    2
    2

    2
    2

    2
    6
    6
    6

    2

    2

    2

    1

    1
    1

    1

    1
    1

    1

    1
    1
    1

    1
    1

    1
    1
    1

    1
    1

    1
    1
    1

    1

    1

    1

    1

    1
    846
    846

    1

    1

    1

    1
    1
    1

    1

    1

    1

    1

    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1
    3

    1
    3
    3
    3
    3
    3

    3

    3
    3

    3
    3
    3

    3
    3

    1
    1
    1
    1

    1
    6

    1
    3

    1

    1
    1
    1
    1
    1

    1
    3
    3

    3
    3

    1

    3

    3

    3
    3

    3

    3

    3

    1
    4

    4

    4

    4

    4
    4

    4
    4
    4

    4

    4

    4
    4

    4

    1

    1

    1

    1

    1

    1
    1
    1

    1
    1
    1

    1

    1

    1

    1
    1

    1

    1
    1

    1
    6
    1
    1

    1

    1

    1

    1
    1

    1
    9
    9
    9

    1

    1
    1

    1
    2
    2

    2

    2

    1
    1

    1

    1

    1
    2
    2
    2
    2
    2

    2

    2

    2

    1
    8

    1

    2

    1

    1
    3

    3

    3
    3
    3

    3

    1

    1

    1
    1

    1

    1
    13

    1
    13
    13
    13
    13
    13

    13

    13
    13

    13
    13
    13

    13
    13

    1
    1
    1

    1
    26

    1
    13

    1
    4

    1
    1
    1
    1
    1

    1
    13
    13

    13
    13

    1

    13

    13

    13
    13

    13
    9

    13
    1037

    13

    1
    1046

    1046
    33
    33

    1046
    1046

    1046

    1
    1

    1
    1
    1

    1
    1

    1

    1

    11

    11

    1

    1
    9

    1
    10

    1
    45

    45

    45
    69
    69

    45

    1
    13

    13

    13
    21
    21

    13

    1

    1

    1
    1

    1

    1
    13

    1
    13
    13
    13

    13
    13

    13
    13

    13
    13

    13

    1
    1

    1
    26

    1
    13

    1
    2

    1
    1
    1
    1
    1

    1
    13
    13

    13
    13

    1

    13

    13

    13
    13

    13
    9

    13
    10037

    13

    1
    10041

    10041
    28
    28

    10041

    10041
    10065

    1

    1
    1

    1
    1
    1

    1

    1
    1

    1

    5

    5

    1

    1
    10065

    10065

    10065

    10065

    10065

    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    10065

    10065

    10065

    10065

    10065

    1
    1

    1

    1
    9

    1

    11
    11

    11
    14
    11
    11

    3

    8

    1
    43

    43

    43
    62
    62

    43

    1
    13

    13

    13
    19
    19

    13

    1
    10042

    10042

    10042
    10067

    10067
    10091

    10066

    25
    45

    10042

    1

    1
    1

    1

    1
    2826

    1
    2826
    2826
    2826

    1
    1

    1

    1
    2
    2
    2

    1
    6
    6

    1
    6
    6

    1
    29811

    1
    876

    876
    448
    448
    416

    32

    428
    428

    21
    21

    21
    63

    63
    63
    63

    21
    407
    407

    1
    1617
    1617

    1
    86880
    86880
    86880

    1
    1

    1

    1
    846

    1
    846

    1
    1

    1
    1815

    1815

    1815

    1

    1

    1

    1
    1

    1
    1

    1

    1

    1

    137
    76
    53

    23

    137
    137

    137
    137

    37
    30
    7

    23

    37
    37

    37
    37

    28928

    2037
    369

    369
    400

    400
    400
    206
    178

    28

    400
    400

    400

    400
    186

    400

    399

    400

    285

    1

    1

    1

    2

    4156
    4152
    3784

    368

    368
    400

    368

    4

    4200

    4210

    2986

    2986
    2977

    2977

    9

    9
    4990

    9

    2986

    29505

    384505

    1214
    1210
    1210
    1210
    1210
    1210

    4

    3197

    2866

    5

    5
    6
    6

    6

    5
    5

    5

    11

    11
    6

    5

    11

    5

    7055

    1

    1

    1

    1

    1

    852
    852
    852
    852

    852

    2
    2
    2
    2

    2

    1

    1
    1

    1

    21
    21

    21

    39

    39

    39
    39
    39

    39
    37

    39

    6280

    6280
    395

    395
    393
    393

    393

    398

    398
    398

    395

    16

    14
    14

    14
    14

    2
    2
    2

    2
    2

    6280

    2271

    2271
    2016

    2016
    2016
    1707

    2016
    312
    266

    312

    255

    2271

    1

    1

    57906

    57906
    4

    57906
    4

    57906
    57906

    57906

    957

    57906

    957

    57906

    57906

    57906

    4347

    47
    34

    4300
    4114

    53559
    16
    11

    53543
    29573

    29573

    29573

    29573

    29573

    29573

    2

    29571

    2810

    2810
    2810
    1749

    1061

    2810

    29571
    8

    8
    4

    4

    29571

    26753

    2455
    2444

    24
    24
    27

    27

    17

    24
    17

    7

    2420

    44

    44
    142

    142

    44

    44
    44

    2376

    2376

    2376
    1021

    1355

    11

    11

    11
    4

    7

    24298
    3268

    21030

    676
    676
    2427

    2427

    63

    676
    63

    613

    20354

    29571
    23369

    34537

    2810

    128

    1018

    8

    806

    20

    10

    70
    103
    52

    18

    4
    5
    3

    1

    275
    266

    266
    496
    50

    216
    9
    9

    413
    405

    405
    1297
    46

    359
    8
    8

    36

    36
    36
    36

    36

    2

    34

    34

    5

    5
    5

    5
    5
    5

    5
    3

    2

    17

    17

    17

    17
    17

    17
    4

    4
    4
    4

    4
    4

    13

    17
    17

    78

    78

    78
    88
    142

    142

    142
    142

    142

    142

    1

    141
    141

    142

    434
    434
    434
    434

    434
    1755
    1755

    1755

    1341

    24
    24

    20

    24
    8

    24

    434
    434

    434
    434

    434
    434

    4
    4

    11

    414

    434

    434

    430

    8

    8
    8

    8
    26

    24

    422

    4

    78

    450

    450

    410

    362

    48

    410
    16

    394

    40

    40
    44
    44
    44

    44

    28

    24

    4

    28

    16
    16

    40

    52

    52
    4

    1

    1

    244294
    233292

    11002
    5716
    5286
    5180

    106

    47963
    30670

    17293
    8292
    9001
    7338

    1663

    1

    1

    1

    8

    8
    8

    8

    8
    8

    8

    8

    8

    8
    8
    15
    8
    8

    8

    2

    2
    6

    6
    2

    2
    2

    2
    6

    2

    1

    1

    1

    21

    21

    21
    21

    21
    21
    21

    21

    21

    1

    1
    1
    1
    1

    1
    1
    1
    1

    1
    1
    1
    1

    1

    2

    2
    2
    2
    2

    2
    2
    2
    2

    2
    2
    2
    2

    2

    1

    1
    1
    1
    1

    1
    1
    1

    1

    1

    1
    1

    1

    1
    1
    1

    1

    1

    1

    1

    1

    58772

    26

    26
    26
    21

    58751

    25

    25
    19
    19

    19
    19

    19
    19
    19

    11
    11

    4
    4

    4
    4

    19

    15
    15

    4
    4

    19

    19

    1
    1

    1

    18
    18
    18

    18

    18

    18

    6

    12

    13

    22

    22
    1
    1

    1
    1
    1

    21

    1

    1

    97

    97
    91

    5

    1

    1
    1

    3
    3

    11

    6

    1

    1
    1

    3

    5

    1

    1

    1
    2

    1
    2
    2

    2

    1
    1
    1
    1

    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    2
    2

    1

    1

    1

    1
    1815
    1815
    1815

    1
    1815

    1
    1

    1
    1815

    1

    1
    16497
    16493

    16493

    8663
    8663

    8663

    7830
    7830
    7830
    7830

    16493

    4

    1
    1315
    1315

    1
    5303

    5297

    5297

    6

    1

    1
    1811
    1811

    1
    1

    1
    34
    31
    31

    34
    34

    34
    33

    33
    128
    128

    128

    96

    32

    32
    462
    424

    33

    34
    390025

    390025

    385719
    385719
    386933
    385719

    4306
    5388

    5388
    352

    5388
    786

    4602

    4306

    4306
    4302

    4

    8

    8

    4

    1
    548

    548

    86
    516
    516

    462

    548

    1
    390025

    390025
    1641

    1641
    1641
    1641

    1641

    388384

    1

    1

    1

    1
    2

    1
    2

    2
    2
    2
    2

    2
    1

    1
    1
    1
    1
    1
    1
    1

    1
    1
    1

    1

    1
    1
    1
    1

    1
    1

    1

    1

    1
    1

    1
    1

    1

    1
    4
    2
    1

    2
    2

    2

    1
    3

    1

    1

    1

    2

    2

    2

    1
    2

    2
    2
    2

    2

    2

    2

    1
    2

    2

    2
    2
    2

    2

    2

    2

    1
    1

    1

    1
    7
    6
    4
    4

    4
    4

    4

    6
    3

    3

    1

    1

    1
    1
    1

    1
    1

    1
    1

    1

    1
    1

    1

    1

    1

    1

    1
    2

    2

    2

    2

    2
    2

    2

    2

    1

    1
    1

    1

    1
    13788

    1
    13788
    49

    1
    1
    1

    1
    49
    49
    49
    49

    1

    1

    1

    1
    14522

    14522
    19738

    19738

    19738
    653
    549

    549
    569

    104

    104
    128

    19085
    8801

    10284

    14522

    1
    1773
    1773

    1
    1928

    1928
    1928

    1928
    1240
    1240
    1135
    123

    1012

    1135
    155
    147

    155

    980

    1928

    1

    1
    558564

    1
    570720

    570720
    557240

    13480
    13480

    13033
    17

    17
    30

    17

    13463

    13463
    12373
    12373

    13463
    13463
    13463

    13463
    26450

    26450

    224
    447

    224

    26226
    13201

    13025

    13239

    1

    1
    43

    43
    43
    43

    43
    43
    43

    43
    61

    61
    43
    43

    18

    43

    1
    7156
    7156

    7156
    7156

    7156

    7156

    1847

    1847

    5309

    7156

    1
    19621
    5

    19621

    1
    1

    1

    1
    269

    1

    1
    269

    269
    10

    269
    12

    269
    269
    269

    269

    1
    1
    1

    1
    1
    1
    1
    1
    1
    1
    1

    1

    1

    1

    1
    1713
    269
    269

    1444

    1
    6

    6

    1
    12
    12

    1
    10
    10

    1
    1

    1

    4

    4
    4
    4

    1

    1
    12

    12
    10

    10

    10
    10

    10
    10
    10

    10
    10

    2
    2

    2
    2

    1
    10

    10
    10

    10
    10
    10

    10
    10

    1
    10

    10
    10
    10

    10

    1
    12

    12

    12
    12

    12

    1
    1422

    1422
    1361

    1422

    1

    711
    709

    2
    2

    721

    721
    709
    709

    709
    709

    721

    2

    2

    2
    2
    2

    2
    2

    2

    1
    5

    5
    5
    5

    5
    5
    5
    5

    5

    5

    1
    6

    6
    6

    6
    6
    6

    5
    5

    6
    6
    6
    5

    6

    1

    1

    1
    269
    269

    1

    1

    1
    1

    1

    1
    2

    1

    1

    1
    2

    2
    2
    2

    2

    2

    2

    1
    2

    2
    2

    2

    2
    2

    2

    2
    2

    1

    1

    1

    1
    2

    1

    2

    2
    2

    1

    1

    1

    2

    2
    2

    2
    2

    2

    1

    2

    2

    2
    2

    2
    2

    2

    1
    2

    2

    2

    2
    2

    2

    2
    2

    1
    2

    2
    2

    2

    2

    2
    2

    1

    1

    1

    1
    57
    57
    57
    57

    57

    57

    57

    1

    1
    7
    7

    7
    7

    7
    7

    7
    7
    7

    7

    7

    7

    1

    1
    1
    1

    1
    1

    1
    1

    1
    1

    1
    1

    1
    8

    6
    4

    6

    2

    205982
    3

    205979

    1
    2
    2
    2

    2

    205979
    1

    1

    205978

    1
    2

    2

    2

    1

    8

    8
    10

    8

    1
    4200

    4200

    205982

    205982
    411961

    411961

    4

    205978

    1

    1

    1

    25

    25

    23

    23

    23
    20

    3

    23

    8
    8

    79

    79
    79

    79

    79

    79
    79
    612
    612

    79

    67
    85472
    18041
    18041

    67431

    67
    9

    9
    4493

    4493
    4493
    4493

    4493

    58

    1

    1

    1

    1

    1

    1

    1

    1

    1
    59

    1
    1
    1
    1
    1
    1
    1

    1
    1
    1
    1
    1
    1
    1
    1
    1

    1
    59

    59
    59
    59
    59
    59

    59

    59
    46

    59

    1
    185

    185

    185
    185
    185

    185

    70

    115

    115

    103

    103

    12

    10
    2
    2

    2

    115

    115

    115
    50

    50
    50

    115
    109

    109
    109

    115
    6

    6
    6

    115

    115

    115
    11

    11
    11

    115
    104

    104
    104

    115

    1
    50

    50

    50

    50

    1
    109

    109
    109

    9

    9

    1
    6

    6

    4

    6

    2

    1
    11

    11
    11
    11

    11

    11

    1
    104

    104
    104

    104

    4

    4

    100

    104
    100

    104
    4
    4

    4
    4

    4

    1

    1

    1

    1

    1
    78

    1

    1
    5

    1

    1

    1

    1
    58

    58

    56

    1

    1

    56

    1
    1

    56

    6

    56

    56

    56

    185

    56

    56
    56

    56
    10

    46

    56

    2

    1
    185

    185
    185

    185

    155
    155

    155

    155

    155

    59
    59

    59
    59
    59

    96
    96

    155

    14
    14

    14

    14

    14

    1
    1
    1

    1

    1

    1

    1

    1

    14

    16
    16

    16

    16

    4
    4

    4
    4

    16

    1
    46

    46

    1

    1
    12

    1
    5

    1
    61

    1

    1

    1
    3

    1
    9
    9
    5
    5

    9
    9

    9

    9
    5

    9
    9

    9
    9

    9

    9

    9
    9
    9
    9
    9
    9
    9

    9

    1
    3
    3

    3

    3

    3
    3

    3
    3
    3

    3
    3

    3
    3

    3
    3

    1

    1

    1

    14

    6

    59

    79
    20

    20

    20

    79
    6

    79
    20
    20

    79
    20

    79
    6

    79
    20

    59

    1
    6
    6
    6

    6
    6

    1

    1

    1

    1

    1
    13
    7
    7

    7
    7

    7
    7

    7

    6

    1
    101
    21

    21
    21

    21

    80

    1
    45

    45

    27

    27
    27

    27

    27
    27

    45

    18
    13

    18

    13
    24

    18
    18

    18
    21
    32
    32

    18

    18
    32

    45
    11

    34

    45

    1
    13

    13

    1

    1

    1
    2

    2
    2
    2

    2

    2

    2

    1

    1
    37

    1

    1
    59
    59

    59
    59

    59

    1

    1

    1
    27

    27

    1
    846
    846

    1

    1

    1
    5
    5
    5

    5

    1
    269
    269

    1
    73

    73

    73
    14

    59
    59

    59

    59

    59

    1

    1

    1
    1

    1

    1

    1
    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    22
    22
    22
    22

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    110
    110
    104
    104
    104
    172

    104
    52
    52

    1

    1

    1

    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    4

    1
    3

    1
    4

    1

    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1
    1

    1
    7
    1

    1

    1

    1

    1

    1

    1

    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1
    22
    22

    22

    1
    52
    52

    52
    52
    30

    22

    52

    22

    1

    1

    1

    1

    1
    1
    1
    52
    52

    52

    82
    104

    82

    22

    1

    1

    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    2

    1
    1

    1

    1

    1
    2

    1
    1
    1

    1

    1

    1
    2

    1
    1

    1

    1

    1
    52
    52
    52
    52
    52
    52
    52

    52
    52
    52

    1

    1

    1

    1
    1

    1
    1

    1

    1

    1
    1
    1
    1

    1
    1
    1
    1
    1
    1
    1
    1
    1
    1

    1

    1
    1
    256
    128

    128

    1
    1
    1

    256
    256
    256
    256

    256
    256
    256

    256
    256
    256
    256
    256

    256
    256
    256
    256
    256

    256
    1

    255
    255

    1

    1

    4
    4
    4

    4

    4

    4
    4
    240
    32

    208

    208

    28

    28

    28
    180

    24

    208

    4
    4
    240

    240
    180

    60

    240
    32

    208

    14

    14
    14
    14

    14

    14
    14
    14

    28

    28
    28
    28
    28

    28

    28

    364
    364
    364
    364

    364
    364
    364
    364

    28
    28
    28
    28

    28
    28
    28
    28

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1
    1
    1
    1
    1

    1

    2

    2

    4

    4
    4

    4

    4

    4

    4
    4

    4

    4

    1
    4
    4

    1
    7

    2

    2

    1

    1

    1

    2

    2

    4
    4

    1

    1

    1

    14
    14

    14
    14

    14

    1

    14
    14

    14

    14
    14

    14

    1

    28

    28
    4

    4

    24

    28
    112

    1

    1

    1

    2

    2

    2

    2
    2
    2

    2

    2

    2

    2

    1

    4

    4
    4
    4

    4
    2

    2

    2

    4

    28

    4

    4

    2

    2

    2

    2

    4

    1

    8

    2

    1

    1

    1

    2

    2
    2

    2

    2

    2

    2

    2

    2

    4
    2

    2

    1

    1

    4
    2

    4

    4
    4

    4

    1

    2

    2

    2

    2

    2

    2

    2

    2

    2

    2

    2

    2

    1
    1

    1

    1

    1

    1

    1
    1

    1

    325
    325

    325
    62

    325
    307
    271

    325

    325

    325

    251
    251

    251

    72
    277
    227

    72
    2

    1

    110

    110
    64

    46

    8

    50
    50
    50
    50

    50

    50

    13
    98
    98

    37
    216

    50

    50

    52
    52

    52
    52

    2

    2
    4
    4
    4

    4
    8
    8
    8
    8
    8
    8

    2
    4

    4
    4

    2

    1

    1

    4
    4

    4
    4
    48
    48
    48

    4

    4

    4
    4
    48

    4

    1

    2
    2

    2
    2
    218
    218

    2

    14

    14
    14
    302

    14

    1

    2
    2

    14

    1

    20
    20

    36
    14

    36
    36

    36
    36
    36
    36
    36

    36
    36

    4

    32

    36

    36

    36
    16

    40

    16
    16

    36

    1

    4

    4

    16

    16

    20

    20

    20

    12
    12

    12

    12

    8

    8

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1

    1

    2
    2
    2

    2

    2
    2
    76
    76
    76

    76

    76
    300

    2
    2
    2
    4

    2

    2
    2

    2
    2
    2
    2
    2

    2
    2
    2
    300
    224
    224
    224
    224

    2

    1

    1
    1

    1

    1

    1
    1
    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1

    1

    4

    4

    4

    4

    4
    4
    4

    4
    12
    8

    12
    12

    12

    12

    4

    4

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1

    1

    1
    1

    1

    1

    1
    1

    1

    1

    1
    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1

    1
    1
    64

    1

    16

    12

    192
    192

    192

    12

    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12

    12
    12
    12
    12

    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12

    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12

    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12

    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12
    12

    12
    12
    12
    12

    12
    12

    12
    12

    12

    12
    12
    12

    12

    12

    12

    12
    12

    12

    48

    48

    12

    1
    192
    192

    1
    192
    192

    1
    192
    192

    1
    192
    192

    1

    1

    1

    1
    1

    1

    1
    1

    1

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1

    1
    1

    1

    1

    1

    1
    1

    1

    1

    1

    1
    1

    1

    1

    1

    1
    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1
    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1

    1
    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1

    1
    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1
    1

    1
    1
    310
    310
    1118
    246

    64

    1
    72

    1
    1
    1
    310
    64
    8

    64

    64

    310

    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1
    1

    1
    1
    1

    1

    1
    1
    24

    24
    24
    24
    24

    1
    5
    25

    1
    1
    24
    24

    24
    168
    86
    86
    73

    13

    168

    85

    83

    24

    1
    1
    1
    25

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1
    1

    1
    160

    1

    1
    1
    1
    80

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    1
    1
    1

    1

    1

    209
    209

    1

    1

    1
    1
    1
    1
    1

    1

    1
    22

    22
    22

    22
    22
    52
    52
    52
    52
    52

    52
    52

    22
    22
    22

    1
    52
    52

    52
    52
    22

    1
    52
    52

    1
    52

    1
    1
    1
    1
    1
    1

    1

    1
    1
    1
    1
    1
    1
    1

    1

    1
    1

    1

    1

    1
    1

    1
    1

    1
    9

    1
    12

    12
    9

    9

    9

    9
    20
    9

    11

    9
    9

    1
    11
    11
    11

    11
    22

    22
    22
    11

    11

    1

    1
    1

    1

    1

    1

    1

    1

    1
    1
    1

    1

    1

    1
    1
    275

    1
    1
    274
    13265
    13265
    13265

    274

    1

    1

    1

    1

    1
    13277
    13277

    275

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1
    1

    1
    1

    1

    1
    1

    1

    1

    1
    1
    1
    1
    1
    1
    1
    1
    1
    1

    1

    1

    1
    10618

    10618

    10618

    10618

    1
    1
    1433

    1

    10618
    10618

    1
    9015

    9015
    6014
    6014
    6014

    3001
    3001

    9015
    1593
    7422
    4421
    3001

    3001
    3001

    1
    1
    1
    1

    1
    6295
    6295

    6295
    6295
    6295

    1
    10448

    10448
    6198
    6198

    6198

    10448

    1

    9124

    9124

    9124
    2829
    2829
    2817

    6295

    9124

    1481

    1
    1
    1
    1

    1
    19463

    19463
    19463

    19463
    1680

    1680
    1593
    1593
    1593

    1593
    1593

    1593

    17870

    1
    10448

    10448
    10448

    1
    10448
    10448
    10448

    10448

    1

    1
    10448

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1

    1
    19463

    1
    40776

    1

    1

    1
    1
    1
    1

    1
    1
    1
    1

    1

    1

    1

    38
    35

    3

    3

    3

    3

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1
    1

    1
    1
    1

    1

    1

    1
    112
    62
    62
    62

    1
    14
    15

    15
    14
    132
    132
    2

    130

    14

    1
    25
    75
    25

    1
    1
    1

    1
    1
    1

    1
    1
    1
    1
    1
    1

    1
    1

    1

    269

    269
    257

    12
    36
    12

    36

    12
    12

    12

    1

    1
    31

    1
    25
    25
    25
    25

    25
    25

    25
    25

    1

    1
    1506

    1506
    1494
    12

    1494

    1506
    1506

    1
    13

    13

    13

    1
    25

    1
    13
    12

    1
    12
    12
    12

    12
    12

    12
    12
    12

    12
    12

    12

    13

    13
    13
    13
    13

    13
    13
    13
    13
    13

    13
    13

    1
    39

    1
    12

    1
    13
    13
    39
    39
    26

    13

    1

    14
    112

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1
    1

    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1

    1

    1

    1
    10
    10
    10

    10

    10

    10
    10

    1

    10
    10

    1

    1

    1

    1

    1

    1
    1

    1
    1

    1

    1
    12
    12

    12
    12
    72

    12

    12
    12

    12
    12
    12
    12

    12
    12

    12
    12

    1
    12

    12

    12
    12
    12
    12
    12
    12

    12
    10

    12

    12
    12

    1

    1
    10

    10

    10
    10

    10

    10

    10
    10
    10

    10
    10
    10

    10
    10

    1
    1422

    1422

    1422
    1422
    1410
    1410
    1362
    1361

    1422
    1422

    1

    1

    1

    1

    1
    1444

    1

    1

    1

    1

    1
    1
    1

    1

    1

    1

    1
    1
    1
    1
    1

    1

    1
    1

    1
    1
    1

    1

    1

    1

    1

    2

    2

    2

    2

    2
    2
    2
    2

    2
    2

    2

    2

    2

    1
    2
    2
    2

    2

    2

    2

    2

    2
    2

    2
    2
    2
    2
    2

    2

    2

    2
    2
    2

    2
    2
    2
    2
    2

    1
    2

    1

    2
    2
    2

    2
    2
    2

    1
    2

    2

    2

    2

    1

    1

    1
    1
    1
    1

    1
    1
    1
    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1
    1
    1
    1

    1

    1
    4
    4
    6
    6

    6

    6
    39
    39

    4

    1
    2
    2

    1

    8
    8
    8

    1

    1
    1
    1
    1
    1
    1

    1

    1

    1
    1

    1
    1

    1
    1
    256

    1

    1
    2

    2
    110
    110

    110

    2

    2
    110
    110

    110

    110

    2

    1

    2
    2

    2
    2
    124

    2

    1
    2

    1

    1

    1

    1
    2

    2

    2
    2

    2
    110
    110

    2
    2

    2

    1

    1

    1
    1

    1
    256
    256
    2048

    256

    1

    1

    1

    1

    1
    1
    1
    1
    1

    1
    1

    1
    1
    1

    1
    1

    1
    1

    1

    1

    1
    1
    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1
    1

    1

    1
    1
    1
    1
    1
    1
    1

    1
    1
    1
    1

    1

    1

    1

    70520

    1
    6

    6
    6

    6

    6
    6
    6
    6
    6
    6
    6
    6

    1
    2
    2
    2

    1

    1

    6
    6

    1
    2

    2
    2

    2

    2
    2
    2

    2
    2

    2

    1
    1
    1
    1
    1
    1
    1
    1

    1

    1
    1

    1
    1
    1

    1

    1

    1

    1

    1

    1
    1

    1

    1
    1

    1
    1
    1
    1

    1
    1

    1
    1

    1
    111
    111

    111
    111

    111

    111
    109

    2
    2

    2
    2
    2

    2

    2

    1

    1

    1
    2
    2

    2

    2

    111
    111
    111

    111

    109
    109

    105
    105
    105

    109
    109
    109

    109

    1

    1

    109
    1

    1

    1
    1
    1
    1

    1
    1
    1

    1
    1
    1

    1

    108

    105

    105

    105
    105
    105

    3
    3
    3

    2

    2

    2

    2
    2

    2
    2

    2

    1

    1

    1
    10
    10
    10
    10
    10

    1

    1

    1
    2

    2

    2
    2
    2
    2

    2
    2
    2
    2
    2
    2
    2

    1
    2
    2
    2
    2
    2
    2
    2
    2
    2
    2
    2

    2
    2
    2

    2

    2

    2

    2

    2
    2
    2
    2

    2

    2

    2
    2
    2
    2
    2
    2

    2

    2

    2

    2
    2

    2

    2

    2
    2
    2
    2
    2
    2

    2
    2
    2

    2

    2
    2

    2
    2

    2
    2

    2

    2

    2

    2

    2
    2
    2
    2

    2

    2

    1
    2

    2

    2
    2

    2
    2
    2

    2

    2
    2

    2
    2
    2

    1
    2
    2
    2

    2

    1

    1
    2

    2

    2
    2

    2

    2

    2

    2

    2

    2
    2

    2
    2
    2
    2
    2

    2
    2
    2
    2

    2
    2
    2

    2

    2
    2

    2
    2

    2
    2
    2

    2

    1

    1
    2
    2

    2

    2

    2

    2
    2
    2

    2

    2

    2
    2

    2

    2

    2
    2

    2
    2
    2

    2
    2

    2

    2

    2

    2

    2

    2

    2
    2
    2

    2

    2

    2

    2
    2

    2

    2

    2
    2

    2

    2
    2

    2

    2

    2

    1
    2

    2

    2
    2

    2

    2

    1
    1
    1
    1
    1
    1
    1
    1

    1

    1

    1
    1

    1

    1
    1
    1
    1
    1

    1
    1
    1

    1
    1
    1

    1
    1
    1

    1
    1
    1
    1

    1

    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1
    1

    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1
    1
    1
    1
    1
    1
    1
    1

    1

    1
    1
    1

    1
    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1

    1463

    1
    1
    1

    1
    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1

    1
    1

    1
    1

    1
    1

    1
    1

    1
    1

    1
    1

    1

    3
    3
    3
    3
    3

    3

    1
    1
    1

    1
    6
    6
    6

    1
    2

    1

    56
    56

    1
    114
    54
    54
    54
    54

    60
    60

    1
    111

    1
    401
    401
    2933
    2933
    2933

    401

    1

    1

    6
    6
    6
    6
    6
    6
    6
    6
    6
    6
    6
    6
    6

    6
    96

    6

    6
    154
    154
    154

    154

    154

    83
    83
    83
    21

    83
    83
    83
    67

    6

    1

    7
    7
    7
    7

    7
    105

    7
    851
    851

    371

    1
    1
    1
    1
    1
    1
    1

    1
    1
    28
    28
    256

    1

    1
    1
    16
    16
    256

    1
    1
    14
    14
    254

    1
    16

    1
    1
    144
    144
    144

    1
    112
    112
    112

    1
    24
    24
    24

    1
    8
    8
    8

    1

    1
    30
    30

    1
    1
    1

    1
    4

    1144
    120
    76

    4
    4
    4

    1

    2
    2

    2
    2

    1

    1
    848
    848
    848

    1

    195
    195
    195

    440

    198

    440

    382
    382

    382

    195

    1

    2
    2
    2
    2
    2

    2
    2
    108
    108
    108

    108
    107

    1
    1
    1
    1

    1
    1

    1
    1
    1
    1
    1

    2

    1

    6
    6
    6
    6
    6
    6
    6

    6
    6

    6
    670
    80
    80

    590

    6
    3
    3
    3
    3

    3
    3

    6

    41

    6
    6

    77
    77
    77

    77

    77
    77

    77
    77
    77

    77
    77

    6

    6

    6

    1

    4
    4
    4

    4

    4
    4
    4

    4
    2
    2

    4

    4
    525
    525

    525
    436

    89
    71

    18

    18
    12

    6

    89
    89

    89
    34
    34

    55

    55
    55

    1

    1
    2

    2
    2

    2

    2
    4
    2

    2

    2

    1

    1

    2
    2

    2
    64

    2

    2
    6
    2

    1

    1

    2
    1
    1

    2
    2
    2

    2
    2

    2

    1

    1

    1

    2
    2

    2

    2
    2

    2

    2

    2

    2
    2

    2

    2

    2

    2
    2

    2

    2
    2

    1

    108
    108

    108
    108

    108

    107

    1

    1

    1
    1

    108

    1
    1
    1
    1
    1

    1

    2
    2

    2

    2

    2
    2

    2

    2

    2

    2

    2

    2

    1

     (function e(t,n,r){function s(o,u){if(!n[o]){Iif(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
    var Core = _dereq_('./core'),
    	CollectionGroup = _dereq_('../lib/CollectionGroup'),
    	View = _dereq_('../lib/View'),
    	Highchart = _dereq_('../lib/Highchart'),
    	Persist = _dereq_('../lib/Persist'),
    	Document = _dereq_('../lib/Document'),
    	Overview = _dereq_('../lib/Overview'),
    	Grid = _dereq_('../lib/Grid'),
    	NodeApiClient = _dereq_('../lib/NodeApiClient'),
    	BinaryLog = _dereq_('../lib/BinaryLog');

    Eif (typeof window !== 'undefined') {
    	window.ForerunnerDB = Core;
    }

    module.exports = Core;
    },{"../lib/BinaryLog":4,"../lib/CollectionGroup":8,"../lib/Document":11,"../lib/Grid":13,"../lib/Highchart":14,"../lib/NodeApiClient":30,"../lib/Overview":33,"../lib/Persist":35,"../lib/View":42,"./core":2}],2:[function(_dereq_,module,exports){
    var Core = _dereq_('../lib/Core'),
    	ShimIE8 = _dereq_('../lib/Shim.IE8');

    Eif (typeof window !== 'undefined') {
    	window.ForerunnerDB = Core;
    }
    module.exports = Core;
    },{"../lib/Core":9,"../lib/Shim.IE8":41}],3:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared'),
    	Path = _dereq_('./Path'),
    	sharedPathSolver;

    /**
     * Creates an always-sorted multi-key bucket that allows ForerunnerDB to
     * know the index that a document will occupy in an array with minimal
     * processing, speeding up things like sorted views.
     * @param {object} orderBy An order object.
     * @constructor
     */
    var ActiveBucket = function (orderBy) {
    	this._primaryKey = '_id';
    	this._keyArr = [];
    	this._data = [];
    	this._objLookup = {};
    	this._count = 0;

    	this._keyArr = sharedPathSolver.parse(orderBy, true);
    };

    Shared.addModule('ActiveBucket', ActiveBucket);
    Shared.mixin(ActiveBucket.prototype, 'Mixin.Sorting');

    sharedPathSolver = new Path();

    /**
     * Gets / sets the primary key used by the active bucket.
     * @returns {String} The current primary key.
     */
    Shared.synthesize(ActiveBucket.prototype, 'primaryKey');

    /**
     * Quicksorts a single document into the passed array and
     * returns the index that the document should occupy.
     * @param {object} obj The document to calculate index for.
     * @param {array} arr The array the document index will be
     * calculated for.
     * @param {string} item The string key representation of the
     * document whose index is being calculated.
     * @param {function} fn The comparison function that is used
     * to determine if a document is sorted below or above the
     * document we are calculating the index for.
     * @returns {number} The index the document should occupy.
     */
    ActiveBucket.prototype.qs = function (obj, arr, item, fn) {
    	// If the array is empty then return index zero
    	if (!arr.length) {
    		return 0;
    	}

    	var lastMidwayIndex = -1,
    		midwayIndex,
    		lookupItem,
    		result,
    		start = 0,
    		end = arr.length - 1;

    	// Loop the data until our range overlaps
    	while (end >= start) {
    		// Calculate the midway point (divide and conquer)
    		midwayIndex = Math.floor((start + end) / 2);

    		if (lastMidwayIndex === midwayIndex) {
    			// No more items to scan
    			break;
    		}

    		// Get the item to compare against
    		lookupItem = arr[midwayIndex];

    		Eif (lookupItem !== undefined) {
    			// Compare items
    			result = fn(this, obj, item, lookupItem);

    			if (result > 0) {
    				start = midwayIndex + 1;
    			}

    			if (result < 0) {
    				end = midwayIndex - 1;
    			}
    		}

    		lastMidwayIndex = midwayIndex;
    	}

    	if (result > 0) {
    		return midwayIndex + 1;
    	} else {
    		return midwayIndex;
    	}

    };

    /**
     * Calculates the sort position of an item against another item.
     * @param {object} sorter An object or instance that contains
     * sortAsc and sortDesc methods.
     * @param {object} obj The document to compare.
     * @param {string} a The first key to compare.
     * @param {string} b The second key to compare.
     * @returns {number} Either 1 for sort a after b or -1 to sort
     * a before b.
     * @private
     */
    ActiveBucket.prototype._sortFunc = function (sorter, obj, a, b) {
    	var aVals = a.split('.:.'),
    		bVals = b.split('.:.'),
    		arr = sorter._keyArr,
    		count = arr.length,
    		index,
    		sortType,
    		castType;

    	for (index = 0; index < count; index++) {
    		sortType = arr[index];
    		castType = typeof sharedPathSolver.get(obj, sortType.path);

    		if (castType === 'number') {
    			aVals[index] = Number(aVals[index]);
    			bVals[index] = Number(bVals[index]);
    		}

    		// Check for non-equal items
    		if (aVals[index] !== bVals[index]) {
    			// Return the sorted items
    			if (sortType.value === 1) {
    				return sorter.sortAsc(aVals[index], bVals[index]);
    			}

    			Eif (sortType.value === -1) {
    				return sorter.sortDesc(aVals[index], bVals[index]);
    			}
    		}
    	}
    };

    /**
     * Inserts a document into the active bucket.
     * @param {object} obj The document to insert.
     * @returns {number} The index the document now occupies.
     */
    ActiveBucket.prototype.insert = function (obj) {
    	var key,
    		keyIndex;

    	key = this.documentKey(obj);
    	keyIndex = this._data.indexOf(key);

    	if (keyIndex === -1) {
    		// Insert key
    		keyIndex = this.qs(obj, this._data, key, this._sortFunc);

    		this._data.splice(keyIndex, 0, key);
    	} else {
    		this._data.splice(keyIndex, 0, key);
    	}

    	this._objLookup[obj[this._primaryKey]] = key;

    	this._count++;
    	return keyIndex;
    };

    /**
     * Removes a document from the active bucket.
     * @param {object} obj The document to remove.
     * @returns {boolean} True if the document was removed
     * successfully or false if it wasn't found in the active
     * bucket.
     */
    ActiveBucket.prototype.remove = function (obj) {
    	var key,
    		keyIndex;

    	key = this._objLookup[obj[this._primaryKey]];

    	if (key) {
    		keyIndex = this._data.indexOf(key);

    		Eif (keyIndex > -1) {
    			this._data.splice(keyIndex, 1);
    			delete this._objLookup[obj[this._primaryKey]];

    			this._count--;
    			return true;
    		} else {
    			return false;
    		}
    	}

    	return false;
    };

    /**
     * Get the index that the passed document currently occupies
     * or the index it will occupy if added to the active bucket.
     * @param {object} obj The document to get the index for.
     * @returns {number} The index.
     */
    ActiveBucket.prototype.index = function (obj) {
    	var key,
    		keyIndex;

    	key = this.documentKey(obj);
    	keyIndex = this._data.indexOf(key);

    	Iif (keyIndex === -1) {
    		// Get key index
    		keyIndex = this.qs(obj, this._data, key, this._sortFunc);
    	}

    	return keyIndex;
    };

    /**
     * The key that represents the passed document.
     * @param {object} obj The document to get the key for.
     * @returns {string} The document key.
     */
    ActiveBucket.prototype.documentKey = function (obj) {
    	var key = '',
    		arr = this._keyArr,
    		count = arr.length,
    		index,
    		sortType;

    	for (index = 0; index < count; index++) {
    		sortType = arr[index];

    		if (key) {
    			key += '.:.';
    		}

    		key += sharedPathSolver.get(obj, sortType.path);
    	}

    	// Add the unique identifier on the end of the key
    	key += '.:.' + obj[this._primaryKey];

    	return key;
    };

    /**
     * Get the number of documents currently indexed in the active
     * bucket instance.
     * @returns {number} The number of documents.
     */
    ActiveBucket.prototype.count = function () {
    	return this._count;
    };

    Shared.finishModule('ActiveBucket');
    module.exports = ActiveBucket;
    },{"./Path":34,"./Shared":40}],4:[function(_dereq_,module,exports){
    "use strict";

    var Shared,
    	ReactorIO,
    	Collection,
    	CollectionInit,
    	Db,
    	DbInit,
    	BinaryLog;

    Shared = _dereq_('./Shared');

    BinaryLog = function () {
    	this.init.apply(this, arguments);
    };

    BinaryLog.prototype.init = function (parent) {
    	var self = this;

    	self._logCounter = 0;
    	self._parent = parent;
    	self.size(1000);
    };

    Shared.addModule('BinaryLog', BinaryLog);
    Shared.mixin(BinaryLog.prototype, 'Mixin.Common');
    Shared.mixin(BinaryLog.prototype, 'Mixin.ChainReactor');
    Shared.mixin(BinaryLog.prototype, 'Mixin.Events');

    Collection = Shared.modules.Collection;
    Db = Shared.modules.Db;
    ReactorIO = Shared.modules.ReactorIO;
    CollectionInit = Collection.prototype.init;
    DbInit = Db.prototype.init;

    Shared.synthesize(BinaryLog.prototype, 'name');
    Shared.synthesize(BinaryLog.prototype, 'size');

    BinaryLog.prototype.attachIO = function () {
    	var self = this;

    	if (!self._io) {
    		self._log = new Collection(self._parent.name() + '-BinaryLog', {capped: true, size: self.size()});

    		// Override the log collection's id generator so it is linear
    		self._log.objectId = function (id) {
    			if (!id) {
    				id = ++self._logCounter;
    			}

    			return id;
    		};

    		self._io = new ReactorIO(self._parent, self, function (chainPacket) {
    			self._log.insert({
    				type: chainPacket.type,
    				data: chainPacket.data
    			});

    			// Returning false informs the chain reactor to continue propagation
    			// of the chain packet down the graph tree
    			return false;
    		});
    	}
    };

    BinaryLog.prototype.detachIO = function () {
    	var self = this;

    	if (self._io) {
    		self._log.drop();
    		self._io.drop();

    		delete self._log;
    		delete self._io;
    	}
    };

    Collection.prototype.init = function () {
    	CollectionInit.apply(this, arguments);
    	this._binaryLog = new BinaryLog(this);
    };

    Shared.finishModule('BinaryLog');
    module.exports = BinaryLog;
    },{"./Shared":40}],5:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared'),
    	Path = _dereq_('./Path'),
    	sharedPathSolver = new Path();

    var BinaryTree = function (data, compareFunc, hashFunc) {
    	this.init.apply(this, arguments);
    };

    BinaryTree.prototype.init = function (data, index, primaryKey, compareFunc, hashFunc) {
    	this._store = [];
    	this._keys = [];

    	Iif (primaryKey !== undefined) { this.primaryKey(primaryKey); }
    	if (index !== undefined) { this.index(index); }
    	if (compareFunc !== undefined) { this.compareFunc(compareFunc); }
    	if (hashFunc !== undefined) { this.hashFunc(hashFunc); }
    	if (data !== undefined) { this.data(data); }
    };

    Shared.addModule('BinaryTree', BinaryTree);
    Shared.mixin(BinaryTree.prototype, 'Mixin.ChainReactor');
    Shared.mixin(BinaryTree.prototype, 'Mixin.Sorting');
    Shared.mixin(BinaryTree.prototype, 'Mixin.Common');

    Shared.synthesize(BinaryTree.prototype, 'compareFunc');
    Shared.synthesize(BinaryTree.prototype, 'hashFunc');
    Shared.synthesize(BinaryTree.prototype, 'indexDir');
    Shared.synthesize(BinaryTree.prototype, 'primaryKey');
    Shared.synthesize(BinaryTree.prototype, 'keys');
    Shared.synthesize(BinaryTree.prototype, 'index', function (index) {
    	Eif (index !== undefined) {
    		Iif (this.debug()) {
    			console.log('Setting index', index, sharedPathSolver.parse(index, true));
    		}

    		// Convert the index object to an array of key val objects
    		this.keys(sharedPathSolver.parse(index, true));
    	}

    	return this.$super.call(this, index);
    });

    /**
     * Remove all data from the binary tree.
     */
    BinaryTree.prototype.clear = function () {
    	delete this._data;
    	delete this._left;
    	delete this._right;

    	this._store = [];
    };

    /**
     * Sets this node's data object. All further inserted documents that
     * match this node's key and value will be pushed via the push()
     * method into the this._store array. When deciding if a new data
     * should be created left, right or middle (pushed) of this node the
     * new data is checked against the data set via this method.
     * @param val
     * @returns {*}
     */
    BinaryTree.prototype.data = function (val) {
    	Eif (val !== undefined) {
    		this._data = val;

    		Eif (this._hashFunc) { this._hash = this._hashFunc(val); }
    		return this;
    	}

    	return this._data;
    };

    /**
     * Pushes an item to the binary tree node's store array.
     * @param {*} val The item to add to the store.
     * @returns {*}
     */
    BinaryTree.prototype.push = function (val) {
    	if (val !== undefined) {
    		this._store.push(val);
    		return this;
    	}

    	return false;
    };

    /**
     * Pulls an item from the binary tree node's store array.
     * @param {*} val The item to remove from the store.
     * @returns {*}
     */
    BinaryTree.prototype.pull = function (val) {
    	if (val !== undefined) {
    		var index = this._store.indexOf(val);

    		if (index > -1) {
    			this._store.splice(index, 1);
    			return this;
    		}
    	}

    	return false;
    };

    /**
     * Default compare method. Can be overridden.
     * @param a
     * @param b
     * @returns {number}
     * @private
     */
    BinaryTree.prototype._compareFunc = function (a, b) {
    	// Loop the index array
    	var i,
    		indexData,
    		result = 0;

    	for (i = 0; i < this._keys.length; i++) {
    		indexData = this._keys[i];

    		if (indexData.value === 1) {
    			result = this.sortAsc(sharedPathSolver.get(a, indexData.path), sharedPathSolver.get(b, indexData.path));
    		} else Eif (indexData.value === -1) {
    			result = this.sortDesc(sharedPathSolver.get(a, indexData.path), sharedPathSolver.get(b, indexData.path));
    		}

    		if (this.debug()) {
    			console.log('Compared %s with %s order %d in path %s and result was %d', sharedPathSolver.get(a, indexData.path), sharedPathSolver.get(b, indexData.path), indexData.value, indexData.path, result);
    		}

    		if (result !== 0) {
    			if (this.debug()) {
    				console.log('Retuning result %d', result);
    			}
    			return result;
    		}
    	}

    	if (this.debug()) {
    		console.log('Retuning result %d', result);
    	}

    	return result;
    };

    /**
     * Default hash function. Can be overridden.
     * @param obj
     * @private
     */
    BinaryTree.prototype._hashFunc = function (obj) {
    	/*var i,
    		indexData,
    		hash = '';

    	for (i = 0; i < this._keys.length; i++) {
    		indexData = this._keys[i];

    		if (hash) { hash += '_'; }
    		hash += obj[indexData.path];
    	}

    	return hash;*/

    	return obj[this._keys[0].path];
    };

    /**
     * Removes (deletes reference to) either left or right child if the passed
     * node matches one of them.
     * @param {BinaryTree} node The node to remove.
     */
    BinaryTree.prototype.removeChildNode = function (node) {
    	if (this._left === node) {
    		// Remove left
    		delete this._left;
    	} else if (this._right === node) {
    		// Remove right
    		delete this._right;
    	}
    };

    /**
     * Returns the branch this node matches (left or right).
     * @param node
     * @returns {String}
     */
    BinaryTree.prototype.nodeBranch = function (node) {
    	if (this._left === node) {
    		return 'left';
    	} else if (this._right === node) {
    		return 'right';
    	}
    };

    /**
     * Inserts a document into the binary tree.
     * @param data
     * @returns {*}
     */
    BinaryTree.prototype.insert = function (data) {
    	var result,
    		inserted,
    		failed,
    		i;

    	if (data instanceof Array) {
    		// Insert array of data
    		inserted = [];
    		failed = [];

    		for (i = 0; i < data.length; i++) {
    			Eif (this.insert(data[i])) {
    				inserted.push(data[i]);
    			} else {
    				failed.push(data[i]);
    			}
    		}

    		return {
    			inserted: inserted,
    			failed: failed
    		};
    	}

    	if (this.debug()) {
    		console.log('Inserting', data);
    	}

    	if (!this._data) {
    		if (this.debug()) {
    			console.log('Node has no data, setting data', data);
    		}
    		// Insert into this node (overwrite) as there is no data
    		this.data(data);
    		//this.push(data);
    		return true;
    	}

    	result = this._compareFunc(this._data, data);

    	if (result === 0) {
    		Iif (this.debug()) {
    			console.log('Data is equal (currrent, new)', this._data, data);
    		}

    		//this.push(data);

    		// Less than this node
    		if (this._left) {
    			// Propagate down the left branch
    			this._left.insert(data);
    		} else {
    			// Assign to left branch
    			this._left = new BinaryTree(data, this._index, this._binaryTree, this._compareFunc, this._hashFunc);
    			this._left._parent = this;
    		}

    		return true;
    	}

    	if (result === -1) {
    		if (this.debug()) {
    			console.log('Data is greater (currrent, new)', this._data, data);
    		}

    		// Greater than this node
    		if (this._right) {
    			// Propagate down the right branch
    			this._right.insert(data);
    		} else {
    			// Assign to right branch
    			this._right = new BinaryTree(data, this._index, this._binaryTree, this._compareFunc, this._hashFunc);
    			this._right._parent = this;
    		}

    		return true;
    	}

    	Eif (result === 1) {
    		Iif (this.debug()) {
    			console.log('Data is less (currrent, new)', this._data, data);
    		}

    		// Less than this node
    		if (this._left) {
    			// Propagate down the left branch
    			this._left.insert(data);
    		} else {
    			// Assign to left branch
    			this._left = new BinaryTree(data, this._index, this._binaryTree, this._compareFunc, this._hashFunc);
    			this._left._parent = this;
    		}

    		return true;
    	}

    	return false;
    };

    BinaryTree.prototype.remove = function (data) {
    	var pk = this.primaryKey(),
    		result,
    		removed,
    		i;

    	Iif (data instanceof Array) {
    		// Insert array of data
    		removed = [];

    		for (i = 0; i < data.length; i++) {
    			if (this.remove(data[i])) {
    				removed.push(data[i]);
    			}
    		}

    		return removed;
    	}

    	Iif (this.debug()) {
    		console.log('Removing', data);
    	}

    	Eif (this._data[pk] === data[pk]) {
    		// Remove this node
    		return this._remove(this);
    	}

    	// Compare the data to work out which branch to send the remove command down
    	result = this._compareFunc(this._data, data);

    	if (result === -1 && this._right) {
    		return this._right.remove(data);
    	}

    	if (result === 1 && this._left) {
    		return this._left.remove(data);
    	}

    	return false;
    };

    BinaryTree.prototype._remove = function (node) {
    	var leftNode,
    		rightNode;

    	Eif (this._left) {
    		// Backup branch data
    		leftNode = this._left;
    		rightNode = this._right;

    		// Copy data from left node
    		this._left = leftNode._left;
    		this._right = leftNode._right;
    		this._data = leftNode._data;
    		this._store = leftNode._store;

    		Eif (rightNode) {
    			// Attach the rightNode data to the right-most node
    			// of the leftNode
    			leftNode.rightMost()._right = rightNode;
    		}
    	} else if (this._right) {
    		// Backup branch data
    		rightNode = this._right;

    		// Copy data from right node
    		this._left = rightNode._left;
    		this._right = rightNode._right;
    		this._data = rightNode._data;
    		this._store = rightNode._store;
    	} else {
    		this.clear();
    	}

    	return true;
    };

    BinaryTree.prototype.leftMost = function () {
    	if (!this._left) {
    		return this;
    	} else {
    		return this._left.leftMost();
    	}
    };

    BinaryTree.prototype.rightMost = function () {
    	if (!this._right) {
    		return this;
    	} else {
    		return this._right.rightMost();
    	}
    };

    /**
     * Searches the binary tree for all matching documents based on the data
     * passed (query).
     * @param data
     * @param options
     * @param {Array=} resultArr The results passed between recursive calls.
     * Do not pass anything into this argument when calling externally.
     * @returns {*|Array}
     */
    BinaryTree.prototype.lookup = function (data, options, resultArr) {
    	var result = this._compareFunc(this._data, data);

    	resultArr = resultArr || [];

    	if (result === 0) {
    		if (this._left) { this._left.lookup(data, options, resultArr); }
    		resultArr.push(this._data);
    		if (this._right) { this._right.lookup(data, options, resultArr); }
    	}

    	if (result === -1) {
    		if (this._right) { this._right.lookup(data, options, resultArr); }
    	}

    	if (result === 1) {
    		if (this._left) { this._left.lookup(data, options, resultArr); }
    	}

    	return resultArr;
    };

    /**
     * Returns the entire binary tree ordered.
     * @param {String} type
     * @param resultArr
     * @returns {*|Array}
     */
    BinaryTree.prototype.inOrder = function (type, resultArr) {
    	resultArr = resultArr || [];

    	if (this._left) {
    		this._left.inOrder(type, resultArr);
    	}

    	switch (type) {
    		case 'hash':
    			resultArr.push(this._hash);
    			break;

    		case 'data':
    			resultArr.push(this._data);
    			break;

    		default:
    			resultArr.push({
    				key: this._data,
    				arr: this._store
    			});
    			break;
    	}

    	if (this._right) {
    		this._right.inOrder(type, resultArr);
    	}

    	return resultArr;
    };

    /**
     * Searches the binary tree for all matching documents based on the regular
     * expression passed.
     * @param path
     * @param val
     * @param regex
     * @param {Array=} resultArr The results passed between recursive calls.
     * Do not pass anything into this argument when calling externally.
     * @returns {*|Array}
     */
    BinaryTree.prototype.startsWith = function (path, val, regex, resultArr) {
    	var reTest,
    		thisDataPathVal = sharedPathSolver.get(this._data, path),
    		thisDataPathValSubStr = thisDataPathVal.substr(0, val.length),
    		result;

    	regex = regex || new RegExp('^' + val);
    	resultArr = resultArr || [];

    	if (resultArr._visited === undefined) { resultArr._visited = 0; }
    	resultArr._visited++;

    	result = this.sortAsc(thisDataPathVal, val);
    	reTest = thisDataPathValSubStr === val;

    	Iif (result === 0) {
    		if (this._left) { this._left.startsWith(path, val, regex, resultArr); }
    		if (reTest) { resultArr.push(this._data); }
    		if (this._right) { this._right.startsWith(path, val, regex, resultArr); }
    	}

    	if (result === -1) {
    		Iif (reTest) { resultArr.push(this._data); }
    		if (this._right) { this._right.startsWith(path, val, regex, resultArr); }
    	}

    	if (result === 1) {
    		if (this._left) { this._left.startsWith(path, val, regex, resultArr); }
    		if (reTest) { resultArr.push(this._data); }
    	}

    	return resultArr;
    };

    /*BinaryTree.prototype.find = function (type, search, resultArr) {
    	resultArr = resultArr || [];

    	if (this._left) {
    		this._left.find(type, search, resultArr);
    	}

    	// Check if this node's data is greater or less than the from value
    	var fromResult = this.sortAsc(this._data[key], from),
    			toResult = this.sortAsc(this._data[key], to);

    	if ((fromResult === 0 || fromResult === 1) && (toResult === 0 || toResult === -1)) {
    		// This data node is greater than or equal to the from value,
    		// and less than or equal to the to value so include it
    		switch (type) {
    			case 'hash':
    				resultArr.push(this._hash);
    				break;

    			case 'data':
    				resultArr.push(this._data);
    				break;

    			default:
    				resultArr.push({
    					key: this._data,
    					arr: this._store
    				});
    				break;
    		}
    	}

    	if (this._right) {
    		this._right.find(type, search, resultArr);
    	}

    	return resultArr;
    };*/

    /**
     *
     * @param {String} type
     * @param {String} key The data key / path to range search against.
     * @param {Number} from Range search from this value (inclusive)
     * @param {Number} to Range search to this value (inclusive)
     * @param {Array=} resultArr Leave undefined when calling (internal use),
     * passes the result array between recursive calls to be returned when
     * the recursion chain completes.
     * @param {Path=} pathResolver Leave undefined when calling (internal use),
     * caches the path resolver instance for performance.
     * @returns {Array} Array of matching document objects
     */
    BinaryTree.prototype.findRange = function (type, key, from, to, resultArr, pathResolver) {
    	resultArr = resultArr || [];
    	pathResolver = pathResolver || new Path(key);

    	if (this._left) {
    		this._left.findRange(type, key, from, to, resultArr, pathResolver);
    	}

    	// Check if this node's data is greater or less than the from value
    	var pathVal = pathResolver.value(this._data),
    		fromResult = this.sortAsc(pathVal, from),
    		toResult = this.sortAsc(pathVal, to);

    	if ((fromResult === 0 || fromResult === 1) && (toResult === 0 || toResult === -1)) {
    		// This data node is greater than or equal to the from value,
    		// and less than or equal to the to value so include it
    		switch (type) {
    			case 'hash':
    				resultArr.push(this._hash);
    				break;

    			case 'data':
    				resultArr.push(this._data);
    				break;

    			default:
    				resultArr.push({
    					key: this._data,
    					arr: this._store
    				});
    				break;
    		}
    	}

    	if (this._right) {
    		this._right.findRange(type, key, from, to, resultArr, pathResolver);
    	}

    	return resultArr;
    };

    /*BinaryTree.prototype.findRegExp = function (type, key, pattern, resultArr) {
    	resultArr = resultArr || [];

    	if (this._left) {
    		this._left.findRegExp(type, key, pattern, resultArr);
    	}

    	// Check if this node's data is greater or less than the from value
    	var fromResult = this.sortAsc(this._data[key], from),
    			toResult = this.sortAsc(this._data[key], to);

    	if ((fromResult === 0 || fromResult === 1) && (toResult === 0 || toResult === -1)) {
    		// This data node is greater than or equal to the from value,
    		// and less than or equal to the to value so include it
    		switch (type) {
    			case 'hash':
    				resultArr.push(this._hash);
    				break;

    			case 'data':
    				resultArr.push(this._data);
    				break;

    			default:
    				resultArr.push({
    					key: this._data,
    					arr: this._store
    				});
    				break;
    		}
    	}

    	if (this._right) {
    		this._right.findRegExp(type, key, pattern, resultArr);
    	}

    	return resultArr;
    };*/

    /**
     * Determines if the passed query and options object will be served
     * by this index successfully or not and gives a score so that the
     * DB search system can determine how useful this index is in comparison
     * to other indexes on the same collection.
     * @param query
     * @param queryOptions
     * @param matchOptions
     * @returns {{matchedKeys: Array, totalKeyCount: Number, score: number}}
     */
    BinaryTree.prototype.match = function (query, queryOptions, matchOptions) {
    	// Check if the passed query has data in the keys our index
    	// operates on and if so, is the query sort matching our order
    	var indexKeyArr,
    		queryArr,
    		matchedKeys = [],
    		matchedKeyCount = 0,
    		i;

    	indexKeyArr = sharedPathSolver.parseArr(this._index, {
    		verbose: true
    	});

    	queryArr = sharedPathSolver.parseArr(query, matchOptions && matchOptions.pathOptions ? matchOptions.pathOptions : {
    		ignore:/\$/,
    		verbose: true
    	});

    	// Loop the query array and check the order of keys against the
    	// index key array to see if this index can be used
    	for (i = 0; i < indexKeyArr.length; i++) {
    		if (queryArr[i] === indexKeyArr[i]) {
    			matchedKeyCount++;
    			matchedKeys.push(queryArr[i]);
    		}
    	}

    	return {
    		matchedKeys: matchedKeys,
    		totalKeyCount: queryArr.length,
    		score: matchedKeyCount
    	};

    	//return sharedPathSolver.countObjectPaths(this._keys, query);
    };

    Shared.finishModule('BinaryTree');
    module.exports = BinaryTree;
    },{"./Path":34,"./Shared":40}],6:[function(_dereq_,module,exports){
    "use strict";

    var crcTable,
    	checksum;

    crcTable = (function () {
    	var crcTable = [],
    		c, n, k;

    	for (n = 0; n < 256; n++) {
    		c = n;

    		for (k = 0; k < 8; k++) {
    			c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); // jshint ignore:line
    		}

    		crcTable[n] = c;
    	}

    	return crcTable;
    }());

    /**
     * Returns a checksum of a string.
     * @param {String} str The string to checksum.
     * @return {Number} The checksum generated.
     */
    checksum = function(str) {
    	var crc = 0 ^ (-1), // jshint ignore:line
    		i;

    	for (i = 0; i < str.length; i++) {
    		crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF]; // jshint ignore:line
    	}

    	return (crc ^ (-1)) >>> 0; // jshint ignore:line
    };

    module.exports = checksum;
    },{}],7:[function(_dereq_,module,exports){
    "use strict";

    var Shared,
    	Db,
    	Metrics,
    	KeyValueStore,
    	Path,
    	IndexHashMap,
    	IndexBinaryTree,
    	Index2d,
    	Overload,
    	ReactorIO,
    	sharedPathSolver;

    Shared = _dereq_('./Shared');

    /**
     * Creates a new collection. Collections store multiple documents and
     * handle CRUD against those documents.
     * @constructor
     */
    var Collection = function (name, options) {
    	this.init.apply(this, arguments);
    };

    Collection.prototype.init = function (name, options) {
    	this.sharedPathSolver = sharedPathSolver;
    	this._primaryKey = '_id';
    	this._primaryIndex = new KeyValueStore('primary');
    	this._primaryCrc = new KeyValueStore('primaryCrc');
    	this._crcLookup = new KeyValueStore('crcLookup');
    	this._name = name;
    	this._data = [];
    	this._metrics = new Metrics();

    	this._options = options || {
    		changeTimestamp: false
    	};

    	Iif (this._options.db) {
    		this.db(this._options.db);
    	}

    	// Create an object to store internal protected data
    	this._metaData = {};

    	this._deferQueue = {
    		insert: [],
    		update: [],
    		remove: [],
    		upsert: [],
    		async: []
    	};

    	this._deferThreshold = {
    		insert: 100,
    		update: 100,
    		remove: 100,
    		upsert: 100
    	};

    	this._deferTime = {
    		insert: 1,
    		update: 1,
    		remove: 1,
    		upsert: 1
    	};

    	this._deferredCalls = true;

    	// Set the subset to itself since it is the root collection
    	this.subsetOf(this);
    };

    Shared.addModule('Collection', Collection);
    Shared.mixin(Collection.prototype, 'Mixin.Common');
    Shared.mixin(Collection.prototype, 'Mixin.Events');
    Shared.mixin(Collection.prototype, 'Mixin.ChainReactor');
    Shared.mixin(Collection.prototype, 'Mixin.CRUD');
    Shared.mixin(Collection.prototype, 'Mixin.Constants');
    Shared.mixin(Collection.prototype, 'Mixin.Triggers');
    Shared.mixin(Collection.prototype, 'Mixin.Sorting');
    Shared.mixin(Collection.prototype, 'Mixin.Matching');
    Shared.mixin(Collection.prototype, 'Mixin.Updating');
    Shared.mixin(Collection.prototype, 'Mixin.Tags');

    Metrics = _dereq_('./Metrics');
    KeyValueStore = _dereq_('./KeyValueStore');
    Path = _dereq_('./Path');
    IndexHashMap = _dereq_('./IndexHashMap');
    IndexBinaryTree = _dereq_('./IndexBinaryTree');
    Index2d = _dereq_('./Index2d');
    Db = Shared.modules.Db;
    Overload = _dereq_('./Overload');
    ReactorIO = _dereq_('./ReactorIO');
    sharedPathSolver = new Path();

    /**
     * Gets / sets the deferred calls flag. If set to true (default)
     * then operations on large data sets can be broken up and done
     * over multiple CPU cycles (creating an async state). For purely
     * synchronous behaviour set this to false.
     * @param {Boolean=} val The value to set.
     * @returns {Boolean}
     */
    Shared.synthesize(Collection.prototype, 'deferredCalls');

    /**
     * Gets / sets the current state.
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(Collection.prototype, 'state');

    /**
     * Gets / sets the name of the collection.
     * @param {String=} val The name of the collection to set.
     * @returns {*}
     */
    Shared.synthesize(Collection.prototype, 'name');

    /**
     * Gets / sets the metadata stored in the collection.
     */
    Shared.synthesize(Collection.prototype, 'metaData');

    /**
     * Gets / sets boolean to determine if the collection should be
     * capped or not.
     */
    Shared.synthesize(Collection.prototype, 'capped');

    /**
     * Gets / sets capped collection size. This is the maximum number
     * of records that the capped collection will store.
     */
    Shared.synthesize(Collection.prototype, 'cappedSize');

    Collection.prototype._asyncPending = function (key) {
    	this._deferQueue.async.push(key);
    };

    Collection.prototype._asyncComplete = function (key) {
    	// Remove async flag for this type
    	var index = this._deferQueue.async.indexOf(key);

    	while (index > -1) {
    		this._deferQueue.async.splice(index, 1);
    		index = this._deferQueue.async.indexOf(key);
    	}

    	Eif (this._deferQueue.async.length === 0) {
    		this.deferEmit('ready');
    	}
    };

    /**
     * Get the data array that represents the collection's data.
     * This data is returned by reference and should not be altered outside
     * of the provided CRUD functionality of the collection as doing so
     * may cause unstable index behaviour within the collection.
     * @returns {Array}
     */
    Collection.prototype.data = function () {
    	return this._data;
    };

    /**
     * Drops a collection and all it's stored data from the database.
     * @returns {boolean} True on success, false on failure.
     */
    Collection.prototype.drop = function (callback) {
    	var key;

    	Eif (!this.isDropped()) {
    		Eif (this._db && this._db._collection && this._name) {
    			if (this.debug()) {
    				console.log(this.logIdentifier() + ' Dropping');
    			}

    			this._state = 'dropped';

    			this.emit('drop', this);

    			delete this._db._collection[this._name];

    			// Remove any reactor IO chain links
    			if (this._collate) {
    				for (key in this._collate) {
    					Eif (this._collate.hasOwnProperty(key)) {
    						this.collateRemove(key);
    					}
    				}
    			}

    			delete this._primaryKey;
    			delete this._primaryIndex;
    			delete this._primaryCrc;
    			delete this._crcLookup;
    			delete this._data;
    			delete this._metrics;
    			delete this._listeners;

    			Iif (callback) { callback.call(this, false, true); }

    			return true;
    		}
    	} else {
    		if (callback) { callback.call(this, false, true); }

    		return true;
    	}

    	if (callback) { callback.call(this, false, true); }
    	return false;
    };

    /**
     * Gets / sets the primary key for this collection.
     * @param {String=} keyName The name of the primary key.
     * @returns {*}
     */
    Collection.prototype.primaryKey = function (keyName) {
    	if (keyName !== undefined) {
    		if (this._primaryKey !== keyName) {
    			var oldKey = this._primaryKey;
    			this._primaryKey = keyName;

    			// Set the primary key index primary key
    			this._primaryIndex.primaryKey(keyName);

    			// Rebuild the primary key index
    			this.rebuildPrimaryKeyIndex();

    			// Propagate change down the chain
    			this.chainSend('primaryKey', {
    				keyName: keyName,
    				oldData: oldKey
    			});
    		}
    		return this;
    	}

    	return this._primaryKey;
    };

    /**
     * Handles insert events and routes changes to binds and views as required.
     * @param {Array} inserted An array of inserted documents.
     * @param {Array} failed An array of documents that failed to insert.
     * @private
     */
    Collection.prototype._onInsert = function (inserted, failed) {
    	this.emit('insert', inserted, failed);
    };

    /**
     * Handles update events and routes changes to binds and views as required.
     * @param {Array} items An array of updated documents.
     * @private
     */
    Collection.prototype._onUpdate = function (items) {
    	this.emit('update', items);
    };

    /**
     * Handles remove events and routes changes to binds and views as required.
     * @param {Array} items An array of removed documents.
     * @private
     */
    Collection.prototype._onRemove = function (items) {
    	this.emit('remove', items);
    };

    /**
     * Handles any change to the collection.
     * @private
     */
    Collection.prototype._onChange = function () {
    	if (this._options.changeTimestamp) {
    		// Record the last change timestamp
    		this._metaData.lastChange = this.serialiser.convert(new Date());
    	}
    };

    /**
     * Gets / sets the db instance this class instance belongs to.
     * @param {Db=} db The db instance.
     * @returns {*}
     */
    Shared.synthesize(Collection.prototype, 'db', function (db) {
    	if (db) {
    		Eif (this.primaryKey() === '_id') {
    			// Set primary key to the db's key by default
    			this.primaryKey(db.primaryKey());

    			// Apply the same debug settings
    			this.debug(db.debug());
    		}
    	}

    	return this.$super.apply(this, arguments);
    });

    /**
     * Gets / sets mongodb emulation mode.
     * @param {Boolean=} val True to enable, false to disable.
     * @returns {*}
     */
    Shared.synthesize(Collection.prototype, 'mongoEmulation');

    /**
     * Sets the collection's data to the array / documents passed.  If any
     * data already exists in the collection it will be removed before the
     * new data is set.
     * @param {Array|Object} data The array of documents or a single document
     * that will be set as the collections data.
     * @param options Optional options object.
     * @param callback Optional callback function.
     */
    Collection.prototype.setData = new Overload('Collection.prototype.setData', {
    	'*': function (data) {
    		return this.$main.call(this, data, {});
    	},

    	'*, object': function (data, options) {
    		return this.$main.call(this, data, options);
    	},

    	'*, function': function (data, callback) {
    		return this.$main.call(this, data, {}, callback);
    	},

    	'*, *, function': function (data, options, callback) {
    		return this.$main.call(this, data, options, callback);
    	},

    	'*, *, *': function (data, options, callback) {
    		return this.$main.call(this, data, options, callback);
    	},

    	'$main': function (data, options, callback) {
    		Iif (this.isDropped()) {
    			throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    		}

    		Eif (data) {
    			var deferredSetting = this.deferredCalls(),
    				oldData = [].concat(this._data);

    			// Switch off deferred calls since setData should be
    			// a synchronous call
    			this.deferredCalls(false);

    			options = this.options(options);

    			Eif (options.$decouple) {
    				data = this.decouple(data);
    			}

    			if (!(data instanceof Array)) {
    				data = [data];
    			}

    			// Remove all items from the collection
    			this.remove({});

    			// Insert the new data
    			this.insert(data);

    			// Switch deferred calls back to previous settings
    			this.deferredCalls(deferredSetting);

    			this._onChange();
    			this.emit('setData', this._data, oldData);
    		}

    		Iif (callback) { callback.call(this); }

    		return this;
    	}
    });

    /**
     * Drops and rebuilds the primary key index for all documents in the collection.
     * @param {Object=} options An optional options object.
     * @private
     */
    Collection.prototype.rebuildPrimaryKeyIndex = function (options) {
    	options = options || {
    		$ensureKeys: undefined,
    		$violationCheck: undefined
    	};

    	var ensureKeys = options && options.$ensureKeys !== undefined ? options.$ensureKeys : true,
    		violationCheck = options && options.$violationCheck !== undefined ? options.$violationCheck : true,
    		arr,
    		arrCount,
    		arrItem,
    		pIndex = this._primaryIndex,
    		crcIndex = this._primaryCrc,
    		crcLookup = this._crcLookup,
    		pKey = this._primaryKey,
    		jString;

    	// Drop the existing primary index
    	pIndex.truncate();
    	crcIndex.truncate();
    	crcLookup.truncate();

    	// Loop the data and check for a primary key in each object
    	arr = this._data;
    	arrCount = arr.length;

    	while (arrCount--) {
    		arrItem = arr[arrCount];

    		Eif (ensureKeys) {
    			// Make sure the item has a primary key
    			this.ensurePrimaryKey(arrItem);
    		}

    		Eif (violationCheck) {
    			// Check for primary key violation
    			Iif (!pIndex.uniqueSet(arrItem[pKey], arrItem)) {
    				// Primary key violation
    				throw(this.logIdentifier() + ' Call to setData on collection failed because your data violates the primary key unique constraint. One or more documents are using the same primary key: ' + arrItem[this._primaryKey]);
    			}
    		} else {
    			pIndex.set(arrItem[pKey], arrItem);
    		}

    		// Generate a hash string
    		jString = this.hash(arrItem);

    		crcIndex.set(arrItem[pKey], jString);
    		crcLookup.set(jString, arrItem);
    	}
    };

    /**
     * Checks for a primary key on the document and assigns one if none
     * currently exists.
     * @param {Object} obj The object to check a primary key against.
     * @private
     */
    Collection.prototype.ensurePrimaryKey = function (obj) {
    	if (obj[this._primaryKey] === undefined) {
    		// Assign a primary key automatically
    		obj[this._primaryKey] = this.objectId();
    	}
    };

    /**
     * Clears all data from the collection.
     * @returns {Collection}
     */
    Collection.prototype.truncate = function () {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}
    	// TODO: This should use remove so that chain reactor events are properly
    	// TODO: handled, but ensure that chunking is switched off
    	this.emit('truncate', this._data);

    	// Clear all the data from the collection
    	this._data.length = 0;

    	// Re-create the primary index data
    	this._primaryIndex = new KeyValueStore('primary');
    	this._primaryCrc = new KeyValueStore('primaryCrc');
    	this._crcLookup = new KeyValueStore('crcLookup');

    	this._onChange();
    	this.emit('immediateChange', {type: 'truncate'});
    	this.deferEmit('change', {type: 'truncate'});
    	return this;
    };

    /**
     * Modifies an existing document or documents in a collection. This will update
     * all matches for 'query' with the data held in 'update'. It will not overwrite
     * the matched documents with the update document.
     *
     * @param {Object} obj The document object to upsert or an array containing
     * documents to upsert.
     *
     * If the document contains a primary key field (based on the collections's primary
     * key) then the database will search for an existing document with a matching id.
     * If a matching document is found, the document will be updated. Any keys that
     * match keys on the existing document will be overwritten with new data. Any keys
     * that do not currently exist on the document will be added to the document.
     *
     * If the document does not contain an id or the id passed does not match an existing
     * document, an insert is performed instead. If no id is present a new primary key
     * id is provided for the item.
     *
     * @param {Function=} callback Optional callback method.
     * @returns {Object} An object containing two keys, "op" contains either "insert" or
     * "update" depending on the type of operation that was performed and "result"
     * contains the return data from the operation used.
     */
    Collection.prototype.upsert = function (obj, callback) {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}

    	Eif (obj) {
    		var queue = this._deferQueue.upsert,
    			deferThreshold = this._deferThreshold.upsert,
    			returnData = {},
    			query,
    			i;

    		// Determine if the object passed is an array or not
    		if (obj instanceof Array) {
    			Iif (this._deferredCalls && obj.length > deferThreshold) {
    				// Break up upsert into blocks
    				this._deferQueue.upsert = queue.concat(obj);
    				this._asyncPending('upsert');

    				// Fire off the insert queue handler
    				this.processQueue('upsert', callback);

    				return {};
    			} else {
    				// Loop the array and upsert each item
    				returnData = [];

    				for (i = 0; i < obj.length; i++) {
    					returnData.push(this.upsert(obj[i]));
    				}

    				Iif (callback) { callback.call(this); }

    				return returnData;
    			}
    		}

    		// Determine if the operation is an insert or an update
    		if (obj[this._primaryKey]) {
    			// Check if an object with this primary key already exists
    			query = {};
    			query[this._primaryKey] = obj[this._primaryKey];

    			if (this._primaryIndex.lookup(query)[0]) {
    				// The document already exists with this id, this operation is an update
    				returnData.op = 'update';
    			} else {
    				// No document with this id exists, this operation is an insert
    				returnData.op = 'insert';
    			}
    		} else {
    			// The document passed does not contain an id, this operation is an insert
    			returnData.op = 'insert';
    		}

    		switch (returnData.op) {
    			case 'insert':
    				returnData.result = this.insert(obj, callback);
    				break;

    			case 'update':
    				returnData.result = this.update(query, obj, {}, callback);
    				break;

    			default:
    				break;
    		}

    		return returnData;
    	} else {
    		if (callback) { callback.call(this); }
    	}

    	return {};
    };

    /**
     * Executes a method against each document that matches query and returns an
     * array of documents that may have been modified by the method.
     * @param {Object} query The query object.
     * @param {Function} func The method that each document is passed to. If this method
     * returns false for a particular document it is excluded from the results.
     * @param {Object=} options Optional options object.
     * @returns {Array}
     */
    Collection.prototype.filter = function (query, func, options) {
    	return (this.find(query, options)).filter(func);
    };

    /**
     * Executes a method against each document that matches query and then executes
     * an update based on the return data of the method.
     * @param {Object} query The query object.
     * @param {Function} func The method that each document is passed to. If this method
     * returns false for a particular document it is excluded from the update.
     * @param {Object=} options Optional options object passed to the initial find call.
     * @returns {Array}
     */
    Collection.prototype.filterUpdate = function (query, func, options) {
    	var items = this.find(query, options),
    		results = [],
    		singleItem,
    		singleQuery,
    		singleUpdate,
    		pk = this.primaryKey(),
    		i;

    	for (i = 0; i < items.length; i++) {
    		singleItem = items[i];
    		singleUpdate = func(singleItem);

    		Eif (singleUpdate) {
    			singleQuery = {};
    			singleQuery[pk] = singleItem[pk];

    			results.push(this.update(singleQuery, singleUpdate));
    		}
    	}

    	return results;
    };

    /**
     * Modifies an existing document or documents in a collection. This will update
     * all matches for 'query' with the data held in 'update'. It will not overwrite
     * the matched documents with the update document.
     *
     * @param {Object} query The query that must be matched for a document to be
     * operated on.
     * @param {Object} update The object containing updated key/values. Any keys that
     * match keys on the existing document will be overwritten with this data. Any
     * keys that do not currently exist on the document will be added to the document.
     * @param {Object=} options An options object.
     * @param {Function=} callback The callback method to call when the update is
     * complete.
     * @returns {Array} The items that were updated.
     */
    Collection.prototype.update = function (query, update, options, callback) {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}

    	// Convert queries from mongo dot notation to forerunner queries
    	if (this.mongoEmulation()) {
    		this.convertToFdb(query);
    		this.convertToFdb(update);
    	} else {
    		// Decouple the update data
    		update = this.decouple(update);
    	}

    	// Handle transform
    	update = this.transformIn(update);

    	return this._handleUpdate(query, update, options, callback);
    };

    Collection.prototype._handleUpdate = function (query, update, options, callback) {
    	var self = this,
    		op = this._metrics.create('update'),
    		dataSet,
    		updated,
    		updateCall = function (referencedDoc) {
    			var oldDoc = self.decouple(referencedDoc),
    				newDoc,
    				triggerOperation,
    				result;

    			if (self.willTrigger(self.TYPE_UPDATE, self.PHASE_BEFORE) || self.willTrigger(self.TYPE_UPDATE, self.PHASE_AFTER)) {
    				newDoc = self.decouple(referencedDoc);

    				triggerOperation = {
    					type: 'update',
    					query: self.decouple(query),
    					update: self.decouple(update),
    					options: self.decouple(options),
    					op: op
    				};

    				// Update newDoc with the update criteria so we know what the data will look
    				// like AFTER the update is processed
    				result = self.updateObject(newDoc, triggerOperation.update, triggerOperation.query, triggerOperation.options, '');

    				if (self.processTrigger(triggerOperation, self.TYPE_UPDATE, self.PHASE_BEFORE, referencedDoc, newDoc) !== false) {
    					// No triggers complained so let's execute the replacement of the existing
    					// object with the new one
    					result = self.updateObject(referencedDoc, newDoc, triggerOperation.query, triggerOperation.options, '');

    					// NOTE: If for some reason we would only like to fire this event if changes are actually going
    					// to occur on the object from the proposed update then we can add "result &&" to the if
    					self.processTrigger(triggerOperation, self.TYPE_UPDATE, self.PHASE_AFTER, oldDoc, newDoc);
    				} else {
    					// Trigger cancelled operation so tell result that it was not updated
    					result = false;
    				}
    			} else {
    				// No triggers complained so let's execute the replacement of the existing
    				// object with the new one
    				result = self.updateObject(referencedDoc, update, query, options, '');
    			}

    			// Inform indexes of the change
    			self._updateIndexes(oldDoc, referencedDoc);

    			return result;
    		};

    	op.start();
    	op.time('Retrieve documents to update');
    	dataSet = this.find(query, {$decouple: false});
    	op.time('Retrieve documents to update');

    	Eif (dataSet.length) {
    		op.time('Update documents');
    		updated = dataSet.filter(updateCall);
    		op.time('Update documents');

    		if (updated.length) {
    			if (this.debug()) {
    				console.log(this.logIdentifier() + ' Updated some data');
    			}

    			op.time('Resolve chains');
    			if (this.chainWillSend()) {
    				this.chainSend('update', {
    					query: query,
    					update: update,
    					dataSet: this.decouple(updated)
    				}, options);
    			}
    			op.time('Resolve chains');

    			this._onUpdate(updated);
    			this._onChange();

    			Iif (callback) { callback.call(this); }

    			this.emit('immediateChange', {type: 'update', data: updated});
    			this.deferEmit('change', {type: 'update', data: updated});
    		}
    	}

    	op.stop();

    	// TODO: Should we decouple the updated array before return by default?
    	return updated || [];
    };

    /**
     * Replaces an existing object with data from the new object without
     * breaking data references.
     * @param {Object} currentObj The object to alter.
     * @param {Object} newObj The new object to overwrite the existing one with.
     * @returns {*} Chain.
     * @private
     */
    Collection.prototype._replaceObj = function (currentObj, newObj) {
    	var i;

    	// Check if the new document has a different primary key value from the existing one
    	// Remove item from indexes
    	this._removeFromIndexes(currentObj);

    	// Remove existing keys from current object
    	for (i in currentObj) {
    		if (currentObj.hasOwnProperty(i)) {
    			delete currentObj[i];
    		}
    	}

    	// Add new keys to current object
    	for (i in newObj) {
    		if (newObj.hasOwnProperty(i)) {
    			currentObj[i] = newObj[i];
    		}
    	}

    	// Update the item in the primary index
    	if (!this._insertIntoIndexes(currentObj)) {
    		throw(this.logIdentifier() + ' Primary key violation in update! Key violated: ' + currentObj[this._primaryKey]);
    	}

    	// Update the object in the collection data
    	//this._data.splice(this._data.indexOf(currentObj), 1, newObj);

    	return this;
    };

    /**
     * Helper method to update a document from it's id.
     * @param {String} id The id of the document.
     * @param {Object} update The object containing the key/values to update to.
     * @returns {Object} The document that was updated or undefined
     * if no document was updated.
     */
    Collection.prototype.updateById = function (id, update) {
    	var searchObj = {};
    	searchObj[this._primaryKey] = id;
    	return this.update(searchObj, update)[0];
    };

    /**
     * Internal method for document updating.
     * @param {Object} doc The document to update.
     * @param {Object} update The object with key/value pairs to update the document with.
     * @param {Object} query The query object that we need to match to perform an update.
     * @param {Object} options An options object.
     * @param {String} path The current recursive path.
     * @param {String} opType The type of update operation to perform, if none is specified
     * default is to set new data against matching fields.
     * @returns {Boolean} True if the document was updated with new / changed data or
     * false if it was not updated because the data was the same.
     * @private
     */
    Collection.prototype.updateObject = function (doc, update, query, options, path, opType) {
    	// TODO: This method is long, try to break it into smaller pieces
    	update = this.decouple(update);

    	// Clear leading dots from path
    	path = path || '';
    	if (path.substr(0, 1) === '.') { path = path.substr(1, path.length -1); }

    	//var oldDoc = this.decouple(doc),
    	var	updated = false,
    		recurseUpdated = false,
    		operation,
    		tmpArray,
    		tmpIndex,
    		tmpCount,
    		tempIndex,
    		tempKey,
    		replaceObj,
    		pk,
    		pathInstance,
    		sourceIsArray,
    		updateIsArray,
    		i;

    	// Loop each key in the update object
    	for (i in update) {
    		Eif (update.hasOwnProperty(i)) {
    			// Reset operation flag
    			operation = false;

    			// Check if the property starts with a dollar (function)
    			if (i.substr(0, 1) === '$') {
    				// Check for commands
    				switch (i) {
    					case '$key':
    					case '$index':
    					case '$data':
    					case '$min':
    					case '$max':
    						// Ignore some operators
    						operation = true;
    						break;

    					case '$each':
    						operation = true;

    						// Loop over the array of updates and run each one
    						tmpCount = update.$each.length;
    						for (tmpIndex = 0; tmpIndex < tmpCount; tmpIndex++) {
    							recurseUpdated = this.updateObject(doc, update.$each[tmpIndex], query, options, path);

    							Eif (recurseUpdated) {
    								updated = true;
    							}
    						}

    						updated = updated || recurseUpdated;
    						break;

    					case '$replace':
    						operation = true;
    						replaceObj = update.$replace;
    						pk = this.primaryKey();

    						// Loop the existing item properties and compare with
    						// the replacement (never remove primary key)
    						for (tempKey in doc) {
    							if (doc.hasOwnProperty(tempKey) && tempKey !== pk) {
    								if (replaceObj[tempKey] === undefined) {
    									// The new document doesn't have this field, remove it from the doc
    									this._updateUnset(doc, tempKey);
    									updated = true;
    								}
    							}
    						}

    						// Loop the new item props and update the doc
    						for (tempKey in replaceObj) {
    							Eif (replaceObj.hasOwnProperty(tempKey) && tempKey !== pk) {
    								this._updateOverwrite(doc, tempKey, replaceObj[tempKey]);
    								updated = true;
    							}
    						}
    						break;

    					default:
    						operation = true;

    						// Now run the operation
    						recurseUpdated = this.updateObject(doc, update[i], query, options, path, i);
    						updated = updated || recurseUpdated;
    						break;
    				}
    			}

    			// Check if the key has a .$ at the end, denoting an array lookup
    			if (this._isPositionalKey(i)) {
    				operation = true;

    				// Modify i to be the name of the field
    				i = i.substr(0, i.length - 2);

    				pathInstance = new Path(path + '.' + i);

    				// Check if the key is an array and has items
    				Eif (doc[i] && doc[i] instanceof Array && doc[i].length) {
    					tmpArray = [];

    					// Loop the array and find matches to our search
    					for (tmpIndex = 0; tmpIndex < doc[i].length; tmpIndex++) {
    						if (this._match(doc[i][tmpIndex], pathInstance.value(query)[0], options, '', {})) {
    							tmpArray.push(tmpIndex);
    						}
    					}

    					// Loop the items that matched and update them
    					for (tmpIndex = 0; tmpIndex < tmpArray.length; tmpIndex++) {
    						recurseUpdated = this.updateObject(doc[i][tmpArray[tmpIndex]], update[i + '.$'], query, options, path + '.' + i, opType);
    						updated = updated || recurseUpdated;
    					}
    				}
    			}

    			if (!operation) {
    				if (!opType && typeof(update[i]) === 'object') {
    					Eif (doc[i] !== null && typeof(doc[i]) === 'object') {
    						// Check if we are dealing with arrays
    						sourceIsArray = doc[i] instanceof Array;
    						updateIsArray = update[i] instanceof Array;

    						if (sourceIsArray || updateIsArray) {
    							// Check if the update is an object and the doc is an array
    							if (!updateIsArray && sourceIsArray) {
    								// Update is an object, source is an array so match the array items
    								// with our query object to find the one to update inside this array

    								// Loop the array and find matches to our search
    								for (tmpIndex = 0; tmpIndex < doc[i].length; tmpIndex++) {
    									recurseUpdated = this.updateObject(doc[i][tmpIndex], update[i], query, options, path + '.' + i, opType);
    									updated = updated || recurseUpdated;
    								}
    							} else {
    								// Either both source and update are arrays or the update is
    								// an array and the source is not, so set source to update
    								Eif (doc[i] !== update[i]) {
    									this._updateProperty(doc, i, update[i]);
    									updated = true;
    								}
    							}
    						} else {
    							// The doc key is an object so traverse the
    							// update further
    							recurseUpdated = this.updateObject(doc[i], update[i], query, options, path + '.' + i, opType);
    							updated = updated || recurseUpdated;
    						}
    					} else {
    						if (doc[i] !== update[i]) {
    							this._updateProperty(doc, i, update[i]);
    							updated = true;
    						}
    					}
    				} else {
    					switch (opType) {
    						case '$inc':
    							var doUpdate = true;

    							// Check for a $min / $max operator
    							if (update[i] > 0) {
    								Iif (update.$max) {
    									// Check current value
    									if (doc[i] >= update.$max) {
    										// Don't update
    										doUpdate = false;
    									}
    								}
    							} else Eif (update[i] < 0) {
    								Iif (update.$min) {
    									// Check current value
    									if (doc[i] <= update.$min) {
    										// Don't update
    										doUpdate = false;
    									}
    								}
    							}

    							Eif (doUpdate) {
    								this._updateIncrement(doc, i, update[i]);
    								updated = true;
    							}
    							break;

    						case '$cast':
    							// Casts a property to the type specified if it is not already
    							// that type. If the cast is an array or an object and the property
    							// is not already that type a new array or object is created and
    							// set to the property, overwriting the previous value
    							switch (update[i]) {
    								case 'array':
    									Eif (!(doc[i] instanceof Array)) {
    										// Cast to an array
    										this._updateProperty(doc, i, update.$data || []);
    										updated = true;
    									}
    									break;

    								case 'object':
    									if (!(doc[i] instanceof Object) || (doc[i] instanceof Array)) {
    										// Cast to an object
    										this._updateProperty(doc, i, update.$data || {});
    										updated = true;
    									}
    									break;

    								case 'number':
    									if (typeof doc[i] !== 'number') {
    										// Cast to a number
    										this._updateProperty(doc, i, Number(doc[i]));
    										updated = true;
    									}
    									break;

    								case 'string':
    									if (typeof doc[i] !== 'string') {
    										// Cast to a string
    										this._updateProperty(doc, i, String(doc[i]));
    										updated = true;
    									}
    									break;

    								default:
    									throw(this.logIdentifier() + ' Cannot update cast to unknown type: ' + update[i]);
    							}

    							break;

    						case '$push':
    							// Check if the target key is undefined and if so, create an array
    							if (doc[i] === undefined) {
    								// Initialise a new array
    								this._updateProperty(doc, i, []);
    							}

    							// Check that the target key is an array
    							Eif (doc[i] instanceof Array) {
    								// Check for a $position modifier with an $each
    								if (update[i].$position !== undefined && update[i].$each instanceof Array) {
    									// Grab the position to insert at
    									tempIndex = update[i].$position;

    									// Loop the each array and push each item
    									tmpCount = update[i].$each.length;
    									for (tmpIndex = 0; tmpIndex < tmpCount; tmpIndex++) {
    										this._updateSplicePush(doc[i], tempIndex + tmpIndex, update[i].$each[tmpIndex]);
    									}
    								} else if (update[i].$each instanceof Array) {
    									// Do a loop over the each to push multiple items
    									tmpCount = update[i].$each.length;
    									for (tmpIndex = 0; tmpIndex < tmpCount; tmpIndex++) {
    										this._updatePush(doc[i], update[i].$each[tmpIndex]);
    									}
    								} else {
    									// Do a standard push
    									this._updatePush(doc[i], update[i]);
    								}
    								updated = true;
    							} else {
    								throw(this.logIdentifier() + ' Cannot push to a key that is not an array! (' + i + ')');
    							}
    							break;

    						case '$pull':
    							Eif (doc[i] instanceof Array) {
    								tmpArray = [];

    								// Loop the array and find matches to our search
    								for (tmpIndex = 0; tmpIndex < doc[i].length; tmpIndex++) {
    									if (this._match(doc[i][tmpIndex], update[i], options, '', {})) {
    										tmpArray.push(tmpIndex);
    									}
    								}

    								tmpCount = tmpArray.length;

    								// Now loop the pull array and remove items to be pulled
    								while (tmpCount--) {
    									this._updatePull(doc[i], tmpArray[tmpCount]);
    									updated = true;
    								}
    							}
    							break;

    						case '$pullAll':
    							Eif (doc[i] instanceof Array) {
    								Eif (update[i] instanceof Array) {
    									tmpArray = doc[i];
    									tmpCount = tmpArray.length;

    									Eif (tmpCount > 0) {
    										// Now loop the pull array and remove items to be pulled
    										while (tmpCount--) {
    											for (tempIndex = 0; tempIndex < update[i].length; tempIndex++) {
    												if (tmpArray[tmpCount] === update[i][tempIndex]) {
    													this._updatePull(doc[i], tmpCount);
    													tmpCount--;
    													updated = true;
    												}
    											}

    											if (tmpCount < 0) {
    												break;
    											}
    										}
    									}
    								} else {
    									throw(this.logIdentifier() + ' Cannot pullAll without being given an array of values to pull! (' + i + ')');
    								}
    							}
    							break;

    						case '$addToSet':
    							// Check if the target key is undefined and if so, create an array
    							Iif (doc[i] === undefined) {
    								// Initialise a new array
    								this._updateProperty(doc, i, []);
    							}

    							// Check that the target key is an array
    							Eif (doc[i] instanceof Array) {
    								// Loop the target array and check for existence of item
    								var targetArr = doc[i],
    									targetArrIndex,
    									targetArrCount = targetArr.length,
    									objHash,
    									addObj = true,
    									optionObj = (options && options.$addToSet),
    									hashMode,
    									pathSolver;

    								// Check if we have an options object for our operation
    								if (update[i].$key) {
    									hashMode = false;
    									pathSolver = new Path(update[i].$key);
    									objHash = pathSolver.value(update[i])[0];

    									// Remove the key from the object before we add it
    									delete update[i].$key;
    								} else if (optionObj && optionObj.key) {
    									hashMode = false;
    									pathSolver = new Path(optionObj.key);
    									objHash = pathSolver.value(update[i])[0];
    								} else {
    									objHash = this.jStringify(update[i]);
    									hashMode = true;
    								}

    								for (targetArrIndex = 0; targetArrIndex < targetArrCount; targetArrIndex++) {
    									if (hashMode) {
    										// Check if objects match via a string hash (JSON)
    										Eif (this.jStringify(targetArr[targetArrIndex]) === objHash) {
    											// The object already exists, don't add it
    											addObj = false;
    											break;
    										}
    									} else {
    										// Check if objects match based on the path
    										if (objHash === pathSolver.value(targetArr[targetArrIndex])[0]) {
    											// The object already exists, don't add it
    											addObj = false;
    											break;
    										}
    									}
    								}

    								if (addObj) {
    									this._updatePush(doc[i], update[i]);
    									updated = true;
    								}
    							} else {
    								throw(this.logIdentifier() + ' Cannot addToSet on a key that is not an array! (' + i + ')');
    							}
    							break;

    						case '$splicePush':
    							// Check if the target key is undefined and if so, create an array
    							Iif (doc[i] === undefined) {
    								// Initialise a new array
    								this._updateProperty(doc, i, []);
    							}

    							// Check that the target key is an array
    							Eif (doc[i] instanceof Array) {
    								tempIndex = update.$index;

    								Eif (tempIndex !== undefined) {
    									delete update.$index;

    									// Check for out of bounds index
    									Iif (tempIndex > doc[i].length) {
    										tempIndex = doc[i].length;
    									}

    									this._updateSplicePush(doc[i], tempIndex, update[i]);
    									updated = true;
    								} else {
    									throw(this.logIdentifier() + ' Cannot splicePush without a $index integer value!');
    								}
    							} else {
    								throw(this.logIdentifier() + ' Cannot splicePush with a key that is not an array! (' + i + ')');
    							}
    							break;

    						case '$move':
    							Eif (doc[i] instanceof Array) {
    								// Loop the array and find matches to our search
    								for (tmpIndex = 0; tmpIndex < doc[i].length; tmpIndex++) {
    									Eif (this._match(doc[i][tmpIndex], update[i], options, '', {})) {
    										var moveToIndex = update.$index;

    										Eif (moveToIndex !== undefined) {
    											delete update.$index;

    											this._updateSpliceMove(doc[i], tmpIndex, moveToIndex);
    											updated = true;
    										} else {
    											throw(this.logIdentifier() + ' Cannot move without a $index integer value!');
    										}
    										break;
    									}
    								}
    							} else {
    								throw(this.logIdentifier() + ' Cannot move on a key that is not an array! (' + i + ')');
    							}
    							break;

    						case '$mul':
    							this._updateMultiply(doc, i, update[i]);
    							updated = true;
    							break;

    						case '$rename':
    							this._updateRename(doc, i, update[i]);
    							updated = true;
    							break;

    						case '$overwrite':
    							this._updateOverwrite(doc, i, update[i]);
    							updated = true;
    							break;

    						case '$unset':
    							this._updateUnset(doc, i);
    							updated = true;
    							break;

    						case '$clear':
    							this._updateClear(doc, i);
    							updated = true;
    							break;

    						case '$pop':
    							if (doc[i] instanceof Array) {
    								if (this._updatePop(doc[i], update[i])) {
    									updated = true;
    								}
    							} else {
    								throw(this.logIdentifier() + ' Cannot pop from a key that is not an array! (' + i + ')');
    							}
    							break;

    						case '$toggle':
    							// Toggle the boolean property between true and false
    							this._updateProperty(doc, i, !doc[i]);
    							updated = true;
    							break;

    						default:
    							if (doc[i] !== update[i]) {
    								this._updateProperty(doc, i, update[i]);
    								updated = true;
    							}
    							break;
    					}
    				}
    			}
    		}
    	}

    	return updated;
    };

    /**
     * Determines if the passed key has an array positional mark (a dollar at the end
     * of its name).
     * @param {String} key The key to check.
     * @returns {Boolean} True if it is a positional or false if not.
     * @private
     */
    Collection.prototype._isPositionalKey = function (key) {
    	return key.substr(key.length - 2, 2) === '.$';
    };

    /**
     * Removes any documents from the collection that match the search query
     * key/values.
     * @param {Object} query The query object.
     * @param {Object=} options An options object.
     * @param {Function=} callback A callback method.
     * @returns {Array} An array of the documents that were removed.
     */
    Collection.prototype.remove = function (query, options, callback) {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}

    	var self = this,
    		dataSet,
    		index,
    		arrIndex,
    		returnArr,
    		removeMethod,
    		triggerOperation,
    		doc,
    		newDoc;

    	Iif (typeof(options) === 'function') {
    		callback = options;
    		options = {};
    	}

    	// Convert queries from mongo dot notation to forerunner queries
    	Iif (this.mongoEmulation()) {
    		this.convertToFdb(query);
    	}

    	Iif (query instanceof Array) {
    		returnArr = [];

    		for (arrIndex = 0; arrIndex < query.length; arrIndex++) {
    			returnArr.push(this.remove(query[arrIndex], {noEmit: true}));
    		}

    		if (!options || (options && !options.noEmit)) {
    			this._onRemove(returnArr);
    		}

    		if (callback) { callback.call(this, false, returnArr); }
    		return returnArr;
    	} else {
    		returnArr = [];
    		dataSet = this.find(query, {$decouple: false});

    		if (dataSet.length) {
    			removeMethod = function (dataItem) {
    				// Remove the item from the collection's indexes
    				self._removeFromIndexes(dataItem);

    				// Remove data from internal stores
    				index = self._data.indexOf(dataItem);
    				self._dataRemoveAtIndex(index);

    				returnArr.push(dataItem);
    			};

    			// Remove the data from the collection
    			for (var i = 0; i < dataSet.length; i++) {
    				doc = dataSet[i];

    				if (self.willTrigger(self.TYPE_REMOVE, self.PHASE_BEFORE) || self.willTrigger(self.TYPE_REMOVE, self.PHASE_AFTER)) {
    					triggerOperation = {
    						type: 'remove'
    					};

    					newDoc = self.decouple(doc);

    					if (self.processTrigger(triggerOperation, self.TYPE_REMOVE, self.PHASE_BEFORE, newDoc, newDoc) !== false) {
    						// The trigger didn't ask to cancel so execute the removal method
    						removeMethod(doc);

    						self.processTrigger(triggerOperation, self.TYPE_REMOVE, self.PHASE_AFTER, newDoc, newDoc);
    					}
    				} else {
    					// No triggers to execute
    					removeMethod(doc);
    				}
    			}

    			if (returnArr.length) {
    				//op.time('Resolve chains');
    				self.chainSend('remove', {
    					query: query,
    					dataSet: returnArr
    				}, options);
    				//op.time('Resolve chains');

    				Eif (!options || (options && !options.noEmit)) {
    					this._onRemove(returnArr);
    				}

    				this._onChange();
    				this.emit('immediateChange', {type: 'remove', data: returnArr});
    				this.deferEmit('change', {type: 'remove', data: returnArr});
    			}
    		}

    		Iif (callback) { callback.call(this, false, returnArr); }
    		return returnArr;
    	}
    };

    /**
     * Helper method that removes a document that matches the given id.
     * @param {String} id The id of the document to remove.
     * @returns {Object} The document that was removed or undefined if
     * nothing was removed.
     */
    Collection.prototype.removeById = function (id) {
    	var searchObj = {};
    	searchObj[this._primaryKey] = id;
    	return this.remove(searchObj)[0];
    };

    /**
     * Processes a deferred action queue.
     * @param {String} type The queue name to process.
     * @param {Function} callback A method to call when the queue has processed.
     * @param {Object=} resultObj A temp object to hold results in.
     */
    Collection.prototype.processQueue = function (type, callback, resultObj) {
    	var self = this,
    		queue = this._deferQueue[type],
    		deferThreshold = this._deferThreshold[type],
    		deferTime = this._deferTime[type],
    		dataArr,
    		result;

    	resultObj = resultObj || {
    		deferred: true
    	};

    	if (queue.length) {
    		// Process items up to the threshold
    		if (queue.length > deferThreshold) {
    			// Grab items up to the threshold value
    			dataArr = queue.splice(0, deferThreshold);
    		} else {
    			// Grab all the remaining items
    			dataArr = queue.splice(0, queue.length);
    		}

    		result = self[type](dataArr);

    		switch (type) {
    			case 'insert':
    				resultObj.inserted = resultObj.inserted || [];
    				resultObj.failed = resultObj.failed || [];

    				resultObj.inserted = resultObj.inserted.concat(result.inserted);
    				resultObj.failed = resultObj.failed.concat(result.failed);
    				break;
    		}

    		// Queue another process
    		setTimeout(function () {
    			self.processQueue.call(self, type, callback, resultObj);
    		}, deferTime);
    	} else {
    		Eif (callback) { callback.call(this, resultObj); }

    		this._asyncComplete(type);
    	}

    	// Check if all queues are complete
    	if (!this.isProcessingQueue()) {
    		this.deferEmit('queuesComplete');
    	}
    };

    /**
     * Checks if any CRUD operations have been deferred and are still waiting to
     * be processed.
     * @returns {Boolean} True if there are still deferred CRUD operations to process
     * or false if all queues are clear.
     */
    Collection.prototype.isProcessingQueue = function () {
    	var i;

    	for (i in this._deferQueue) {
    		Eif (this._deferQueue.hasOwnProperty(i)) {
    			if (this._deferQueue[i].length) {
    				return true;
    			}
    		}
    	}

    	return false;
    };

    /**
     * Inserts a document or array of documents into the collection.
     * @param {Object|Array} data Either a document object or array of document
     * @param {Number=} index Optional index to insert the record at.
     * @param {Function=} callback Optional callback called once action is complete.
     * objects to insert into the collection.
     */
    Collection.prototype.insert = function (data, index, callback) {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}

    	if (typeof(index) === 'function') {
    		callback = index;
    		index = this._data.length;
    	} else Eif (index === undefined) {
    		index = this._data.length;
    	}

    	data = this.transformIn(data);
    	return this._insertHandle(data, index, callback);
    };

    /**
     * Inserts a document or array of documents into the collection.
     * @param {Object|Array} data Either a document object or array of document
     * @param {Number=} index Optional index to insert the record at.
     * @param {Function=} callback Optional callback called once action is complete.
     * objects to insert into the collection.
     */
    Collection.prototype._insertHandle = function (data, index, callback) {
    	var //self = this,
    		queue = this._deferQueue.insert,
    		deferThreshold = this._deferThreshold.insert,
    		//deferTime = this._deferTime.insert,
    		inserted = [],
    		failed = [],
    		insertResult,
    		resultObj,
    		i;

    	if (data instanceof Array) {
    		// Check if there are more insert items than the insert defer
    		// threshold, if so, break up inserts so we don't tie up the
    		// ui or thread
    		if (this._deferredCalls && data.length > deferThreshold) {
    			// Break up insert into blocks
    			this._deferQueue.insert = queue.concat(data);
    			this._asyncPending('insert');

    			// Fire off the insert queue handler
    			this.processQueue('insert', callback);

    			return;
    		} else {
    			// Loop the array and add items
    			for (i = 0; i < data.length; i++) {
    				insertResult = this._insert(data[i], index + i);

    				if (insertResult === true) {
    					inserted.push(data[i]);
    				} else {
    					failed.push({
    						doc: data[i],
    						reason: insertResult
    					});
    				}
    			}
    		}
    	} else {
    		// Store the data item
    		insertResult = this._insert(data, index);

    		if (insertResult === true) {
    			inserted.push(data);
    		} else {
    			failed.push({
    				doc: data,
    				reason: insertResult
    			});
    		}
    	}

    	resultObj = {
    		deferred: false,
    		inserted: inserted,
    		failed: failed
    	};

    	this._onInsert(inserted, failed);
    	Iif (callback) { callback.call(this, resultObj); }

    	this._onChange();
    	this.emit('immediateChange', {type: 'insert', data: inserted});
    	this.deferEmit('change', {type: 'insert', data: inserted});

    	return resultObj;
    };

    /**
     * Internal method to insert a document into the collection. Will
     * check for index violations before allowing the document to be inserted.
     * @param {Object} doc The document to insert after passing index violation
     * tests.
     * @param {Number=} index Optional index to insert the document at.
     * @returns {Boolean|Object} True on success, false if no document passed,
     * or an object containing details about an index violation if one occurred.
     * @private
     */
    Collection.prototype._insert = function (doc, index) {
    	Eif (doc) {
    		var self = this,
    			indexViolation,
    			triggerOperation,
    			insertMethod,
    			newDoc,
    			capped = this.capped(),
    			cappedSize = this.cappedSize();

    		this.ensurePrimaryKey(doc);

    		// Check indexes are not going to be broken by the document
    		indexViolation = this.insertIndexViolation(doc);

    		insertMethod = function (doc) {
    			// Add the item to the collection's indexes
    			self._insertIntoIndexes(doc);

    			// Check index overflow
    			if (index > self._data.length) {
    				index = self._data.length;
    			}

    			// Insert the document
    			self._dataInsertAtIndex(index, doc);

    			// Check capped collection status and remove first record
    			// if we are over the threshold
    			if (capped && self._data.length > cappedSize) {
    				// Remove the first item in the data array
    				self.removeById(self._data[0][self._primaryKey]);
    			}

    			//op.time('Resolve chains');
    			if (self.chainWillSend()) {
    				self.chainSend('insert', {
    					dataSet: self.decouple([doc])
    				}, {
    					index: index
    				});
    			}
    			//op.time('Resolve chains');
    		};

    		if (!indexViolation) {
    			if (self.willTrigger(self.TYPE_INSERT, self.PHASE_BEFORE) || self.willTrigger(self.TYPE_INSERT, self.PHASE_AFTER)) {
    				triggerOperation = {
    					type: 'insert'
    				};

    				if (self.processTrigger(triggerOperation, self.TYPE_INSERT, self.PHASE_BEFORE, {}, doc) !== false) {
    					insertMethod(doc);

    					if (self.willTrigger(self.TYPE_INSERT, self.PHASE_AFTER)) {
    						// Clone the doc so that the programmer cannot update the internal document
    						// on the "after" phase trigger
    						newDoc = self.decouple(doc);

    						self.processTrigger(triggerOperation, self.TYPE_INSERT, self.PHASE_AFTER, {}, newDoc);
    					}
    				} else {
    					// The trigger just wants to cancel the operation
    					return 'Trigger cancelled operation';
    				}
    			} else {
    				// No triggers to execute
    				insertMethod(doc);
    			}

    			return true;
    		} else {
    			return 'Index violation in index: ' + indexViolation;
    		}
    	}

    	return 'No document passed to insert';
    };

    /**
     * Inserts a document into the internal collection data array at
     * Inserts a document into the internal collection data array at
     * the specified index.
     * @param {number} index The index to insert at.
     * @param {object} doc The document to insert.
     * @private
     */
    Collection.prototype._dataInsertAtIndex = function (index, doc) {
    	this._data.splice(index, 0, doc);
    };

    /**
     * Removes a document from the internal collection data array at
     * the specified index.
     * @param {number} index The index to remove from.
     * @private
     */
    Collection.prototype._dataRemoveAtIndex = function (index) {
    	this._data.splice(index, 1);
    };

    /**
     * Replaces all data in the collection's internal data array with
     * the passed array of data.
     * @param {array} data The array of data to replace existing data with.
     * @private
     */
    Collection.prototype._dataReplace = function (data) {
    	// Clear the array - using a while loop with pop is by far the
    	// fastest way to clear an array currently
    	while (this._data.length) {
    		this._data.pop();
    	}

    	// Append new items to the array
    	this._data = this._data.concat(data);
    };

    /**
     * Inserts a document into the collection indexes.
     * @param {Object} doc The document to insert.
     * @private
     */
    Collection.prototype._insertIntoIndexes = function (doc) {
    	var arr = this._indexByName,
    		arrIndex,
    		violated,
    		hash = this.hash(doc),
    		pk = this._primaryKey;

    	// Insert to primary key index
    	violated = this._primaryIndex.uniqueSet(doc[pk], doc);
    	this._primaryCrc.uniqueSet(doc[pk], hash);
    	this._crcLookup.uniqueSet(hash, doc);

    	// Insert into other indexes
    	for (arrIndex in arr) {
    		Eif (arr.hasOwnProperty(arrIndex)) {
    			arr[arrIndex].insert(doc);
    		}
    	}

    	return violated;
    };

    /**
     * Removes a document from the collection indexes.
     * @param {Object} doc The document to remove.
     * @private
     */
    Collection.prototype._removeFromIndexes = function (doc) {
    	var arr = this._indexByName,
    		arrIndex,
    		hash = this.hash(doc),
    		pk = this._primaryKey;

    	// Remove from primary key index
    	this._primaryIndex.unSet(doc[pk]);
    	this._primaryCrc.unSet(doc[pk]);
    	this._crcLookup.unSet(hash);

    	// Remove from other indexes
    	for (arrIndex in arr) {
    		Eif (arr.hasOwnProperty(arrIndex)) {
    			arr[arrIndex].remove(doc);
    		}
    	}
    };

    /**
     * Updates collection index data for the passed document.
     * @param {Object} oldDoc The old document as it was before the update.
     * @param {Object} newDoc The document as it now is after the update.
     * @private
     */
    Collection.prototype._updateIndexes = function (oldDoc, newDoc) {
    	this._removeFromIndexes(oldDoc);
    	this._insertIntoIndexes(newDoc);
    };

    /**
     * Rebuild collection indexes.
     * @private
     */
    Collection.prototype._rebuildIndexes = function () {
    	var arr = this._indexByName,
    		arrIndex;

    	// Remove from other indexes
    	for (arrIndex in arr) {
    		if (arr.hasOwnProperty(arrIndex)) {
    			arr[arrIndex].rebuild();
    		}
    	}
    };

    /**
     * Uses the passed query to generate a new collection with results
     * matching the query parameters.
     *
     * @param {Object} query The query object to generate the subset with.
     * @param {Object=} options An options object.
     * @returns {*}
     */
    Collection.prototype.subset = function (query, options) {
    	var result = this.find(query, options),
    		coll;

    	coll = new Collection();
    	coll.db(this._db);

    	coll.subsetOf(this)
    		.primaryKey(this._primaryKey)
    		.setData(result);

    	return coll;
    };

    /**
     * Gets / sets the collection that this collection is a subset of.
     * @param {Collection=} collection The collection to set as the parent of this subset.
     * @returns {Collection}
     */
    Shared.synthesize(Collection.prototype, 'subsetOf');

    /**
     * Checks if the collection is a subset of the passed collection.
     * @param {Collection} collection The collection to test against.
     * @returns {Boolean} True if the passed collection is the parent of
     * the current collection.
     */
    Collection.prototype.isSubsetOf = function (collection) {
    	return this._subsetOf === collection;
    };

    /**
     * Find the distinct values for a specified field across a single collection and
     * returns the results in an array.
     * @param {String} key The field path to return distinct values for e.g. "person.name".
     * @param {Object=} query The query to use to filter the documents used to return values from.
     * @param {Object=} options The query options to use when running the query.
     * @returns {Array}
     */
    Collection.prototype.distinct = function (key, query, options) {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}

    	var data = this.find(query, options),
    		pathSolver = new Path(key),
    		valueUsed = {},
    		distinctValues = [],
    		value,
    		i;

    	// Loop the data and build array of distinct values
    	for (i = 0; i < data.length; i++) {
    		value = pathSolver.value(data[i])[0];

    		if (value && !valueUsed[value]) {
    			valueUsed[value] = true;
    			distinctValues.push(value);
    		}
    	}

    	return distinctValues;
    };

    /**
     * Helper method to find a document by it's id.
     * @param {String} id The id of the document.
     * @param {Object=} options The options object, allowed keys are sort and limit.
     * @returns {Array} The items that were updated.
     */
    Collection.prototype.findById = function (id, options) {
    	var searchObj = {};
    	searchObj[this._primaryKey] = id;
    	return this.find(searchObj, options)[0];
    };

    /**
     * Finds all documents that contain the passed string or search object
     * regardless of where the string might occur within the document. This
     * will match strings from the start, middle or end of the document's
     * string (partial match).
     * @param search The string to search for. Case sensitive.
     * @param options A standard find() options object.
     * @returns {Array} An array of documents that matched the search string.
     */
    Collection.prototype.peek = function (search, options) {
    	// Loop all items
    	var arr = this._data,
    		arrCount = arr.length,
    		arrIndex,
    		arrItem,
    		tempColl = new Collection(),
    		typeOfSearch = typeof search;

    	Eif (typeOfSearch === 'string') {
    		for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    			// Get json representation of object
    			arrItem = this.jStringify(arr[arrIndex]);

    			// Check if string exists in object json
    			if (arrItem.indexOf(search) > -1) {
    				// Add this item to the temp collection
    				tempColl.insert(arr[arrIndex]);
    			}
    		}

    		return tempColl.find({}, options);
    	} else {
    		return this.find(search, options);
    	}
    };

    /**
     * Provides a query plan / operations log for a query.
     * @param {Object} query The query to execute.
     * @param {Object=} options Optional options object.
     * @returns {Object} The query plan.
     */
    Collection.prototype.explain = function (query, options) {
    	var result = this.find(query, options);
    	return result.__fdbOp._data;
    };

    /**
     * Generates an options object with default values or adds default
     * values to a passed object if those values are not currently set
     * to anything.
     * @param {object=} obj Optional options object to modify.
     * @returns {object} The options object.
     */
    Collection.prototype.options = function (obj) {
    	obj = obj || {};
    	obj.$decouple = obj.$decouple !== undefined ? obj.$decouple : true;
    	obj.$explain = obj.$explain !== undefined ? obj.$explain : false;

    	return obj;
    };

    /**
     * Queries the collection based on the query object passed.
     * @param {Object} query The query key/values that a document must match in
     * order for it to be returned in the result array.
     * @param {Object=} options An optional options object.
     * @param {Function=} callback !! DO NOT USE, THIS IS NON-OPERATIONAL !!
     * Optional callback. If specified the find process
     * will not return a value and will assume that you wish to operate under an
     * async mode. This will break up large find requests into smaller chunks and
     * process them in a non-blocking fashion allowing large datasets to be queried
     * without causing the browser UI to pause. Results from this type of operation
     * will be passed back to the callback once completed.
     *
     * @returns {Array} The results array from the find operation, containing all
     * documents that matched the query.
     */
    Collection.prototype.find = function (query, options, callback) {
    	// Convert queries from mongo dot notation to forerunner queries
    	if (this.mongoEmulation()) {
    		this.convertToFdb(query);
    	}

    	Iif (callback) {
    		// Check the size of the collection's data array

    		// Split operation into smaller tasks and callback when complete
    		callback.call(this, 'Callbacks for the find() operation are not yet implemented!', []);
    		return [];
    	}

    	return this._find.call(this, query, options, callback);
    };

    Collection.prototype._find = function (query, options) {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}

    	// TODO: This method is quite long, break into smaller pieces
    	query = query || {};

    	var op = this._metrics.create('find'),
    		pk = this.primaryKey(),
    		self = this,
    		analysis,
    		scanLength,
    		requiresTableScan = true,
    		resultArr,
    		joinIndex,
    		joinSource = {},
    		joinQuery,
    		joinPath,
    		joinSourceKey,
    		joinSourceType,
    		joinSourceIdentifier,
    		joinSourceData,
    		resultRemove = [],
    		i, j, k,
    		fieldListOn = [],
    		fieldListOff = [],
    		elemMatchPathSolver,
    		elemMatchSubArr,
    		elemMatchSpliceArr,
    		matcherTmpOptions = {},
    		result,
    		cursor = {},
    		pathSolver,
    		waterfallCollection,
    		matcher;

    	Eif (!(options instanceof Array)) {
    		options = this.options(options);
    	}

    	matcher = function (doc) {
    		return self._match(doc, query, options, 'and', matcherTmpOptions);
    	};

    	op.start();
    	Eif (query) {
    		// Check if the query is an array (multi-operation waterfall query)
    		if (query instanceof Array) {
    			waterfallCollection = this;

    			// Loop the query operations
    			for (i = 0; i < query.length; i++) {
    				// Execute each operation and pass the result into the next
    				// query operation
    				waterfallCollection = waterfallCollection.subset(query[i], options && options[i] ? options[i] : {});
    			}

    			return waterfallCollection.find();
    		}

    		// Pre-process any data-changing query operators first
    		if (query.$findSub) {
    			// Check we have all the parts we need
    			Iif (!query.$findSub.$path) {
    				throw('$findSub missing $path property!');
    			}

    			return this.findSub(
    				query.$findSub.$query,
    				query.$findSub.$path,
    				query.$findSub.$subQuery,
    				query.$findSub.$subOptions
    			);
    		}

    		Iif (query.$findSubOne) {
    			// Check we have all the parts we need
    			if (!query.$findSubOne.$path) {
    				throw('$findSubOne missing $path property!');
    			}

    			return this.findSubOne(
    				query.$findSubOne.$query,
    				query.$findSubOne.$path,
    				query.$findSubOne.$subQuery,
    				query.$findSubOne.$subOptions
    			);
    		}

    		// Get query analysis to execute best optimised code path
    		op.time('analyseQuery');
    		analysis = this._analyseQuery(self.decouple(query), options, op);
    		op.time('analyseQuery');
    		op.data('analysis', analysis);

    		// Check if the query tries to limit by data that would only exist after
    		// the join operation has been completed
    		if (analysis.hasJoin && analysis.queriesJoin) {
    			// The query has a join and tries to limit by it's joined data
    			// Get references to the join sources
    			op.time('joinReferences');
    			for (joinIndex = 0; joinIndex < analysis.joinsOn.length; joinIndex++) {
    				joinSourceData = analysis.joinsOn[joinIndex];
    				joinSourceKey = joinSourceData.key;

    				joinSourceType = joinSourceData.type;
    				joinSourceIdentifier = joinSourceData.id;

    				joinPath = new Path(analysis.joinQueries[joinSourceKey]);
    				joinQuery = joinPath.value(query)[0];

    				joinSource[joinSourceIdentifier] = this._db[joinSourceType](joinSourceKey).subset(joinQuery);

    				// Remove join clause from main query
    				delete query[analysis.joinQueries[joinSourceKey]];
    			}
    			op.time('joinReferences');
    		}

    		// Check if an index lookup can be used to return this result
    		if (analysis.indexMatch.length && (!options || (options && !options.$skipIndex))) {
    			op.data('index.potential', analysis.indexMatch);
    			op.data('index.used', analysis.indexMatch[0].index);

    			// Get the data from the index
    			op.time('indexLookup');
    			resultArr = analysis.indexMatch[0].lookup || [];
    			op.time('indexLookup');

    			// Check if the index coverage is all keys, if not we still need to table scan it
    			if (analysis.indexMatch[0].keyData.totalKeyCount === analysis.indexMatch[0].keyData.score) {
    				// Don't require a table scan to find relevant documents
    				requiresTableScan = false;
    			}
    		} else {
    			op.flag('usedIndex', false);
    		}

    		if (requiresTableScan) {
    			if (resultArr && resultArr.length) {
    				scanLength = resultArr.length;
    				op.time('tableScan: ' + scanLength);
    				// Filter the source data and return the result
    				resultArr = resultArr.filter(matcher);
    			} else {
    				// Filter the source data and return the result
    				scanLength = this._data.length;
    				op.time('tableScan: ' + scanLength);
    				resultArr = this._data.filter(matcher);
    			}

    			op.time('tableScan: ' + scanLength);
    		}

    		// Order the array if we were passed a sort clause
    		if (options.$orderBy) {
    			op.time('sort');
    			resultArr = this.sort(options.$orderBy, resultArr);
    			op.time('sort');
    		}

    		if (options.$page !== undefined && options.$limit !== undefined) {
    			// Record paging data
    			cursor.page = options.$page;
    			cursor.pages = Math.ceil(resultArr.length / options.$limit);
    			cursor.records = resultArr.length;

    			// Check if we actually need to apply the paging logic
    			if (options.$page && options.$limit > 0) {
    				op.data('cursor', cursor);

    				// Skip to the page specified based on limit
    				resultArr.splice(0, options.$page * options.$limit);
    			}
    		}

    		if (options.$skip) {
    			cursor.skip = options.$skip;

    			// Skip past the number of records specified
    			resultArr.splice(0, options.$skip);
    			op.data('skip', options.$skip);
    		}

    		if (options.$limit && resultArr && resultArr.length > options.$limit) {
    			cursor.limit = options.$limit;

    			resultArr.length = options.$limit;
    			op.data('limit', options.$limit);
    		}

    		if (options.$decouple) {
    			// Now decouple the data from the original objects
    			op.time('decouple');
    			resultArr = this.decouple(resultArr);
    			op.time('decouple');
    			op.data('flag.decouple', true);
    		}

    		// Now process any joins on the final data
    		if (options.$join) {
    			resultRemove = resultRemove.concat(this.applyJoin(resultArr, options.$join, joinSource));
    			op.data('flag.join', true);
    		}

    		// Process removal queue
    		if (resultRemove.length) {
    			op.time('removalQueue');
    			this.spliceArrayByIndexList(resultArr, resultRemove);
    			op.time('removalQueue');
    		}

    		if (options.$transform) {
    			op.time('transform');
    			for (i = 0; i < resultArr.length; i++) {
    				resultArr.splice(i, 1, options.$transform(resultArr[i]));
    			}
    			op.time('transform');
    			op.data('flag.transform', true);
    		}

    		// Process transforms
    		if (this._transformEnabled && this._transformOut) {
    			op.time('transformOut');
    			resultArr = this.transformOut(resultArr);
    			op.time('transformOut');
    		}

    		op.data('results', resultArr.length);
    	} else {
    		resultArr = [];
    	}

    	// Check for an $as operator in the options object and if it exists
    	// iterate over the fields and generate a rename function that will
    	// operate over the entire returned data array and rename each object's
    	// fields to their new names
    	// TODO: Enable $as in collection find to allow renaming fields
    	/*if (options.$as) {
    		renameFieldPath = new Path();
    		renameFieldMethod = function (obj, oldFieldPath, newFieldName) {
    			renameFieldPath.path(oldFieldPath);
    			renameFieldPath.rename(newFieldName);
    		};

    		for (i in options.$as) {
    			if (options.$as.hasOwnProperty(i)) {

    			}
    		}
    	}*/

    	if (!options.$aggregate) {
    		// Generate a list of fields to limit data by
    		// Each property starts off being enabled by default (= 1) then
    		// if any property is explicitly specified as 1 then all switch to
    		// zero except _id.
    		//
    		// Any that are explicitly set to zero are switched off.
    		op.time('scanFields');
    		for (i in options) {
    			if (options.hasOwnProperty(i) && i.indexOf('$') !== 0) {
    				if (options[i] === 1) {
    					fieldListOn.push(i);
    				} else if (options[i] === 0) {
    					fieldListOff.push(i);
    				}
    			}
    		}
    		op.time('scanFields');

    		// Limit returned fields by the options data
    		if (fieldListOn.length || fieldListOff.length) {
    			op.data('flag.limitFields', true);
    			op.data('limitFields.on', fieldListOn);
    			op.data('limitFields.off', fieldListOff);

    			op.time('limitFields');

    			// We have explicit fields switched on or off
    			for (i = 0; i < resultArr.length; i++) {
    				result = resultArr[i];

    				for (j in result) {
    					Eif (result.hasOwnProperty(j)) {
    						if (fieldListOn.length) {
    							// We have explicit fields switched on so remove all fields
    							// that are not explicitly switched on

    							// Check if the field name is not the primary key
    							if (j !== pk) {
    								if (fieldListOn.indexOf(j) === -1) {
    									// This field is not in the on list, remove it
    									delete result[j];
    								}
    							}
    						}

    						if (fieldListOff.length) {
    							// We have explicit fields switched off so remove fields
    							// that are explicitly switched off
    							if (fieldListOff.indexOf(j) > -1) {
    								// This field is in the off list, remove it
    								delete result[j];
    							}
    						}
    					}
    				}
    			}

    			op.time('limitFields');
    		}

    		// Now run any projections on the data required
    		if (options.$elemMatch) {
    			op.data('flag.elemMatch', true);
    			op.time('projection-elemMatch');

    			for (i in options.$elemMatch) {
    				Eif (options.$elemMatch.hasOwnProperty(i)) {
    					elemMatchPathSolver = new Path(i);

    					// Loop the results array
    					for (j = 0; j < resultArr.length; j++) {
    						elemMatchSubArr = elemMatchPathSolver.value(resultArr[j])[0];

    						// Check we have a sub-array to loop
    						Eif (elemMatchSubArr && elemMatchSubArr.length) {

    							// Loop the sub-array and check for projection query matches
    							for (k = 0; k < elemMatchSubArr.length; k++) {

    								// Check if the current item in the sub-array matches the projection query
    								if (self._match(elemMatchSubArr[k], options.$elemMatch[i], options, '', {})) {
    									// The item matches the projection query so set the sub-array
    									// to an array that ONLY contains the matching item and then
    									// exit the loop since we only want to match the first item
    									elemMatchPathSolver.set(resultArr[j], i, [elemMatchSubArr[k]]);
    									break;
    								}
    							}
    						}
    					}
    				}
    			}

    			op.time('projection-elemMatch');
    		}

    		if (options.$elemsMatch) {
    			op.data('flag.elemsMatch', true);
    			op.time('projection-elemsMatch');

    			for (i in options.$elemsMatch) {
    				Eif (options.$elemsMatch.hasOwnProperty(i)) {
    					elemMatchPathSolver = new Path(i);

    					// Loop the results array
    					for (j = 0; j < resultArr.length; j++) {
    						elemMatchSubArr = elemMatchPathSolver.value(resultArr[j])[0];

    						// Check we have a sub-array to loop
    						Eif (elemMatchSubArr && elemMatchSubArr.length) {
    							elemMatchSpliceArr = [];

    							// Loop the sub-array and check for projection query matches
    							for (k = 0; k < elemMatchSubArr.length; k++) {

    								// Check if the current item in the sub-array matches the projection query
    								if (self._match(elemMatchSubArr[k], options.$elemsMatch[i], options, '', {})) {
    									// The item matches the projection query so add it to the final array
    									elemMatchSpliceArr.push(elemMatchSubArr[k]);
    								}
    							}

    							// Now set the final sub-array to the matched items
    							elemMatchPathSolver.set(resultArr[j], i, elemMatchSpliceArr);
    						}
    					}
    				}
    			}

    			op.time('projection-elemsMatch');
    		}
    	}

    	// Process aggregation
    	if (options.$aggregate) {
    		op.data('flag.aggregate', true);
    		op.time('aggregate');
    		pathSolver = new Path(options.$aggregate);
    		resultArr = pathSolver.value(resultArr);
    		op.time('aggregate');
    	}

    	op.stop();
    	resultArr.__fdbOp = op;
    	resultArr.$cursor = cursor;
    	return resultArr;
    };

    /**
     * Returns one document that satisfies the specified query criteria. If multiple
     * documents satisfy the query, this method returns the first document to match
     * the query.
     * @returns {*}
     */
    Collection.prototype.findOne = function () {
    	return (this.find.apply(this, arguments))[0];
    };

    /**
     * Gets the index in the collection data array of the first item matched by
     * the passed query object.
     * @param {Object} query The query to run to find the item to return the index of.
     * @param {Object=} options An options object.
     * @returns {Number}
     */
    Collection.prototype.indexOf = function (query, options) {
    	var item = this.find(query, {$decouple: false})[0],
    		sortedData;

    	Eif (item) {
    		Eif (!options || options && !options.$orderBy) {
    			// Basic lookup from order of insert
    			return this._data.indexOf(item);
    		} else {
    			// Trying to locate index based on query with sort order
    			options.$decouple = false;
    			sortedData = this.find(query, options);

    			return sortedData.indexOf(item);
    		}
    	}

    	return -1;
    };

    /**
     * Returns the index of the document identified by the passed item's primary key.
     * @param {*} itemLookup The document whose primary key should be used to lookup
     * or the id to lookup.
     * @param {Object=} options An options object.
     * @returns {Number} The index the item with the matching primary key is occupying.
     */
    Collection.prototype.indexOfDocById = function (itemLookup, options) {
    	var item,
    		sortedData;

    	if (typeof itemLookup !== 'object') {
    		item = this._primaryIndex.get(itemLookup);
    	} else {
    		item = this._primaryIndex.get(itemLookup[this._primaryKey]);
    	}

    	Eif (item) {
    		Eif (!options || options && !options.$orderBy) {
    			// Basic lookup
    			return this._data.indexOf(item);
    		} else {
    			// Sorted lookup
    			options.$decouple = false;
    			sortedData = this.find({}, options);

    			return sortedData.indexOf(item);
    		}
    	}

    	return -1;
    };

    /**
     * Removes a document from the collection by it's index in the collection's
     * data array.
     * @param {Number} index The index of the document to remove.
     * @returns {Object} The document that has been removed or false if none was
     * removed.
     */
    Collection.prototype.removeByIndex = function (index) {
    	var doc,
    		docId;

    	doc = this._data[index];

    	if (doc !== undefined) {
    		doc = this.decouple(doc);
    		docId = doc[this.primaryKey()];

    		return this.removeById(docId);
    	}

    	return false;
    };

    /**
     * Gets / sets the collection transform options.
     * @param {Object} obj A collection transform options object.
     * @returns {*}
     */
    Collection.prototype.transform = function (obj) {
    	if (obj !== undefined) {
    		if (typeof obj === "object") {
    			Eif (obj.enabled !== undefined) {
    				this._transformEnabled = obj.enabled;
    			}

    			if (obj.dataIn !== undefined) {
    				this._transformIn = obj.dataIn;
    			}

    			if (obj.dataOut !== undefined) {
    				this._transformOut = obj.dataOut;
    			}
    		} else {
    			this._transformEnabled = obj !== false;
    		}

    		return this;
    	}

    	return {
    		enabled: this._transformEnabled,
    		dataIn: this._transformIn,
    		dataOut: this._transformOut
    	};
    };

    /**
     * Transforms data using the set transformIn method.
     * @param {Object} data The data to transform.
     * @returns {*}
     */
    Collection.prototype.transformIn = function (data) {
    	if (this._transformEnabled && this._transformIn) {
    		if (data instanceof Array) {
    			var finalArr = [],
    				transformResult,
    				i;

    			for (i = 0; i < data.length; i++) {
    				transformResult = this._transformIn(data[i]);

    				// Support transforms returning multiple items
    				Iif (transformResult instanceof Array) {
    					finalArr = finalArr.concat(transformResult);
    				} else {
    					finalArr.push(transformResult);
    				}
    			}

    			return finalArr;
    		} else {
    			return this._transformIn(data);
    		}
    	}

    	return data;
    };

    /**
     * Transforms data using the set transformOut method.
     * @param {Object} data The data to transform.
     * @returns {*}
     */
    Collection.prototype.transformOut = function (data) {
    	Eif (this._transformEnabled && this._transformOut) {
    		Eif (data instanceof Array) {
    			var finalArr = [],
    				transformResult,
    				i;

    			for (i = 0; i < data.length; i++) {
    				transformResult = this._transformOut(data[i]);

    				// Support transforms returning multiple items
    				Iif (transformResult instanceof Array) {
    					finalArr = finalArr.concat(transformResult);
    				} else {
    					finalArr.push(transformResult);
    				}
    			}

    			return finalArr;
    		} else {
    			return this._transformOut(data);
    		}
    	}

    	return data;
    };

    /**
     * Sorts an array of documents by the given sort path.
     * @param {*} sortObj The keys and orders the array objects should be sorted by.
     * @param {Array} arr The array of documents to sort.
     * @returns {Array}
     */
    Collection.prototype.sort = function (sortObj, arr) {
    	// Convert the index object to an array of key val objects
    	var self = this,
    		keys = sharedPathSolver.parse(sortObj, true);

    	if (keys.length) {
    		// Execute sort
    		arr.sort(function (a, b) {
    			// Loop the index array
    			var i,
    				indexData,
    				result = 0;

    			for (i = 0; i < keys.length; i++) {
    				indexData = keys[i];

    				if (indexData.value === 1) {
    					result = self.sortAsc(sharedPathSolver.get(a, indexData.path), sharedPathSolver.get(b, indexData.path));
    				} else Eif (indexData.value === -1) {
    					result = self.sortDesc(sharedPathSolver.get(a, indexData.path), sharedPathSolver.get(b, indexData.path));
    				}

    				if (result !== 0) {
    					return result;
    				}
    			}

    			return result;
    		});
    	}

    	return arr;
    };

    // Commented as we have a new method that was originally implemented for binary trees.
    // This old method actually has problems with nested sort objects
    /*Collection.prototype.sortold = function (sortObj, arr) {
    	// Make sure we have an array object
    	arr = arr || [];

    	var	sortArr = [],
    		sortKey,
    		sortSingleObj;

    	for (sortKey in sortObj) {
    		if (sortObj.hasOwnProperty(sortKey)) {
    			sortSingleObj = {};
    			sortSingleObj[sortKey] = sortObj[sortKey];
    			sortSingleObj.___fdbKey = String(sortKey);
    			sortArr.push(sortSingleObj);
    		}
    	}

    	if (sortArr.length < 2) {
    		// There is only one sort criteria, do a simple sort and return it
    		return this._sort(sortObj, arr);
    	} else {
    		return this._bucketSort(sortArr, arr);
    	}
    };*/

    /**
     * Takes array of sort paths and sorts them into buckets before returning final
     * array fully sorted by multi-keys.
     * @param keyArr
     * @param arr
     * @returns {*}
     * @private
     */
    /*Collection.prototype._bucketSort = function (keyArr, arr) {
    	var keyObj = keyArr.shift(),
    		arrCopy,
    		bucketData,
    		bucketOrder,
    		bucketKey,
    		buckets,
    		i,
    		finalArr = [];

    	if (keyArr.length > 0) {
    		// Sort array by bucket key
    		arr = this._sort(keyObj, arr);

    		// Split items into buckets
    		bucketData = this.bucket(keyObj.___fdbKey, arr);
    		bucketOrder = bucketData.order;
    		buckets = bucketData.buckets;

    		// Loop buckets and sort contents
    		for (i = 0; i < bucketOrder.length; i++) {
    			bucketKey = bucketOrder[i];

    			arrCopy = [].concat(keyArr);
    			finalArr = finalArr.concat(this._bucketSort(arrCopy, buckets[bucketKey]));
    		}

    		return finalArr;
    	} else {
    		return this._sort(keyObj, arr);
    	}
    };*/

     /**
     * Takes an array of objects and returns a new object with the array items
     * split into buckets by the passed key.
     * @param {String} key The key to split the array into buckets by.
     * @param {Array} arr An array of objects.
     * @returns {Object}
     */
    /*Collection.prototype.bucket = function (key, arr) {
    	var i,
    			oldField,
    			field,
    			fieldArr = [],
    			buckets = {};

    	for (i = 0; i < arr.length; i++) {
    		field = String(arr[i][key]);

    		if (oldField !== field) {
    			fieldArr.push(field);
    			oldField = field;
    		}

    		buckets[field] = buckets[field] || [];
    		buckets[field].push(arr[i]);
    	}

    	return {
    		buckets: buckets,
    		order: fieldArr
    	};
    };*/

    /**
     * Sorts array by individual sort path.
     * @param key
     * @param arr
     * @returns {Array|*}
     * @private
     */
    Collection.prototype._sort = function (key, arr) {
    	var self = this,
    		sorterMethod,
    		pathSolver = new Path(),
    		dataPath = pathSolver.parse(key, true)[0];

    	pathSolver.path(dataPath.path);

    	if (dataPath.value === 1) {
    		// Sort ascending
    		sorterMethod = function (a, b) {
    			var valA = pathSolver.value(a)[0],
    				valB = pathSolver.value(b)[0];

    			return self.sortAsc(valA, valB);
    		};
    	} else if (dataPath.value === -1) {
    		// Sort descending
    		sorterMethod = function (a, b) {
    			var valA = pathSolver.value(a)[0],
    				valB = pathSolver.value(b)[0];

    			return self.sortDesc(valA, valB);
    		};
    	} else {
    		throw(this.logIdentifier() + ' $orderBy clause has invalid direction: ' + dataPath.value + ', accepted values are 1 or -1 for ascending or descending!');
    	}

    	return arr.sort(sorterMethod);
    };

    /**
     * Internal method that takes a search query and options and returns an object
     * containing details about the query which can be used to optimise the search.
     *
     * @param query
     * @param options
     * @param op
     * @returns {Object}
     * @private
     */
    Collection.prototype._analyseQuery = function (query, options, op) {
    	var analysis = {
    			queriesOn: [{id: '$collection.' + this._name, type: 'colletion', key: this._name}],
    			indexMatch: [],
    			hasJoin: false,
    			queriesJoin: false,
    			joinQueries: {},
    			query: query,
    			options: options
    		},
    		joinSourceIndex,
    		joinSourceKey,
    		joinSourceType,
    		joinSourceIdentifier,
    		joinMatch,
    		joinSources = [],
    		joinSourceReferences = [],
    		queryPath,
    		index,
    		indexMatchData,
    		indexRef,
    		indexRefName,
    		indexLookup,
    		pathSolver,
    		queryKeyCount,
    		pkQueryType,
    		lookupResult,
    		i;

    	// Check if the query is a primary key lookup
    	op.time('checkIndexes');
    	pathSolver = new Path();
    	queryKeyCount = pathSolver.parseArr(query, {
    		ignore:/\$/,
    		verbose: true
    	}).length;

    	if (queryKeyCount) {
    		if (query[this._primaryKey] !== undefined) {
    			// Check suitability of querying key value index
    			pkQueryType = typeof query[this._primaryKey];

    			if (pkQueryType === 'string' || pkQueryType === 'number' || query[this._primaryKey] instanceof Array) {
    				// Return item via primary key possible
    				op.time('checkIndexMatch: Primary Key');
    				lookupResult = this._primaryIndex.lookup(query, options);

    				analysis.indexMatch.push({
    					lookup: lookupResult,
    					keyData: {
    						matchedKeys: [this._primaryKey],
    						totalKeyCount: queryKeyCount,
    						score: 1
    					},
    					index: this._primaryIndex
    				});
    				op.time('checkIndexMatch: Primary Key');
    			}
    		}

    		// Check if an index can speed up the query
    		for (i in this._indexById) {
    			Eif (this._indexById.hasOwnProperty(i)) {
    				indexRef = this._indexById[i];
    				indexRefName = indexRef.name();

    				op.time('checkIndexMatch: ' + indexRefName);
    				indexMatchData = indexRef.match(query, options);

    				if (indexMatchData.score > 0) {
    					// This index can be used, store it
    					indexLookup = indexRef.lookup(query, options);

    					analysis.indexMatch.push({
    						lookup: indexLookup,
    						keyData: indexMatchData,
    						index: indexRef
    					});
    				}
    				op.time('checkIndexMatch: ' + indexRefName);

    				if (indexMatchData.score === queryKeyCount) {
    					// Found an optimal index, do not check for any more
    					break;
    				}
    			}
    		}
    		op.time('checkIndexes');

    		// Sort array descending on index key count (effectively a measure of relevance to the query)
    		if (analysis.indexMatch.length > 1) {
    			op.time('findOptimalIndex');
    			analysis.indexMatch.sort(function (a, b) {
    				Eif (a.keyData.score > b.keyData.score) {
    					// This index has a higher score than the other
    					return -1;
    				}

    				if (a.keyData.score < b.keyData.score) {
    					// This index has a lower score than the other
    					return 1;
    				}

    				// The indexes have the same score but can still be compared by the number of records
    				// they return from the query. The fewer records they return the better so order by
    				// record count
    				if (a.keyData.score === b.keyData.score) {
    					return a.lookup.length - b.lookup.length;
    				}
    			});
    			op.time('findOptimalIndex');
    		}
    	}

    	// Check for join data
    	if (options.$join) {
    		analysis.hasJoin = true;

    		// Loop all join operations
    		for (joinSourceIndex = 0; joinSourceIndex < options.$join.length; joinSourceIndex++) {
    			// Loop the join sources and keep a reference to them
    			for (joinSourceKey in options.$join[joinSourceIndex]) {
    				Eif (options.$join[joinSourceIndex].hasOwnProperty(joinSourceKey)) {
    					joinMatch = options.$join[joinSourceIndex][joinSourceKey];

    					joinSourceType = joinMatch.$sourceType || 'collection';
    					joinSourceIdentifier = '$' + joinSourceType + '.' + joinSourceKey;

    					joinSources.push({
    						id: joinSourceIdentifier,
    						type: joinSourceType,
    						key: joinSourceKey
    					});

    					// Check if the join uses an $as operator
    					Eif (options.$join[joinSourceIndex][joinSourceKey].$as !== undefined) {
    						joinSourceReferences.push(options.$join[joinSourceIndex][joinSourceKey].$as);
    					} else {
    						joinSourceReferences.push(joinSourceKey);
    					}
    				}
    			}
    		}

    		// Loop the join source references and determine if the query references
    		// any of the sources that are used in the join. If there no queries against
    		// joined sources the find method can use a code path optimised for this.

    		// Queries against joined sources requires the joined sources to be filtered
    		// first and then joined so requires a little more work.
    		for (index = 0; index < joinSourceReferences.length; index++) {
    			// Check if the query references any source data that the join will create
    			queryPath = this._queryReferencesSource(query, joinSourceReferences[index], '');

    			if (queryPath) {
    				analysis.joinQueries[joinSources[index].key] = queryPath;
    				analysis.queriesJoin = true;
    			}
    		}

    		analysis.joinsOn = joinSources;
    		analysis.queriesOn = analysis.queriesOn.concat(joinSources);
    	}

    	return analysis;
    };

    /**
     * Checks if the passed query references a source object (such
     * as a collection) by name.
     * @param {Object} query The query object to scan.
     * @param {String} sourceName The source name to scan for in the query.
     * @param {String=} path The path to scan from.
     * @returns {*}
     * @private
     */
    Collection.prototype._queryReferencesSource = function (query, sourceName, path) {
    	var i;

    	for (i in query) {
    		Eif (query.hasOwnProperty(i)) {
    			// Check if this key is a reference match
    			Eif (i === sourceName) {
    				Iif (path) { path += '.'; }
    				return path + i;
    			} else {
    				if (typeof(query[i]) === 'object') {
    					// Recurse
    					if (path) { path += '.'; }
    					path += i;
    					return this._queryReferencesSource(query[i], sourceName, path);
    				}
    			}
    		}
    	}

    	return false;
    };

    /**
     * Returns the number of documents currently in the collection.
     * @returns {Number}
     */
    Collection.prototype.count = function (query, options) {
    	if (!query) {
    		return this._data.length;
    	} else {
    		// Run query and return count
    		return this.find(query, options).length;
    	}
    };

    /**
     * Finds sub-documents from the collection's documents.
     * @param {Object} match The query object to use when matching parent documents
     * from which the sub-documents are queried.
     * @param {String} path The path string used to identify the key in which
     * sub-documents are stored in parent documents.
     * @param {Object=} subDocQuery The query to use when matching which sub-documents
     * to return.
     * @param {Object=} subDocOptions The options object to use when querying for
     * sub-documents.
     * @returns {*}
     */
    Collection.prototype.findSub = function (match, path, subDocQuery, subDocOptions) {
    	return this._findSub(this.find(match), path, subDocQuery, subDocOptions);
    };

    Collection.prototype._findSub = function (docArr, path, subDocQuery, subDocOptions) {
    	var pathHandler = new Path(path),
    		docCount = docArr.length,
    		docIndex,
    		subDocArr,
    		subDocCollection = new Collection('__FDB_temp_' + this.objectId()).db(this._db),
    		subDocResults,
    		resultObj = {
    			parents: docCount,
    			subDocTotal: 0,
    			subDocs: [],
    			pathFound: false,
    			err: ''
    		};

    	subDocOptions = subDocOptions || {};

    	for (docIndex = 0; docIndex < docCount; docIndex++) {
    		subDocArr = pathHandler.value(docArr[docIndex])[0];
    		Eif (subDocArr) {
    			subDocCollection.setData(subDocArr);
    			subDocResults = subDocCollection.find(subDocQuery, subDocOptions);
    			Iif (subDocOptions.returnFirst && subDocResults.length) {
    				return subDocResults[0];
    			}

    			Iif (subDocOptions.$split) {
    				resultObj.subDocs.push(subDocResults);
    			} else {
    				resultObj.subDocs = resultObj.subDocs.concat(subDocResults);
    			}

    			resultObj.subDocTotal += subDocResults.length;
    			resultObj.pathFound = true;
    		}
    	}

    	// Drop the sub-document collection
    	subDocCollection.drop();

    	Iif (!resultObj.pathFound) {
    		resultObj.err = 'No objects found in the parent documents with a matching path of: ' + path;
    	}

    	// Check if the call should not return stats, if so return only subDocs array
    	Iif (subDocOptions.$stats) {
    		return resultObj;
    	} else {
    		return resultObj.subDocs;
    	}
    };

    /**
     * Finds the first sub-document from the collection's documents that matches
     * the subDocQuery parameter.
     * @param {Object} match The query object to use when matching parent documents
     * from which the sub-documents are queried.
     * @param {String} path The path string used to identify the key in which
     * sub-documents are stored in parent documents.
     * @param {Object=} subDocQuery The query to use when matching which sub-documents
     * to return.
     * @param {Object=} subDocOptions The options object to use when querying for
     * sub-documents.
     * @returns {Object}
     */
    Collection.prototype.findSubOne = function (match, path, subDocQuery, subDocOptions) {
    	return this.findSub(match, path, subDocQuery, subDocOptions)[0];
    };

    /**
     * Checks that the passed document will not violate any index rules if
     * inserted into the collection.
     * @param {Object} doc The document to check indexes against.
     * @returns {Boolean} Either false (no violation occurred) or true if
     * a violation was detected.
     */
    Collection.prototype.insertIndexViolation = function (doc) {
    	var indexViolated,
    		arr = this._indexByName,
    		arrIndex,
    		arrItem;

    	// Check the item's primary key is not already in use
    	if (this._primaryIndex.get(doc[this._primaryKey])) {
    		indexViolated = this._primaryIndex;
    	} else {
    		// Check violations of other indexes
    		for (arrIndex in arr) {
    			Eif (arr.hasOwnProperty(arrIndex)) {
    				arrItem = arr[arrIndex];

    				if (arrItem.unique()) {
    					if (arrItem.violation(doc)) {
    						indexViolated = arrItem;
    						break;
    					}
    				}
    			}
    		}
    	}

    	return indexViolated ? indexViolated.name() : false;
    };

    /**
     * Creates an index on the specified keys.
     * @param {Object} keys The object containing keys to index.
     * @param {Object} options An options object.
     * @returns {*}
     */
    Collection.prototype.ensureIndex = function (keys, options) {
    	Iif (this.isDropped()) {
    		throw(this.logIdentifier() + ' Cannot operate in a dropped state!');
    	}

    	this._indexByName = this._indexByName || {};
    	this._indexById = this._indexById || {};

    	var index,
    		time = {
    			start: new Date().getTime()
    		};

    	if (options) {
    		if (options.type) {
    			// Check if the specified type is available
    			Eif (Shared.index[options.type]) {
    				// We found the type, generate it
    				index = new Shared.index[options.type](keys, options, this);
    			} else {
    				throw(this.logIdentifier() + ' Cannot create index of type "' + options.type + '", type not found in the index type register (Shared.index)');
    			}
    		} else {
    			// Create default index type
    			index = new IndexHashMap(keys, options, this);
    		}
    	} else {
    		// Default
    		index = new IndexHashMap(keys, options, this);
    	}

    	// Check the index does not already exist
    	Iif (this._indexByName[index.name()]) {
    		// Index already exists
    		return {
    			err: 'Index with that name already exists'
    		};
    	}

    	/*if (this._indexById[index.id()]) {
    		// Index already exists
    		return {
    			err: 'Index with those keys already exists'
    		};
    	}*/

    	// Create the index
    	index.rebuild();

    	// Add the index
    	this._indexByName[index.name()] = index;
    	this._indexById[index.id()] = index;

    	time.end = new Date().getTime();
    	time.total = time.end - time.start;

    	this._lastOp = {
    		type: 'ensureIndex',
    		stats: {
    			time: time
    		}
    	};

    	return {
    		index: index,
    		id: index.id(),
    		name: index.name(),
    		state: index.state()
    	};
    };

    /**
     * Gets an index by it's name.
     * @param {String} name The name of the index to retreive.
     * @returns {*}
     */
    Collection.prototype.index = function (name) {
    	Eif (this._indexByName) {
    		return this._indexByName[name];
    	}
    };

    /**
     * Gets the last reporting operation's details such as run time.
     * @returns {Object}
     */
    Collection.prototype.lastOp = function () {
    	return this._metrics.list();
    };

    /**
     * Generates a difference object that contains insert, update and remove arrays
     * representing the operations to execute to make this collection have the same
     * data as the one passed.
     * @param {Collection} collection The collection to diff against.
     * @returns {{}}
     */
    Collection.prototype.diff = function (collection) {
    	var diff = {
    		insert: [],
    		update: [],
    		remove: []
    	};

    	var pk = this.primaryKey(),
    		arr,
    		arrIndex,
    		arrItem,
    		arrCount;

    	// Check if the primary key index of each collection can be utilised
    	Iif (pk !== collection.primaryKey()) {
    		throw(this.logIdentifier() + ' Diffing requires that both collections have the same primary key!');
    	}

    	// Use the collection primary key index to do the diff (super-fast)
    	arr = collection._data;

    	// Check if we have an array or another collection
    	while (arr && !(arr instanceof Array)) {
    		// We don't have an array, assign collection and get data
    		collection = arr;
    		arr = collection._data;
    	}

    	arrCount = arr.length;

    	// Loop the collection's data array and check for matching items
    	for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    		arrItem = arr[arrIndex];

    		// Check for a matching item in this collection
    		if (this._primaryIndex.get(arrItem[pk])) {
    			// Matching item exists, check if the data is the same
    			if (this._primaryCrc.get(arrItem[pk]) !== collection._primaryCrc.get(arrItem[pk])) {
    				// The documents exist in both collections but data differs, update required
    				diff.update.push(arrItem);
    			}
    		} else {
    			// The document is missing from this collection, insert required
    			diff.insert.push(arrItem);
    		}
    	}

    	// Now loop this collection's data and check for matching items
    	arr = this._data;
    	arrCount = arr.length;

    	for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    		arrItem = arr[arrIndex];

    		if (!collection._primaryIndex.get(arrItem[pk])) {
    			// The document does not exist in the other collection, remove required
    			diff.remove.push(arrItem);
    		}
    	}

    	return diff;
    };

    Collection.prototype.collateAdd = new Overload('Collection.prototype.collateAdd', {
    	/**
    	 * Adds a data source to collate data from and specifies the
    	 * key name to collate data to.
    	 * @func collateAdd
    	 * @memberof Collection
    	 * @param {Collection} collection The collection to collate data from.
    	 * @param {String=} keyName Optional name of the key to collate data to.
    	 * If none is provided the record CRUD is operated on the root collection
    	 * data.
    	 */
    	'object, string': function (collection, keyName) {
    		var self = this;

    		self.collateAdd(collection, function (packet) {
    			var obj1,
    				obj2;

    			switch (packet.type) {
    				case 'insert':
    					if (keyName) {
    						obj1 = {
    							$push: {}
    						};

    						obj1.$push[keyName] = self.decouple(packet.data.dataSet);
    						self.update({}, obj1);
    					} else {
    						self.insert(packet.data.dataSet);
    					}
    					break;

    				case 'update':
    					if (keyName) {
    						obj1 = {};
    						obj2 = {};

    						obj1[keyName] = packet.data.query;
    						obj2[keyName + '.$'] = packet.data.update;

    						self.update(obj1, obj2);
    					} else {
    						self.update(packet.data.query, packet.data.update);
    					}
    					break;

    				case 'remove':
    					if (keyName) {
    						obj1 = {
    							$pull: {}
    						};

    						obj1.$pull[keyName] = {};
    						obj1.$pull[keyName][self.primaryKey()] = packet.data.dataSet[0][collection.primaryKey()];

    						self.update({}, obj1);
    					} else {
    						self.remove(packet.data.dataSet);
    					}
    					break;

    				default:
    			}
    		});
    	},

    	/**
    	 * Adds a data source to collate data from and specifies a process
    	 * method that will handle the collation functionality (for custom
    	 * collation).
    	 * @func collateAdd
    	 * @memberof Collection
    	 * @param {Collection} collection The collection to collate data from.
    	 * @param {Function} process The process method.
    	 */
    	'object, function': function (collection, process) {
    		Iif (typeof collection === 'string') {
    			// The collection passed is a name, not a reference so get
    			// the reference from the name
    			collection = this._db.collection(collection, {
    				autoCreate: false,
    				throwError: false
    			});
    		}

    		Eif (collection) {
    			this._collate = this._collate || {};
    			this._collate[collection.name()] = new ReactorIO(collection, this, process);

    			return this;
    		} else {
    			throw('Cannot collate from a non-existent collection!');
    		}
    	}
    });

    Collection.prototype.collateRemove = function (collection) {
    	Iif (typeof collection === 'object') {
    		// We need to have the name of the collection to remove it
    		collection = collection.name();
    	}

    	Eif (collection) {
    		// Drop the reactor IO chain node
    		this._collate[collection].drop();

    		// Remove the collection data from the collate object
    		delete this._collate[collection];

    		return this;
    	} else {
    		throw('No collection name passed to collateRemove() or collection not found!');
    	}
    };

    Db.prototype.collection = new Overload('Db.prototype.collection', {
    	/**
    	 * Get a collection with no name (generates a random name). If the
    	 * collection does not already exist then one is created for that
    	 * name automatically.
    	 * @func collection
    	 * @memberof Db
    	 * @returns {Collection}
    	 */
    	'': function () {
    		return this.$main.call(this, {
    			name: this.objectId()
    		});
    	},

    	/**
    	 * Get a collection by name. If the collection does not already exist
    	 * then one is created for that name automatically.
    	 * @func collection
    	 * @memberof Db
    	 * @param {Object} data An options object or a collection instance.
    	 * @returns {Collection}
    	 */
    	'object': function (data) {
    		// Handle being passed an instance
    		Eif (data instanceof Collection) {
    			Eif (data.state() !== 'droppped') {
    				return data;
    			} else {
    				return this.$main.call(this, {
    					name: data.name()
    				});
    			}
    		}

    		return this.$main.call(this, data);
    	},

    	/**
    	 * Get a collection by name. If the collection does not already exist
    	 * then one is created for that name automatically.
    	 * @func collection
    	 * @memberof Db
    	 * @param {String} collectionName The name of the collection.
    	 * @returns {Collection}
    	 */
    	'string': function (collectionName) {
    		return this.$main.call(this, {
    			name: collectionName
    		});
    	},

    	/**
    	 * Get a collection by name. If the collection does not already exist
    	 * then one is created for that name automatically.
    	 * @func collection
    	 * @memberof Db
    	 * @param {String} collectionName The name of the collection.
    	 * @param {String} primaryKey Optional primary key to specify the primary key field on the collection
    	 * objects. Defaults to "_id".
    	 * @returns {Collection}
    	 */
    	'string, string': function (collectionName, primaryKey) {
    		return this.$main.call(this, {
    			name: collectionName,
    			primaryKey: primaryKey
    		});
    	},

    	/**
    	 * Get a collection by name. If the collection does not already exist
    	 * then one is created for that name automatically.
    	 * @func collection
    	 * @memberof Db
    	 * @param {String} collectionName The name of the collection.
    	 * @param {Object} options An options object.
    	 * @returns {Collection}
    	 */
    	'string, object': function (collectionName, options) {
    		options.name = collectionName;

    		return this.$main.call(this, options);
    	},

    	/**
    	 * Get a collection by name. If the collection does not already exist
    	 * then one is created for that name automatically.
    	 * @func collection
    	 * @memberof Db
    	 * @param {String} collectionName The name of the collection.
    	 * @param {String} primaryKey Optional primary key to specify the primary key field on the collection
    	 * objects. Defaults to "_id".
    	 * @param {Object} options An options object.
    	 * @returns {Collection}
    	 */
    	'string, string, object': function (collectionName, primaryKey, options) {
    		options.name = collectionName;
    		options.primaryKey = primaryKey;

    		return this.$main.call(this, options);
    	},

    	/**
    	 * The main handler method. This gets called by all the other variants and
    	 * handles the actual logic of the overloaded method.
    	 * @func collection
    	 * @memberof Db
    	 * @param {Object} options An options object.
    	 * @returns {*}
    	 */
    	'$main': function (options) {
    		var self = this,
    			name = options.name;

    		Eif (name) {
    			if (this._collection[name]) {
    				return this._collection[name];
    			} else {
    				Iif (options && options.autoCreate === false) {
    					if (options && options.throwError !== false) {
    						throw(this.logIdentifier() + ' Cannot get collection ' + name + ' because it does not exist and auto-create has been disabled!');
    					}

    					return undefined;
    				}

    				if (this.debug()) {
    					console.log(this.logIdentifier() + ' Creating collection ' + name);
    				}
    			}

    			this._collection[name] = this._collection[name] || new Collection(name, options).db(this);
    			this._collection[name].mongoEmulation(this.mongoEmulation());

    			if (options.primaryKey !== undefined) {
    				this._collection[name].primaryKey(options.primaryKey);
    			}

    			if (options.capped !== undefined) {
    				// Check we have a size
    				Eif (options.size !== undefined) {
    					this._collection[name].capped(options.capped);
    					this._collection[name].cappedSize(options.size);
    				} else {
    					throw(this.logIdentifier() + ' Cannot create a capped collection without specifying a size!');
    				}
    			}

    			// Listen for events on this collection so we can fire global events
    			// on the database in response to it
    			self._collection[name].on('change', function () {
    				self.emit('change', self._collection[name], 'collection', name);
    			});

    			self.emit('create', self._collection[name], 'collection', name);

    			return this._collection[name];
    		} else {
    			if (!options || (options && options.throwError !== false)) {
    				throw(this.logIdentifier() + ' Cannot get collection with undefined name!');
    			}
    		}
    	}
    });

    /**
     * Determine if a collection with the passed name already exists.
     * @memberof Db
     * @param {String} viewName The name of the collection to check for.
     * @returns {boolean}
     */
    Db.prototype.collectionExists = function (viewName) {
    	return Boolean(this._collection[viewName]);
    };

    /**
     * Returns an array of collections the DB currently has.
     * @memberof Db
     * @param {String|RegExp=} search The optional search string or regular expression to use
     * to match collection names against.
     * @returns {Array} An array of objects containing details of each collection
     * the database is currently managing.
     */
    Db.prototype.collections = function (search) {
    	var arr = [],
    		collections = this._collection,
    		collection,
    		i;

    	Iif (search) {
    		if (!(search instanceof RegExp)) {
    			// Turn the search into a regular expression
    			search = new RegExp(search);
    		}
    	}

    	for (i in collections) {
    		Eif (collections.hasOwnProperty(i)) {
    			collection = collections[i];

    			Iif (search) {
    				if (search.exec(i)) {
    					arr.push({
    						name: i,
    						count: collection.count(),
    						linked: collection.isLinked !== undefined ? collection.isLinked() : false
    					});
    				}
    			} else {
    				arr.push({
    					name: i,
    					count: collection.count(),
    					linked: collection.isLinked !== undefined ? collection.isLinked() : false
    				});
    			}
    		}
    	}

    	arr.sort(function (a, b) {
    		return a.name.localeCompare(b.name);
    	});

    	return arr;
    };

    Shared.finishModule('Collection');
    module.exports = Collection;
    },{"./Index2d":15,"./IndexBinaryTree":16,"./IndexHashMap":17,"./KeyValueStore":18,"./Metrics":19,"./Overload":32,"./Path":34,"./ReactorIO":38,"./Shared":40}],8:[function(_dereq_,module,exports){
    "use strict";

    // Import external names locally
    var Shared,
    	Db,
    	DbInit,
    	Collection;

    Shared = _dereq_('./Shared');

    /**
     * Creates a new collection group. Collection groups allow single operations to be
     * propagated to multiple collections at once. CRUD operations against a collection
     * group are in fed to the group's collections. Useful when separating out slightly
     * different data into multiple collections but querying as one collection.
     * @constructor
     */
    var CollectionGroup = function () {
    	this.init.apply(this, arguments);
    };

    CollectionGroup.prototype.init = function (name) {
    	var self = this;

    	self._name = name;
    	self._data = new Collection('__FDB__cg_data_' + self._name);
    	self._collections = [];
    	self._view = [];
    };

    Shared.addModule('CollectionGroup', CollectionGroup);
    Shared.mixin(CollectionGroup.prototype, 'Mixin.Common');
    Shared.mixin(CollectionGroup.prototype, 'Mixin.ChainReactor');
    Shared.mixin(CollectionGroup.prototype, 'Mixin.Constants');
    Shared.mixin(CollectionGroup.prototype, 'Mixin.Triggers');
    Shared.mixin(CollectionGroup.prototype, 'Mixin.Tags');
    Shared.mixin(CollectionGroup.prototype, 'Mixin.Events');

    Collection = _dereq_('./Collection');
    Db = Shared.modules.Db;
    DbInit = Shared.modules.Db.prototype.init;

    CollectionGroup.prototype.on = function () {
    	this._data.on.apply(this._data, arguments);
    };

    CollectionGroup.prototype.off = function () {
    	this._data.off.apply(this._data, arguments);
    };

    CollectionGroup.prototype.emit = function () {
    	this._data.emit.apply(this._data, arguments);
    };

    /**
     * Gets / sets the primary key for this collection group.
     * @param {String=} keyName The name of the primary key.
     * @returns {*}
     */
    CollectionGroup.prototype.primaryKey = function (keyName) {
    	if (keyName !== undefined) {
    		this._primaryKey = keyName;
    		return this;
    	}

    	return this._primaryKey;
    };

    /**
     * Gets / sets the current state.
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(CollectionGroup.prototype, 'state');

    /**
     * Gets / sets the db instance the collection group belongs to.
     * @param {Db=} db The db instance.
     * @returns {*}
     */
    Shared.synthesize(CollectionGroup.prototype, 'db');

    /**
     * Gets / sets the instance name.
     * @param {String=} name The new name to set.
     * @returns {*}
     */
    Shared.synthesize(CollectionGroup.prototype, 'name');

    CollectionGroup.prototype.addCollection = function (collection) {
    	Eif (collection) {
    		Eif (this._collections.indexOf(collection) === -1) {
    			//var self = this;

    			// Check for compatible primary keys
    			if (this._collections.length) {
    				Iif (this._primaryKey !== collection.primaryKey()) {
    					throw(this.logIdentifier() + ' All collections in a collection group must have the same primary key!');
    				}
    			} else {
    				// Set the primary key to the first collection added
    				this.primaryKey(collection.primaryKey());
    			}

    			// Add the collection
    			this._collections.push(collection);
    			collection._groups = collection._groups || [];
    			collection._groups.push(this);
    			collection.chain(this);

    			// Hook the collection's drop event to destroy group data
    			collection.on('drop', function () {
    				// Remove collection from any group associations
    				Eif (collection._groups && collection._groups.length) {
    					var groupArr = [],
    						i;

    					// Copy the group array because if we call removeCollection on a group
    					// it will alter the groups array of this collection mid-loop!
    					for (i = 0; i < collection._groups.length; i++) {
    						groupArr.push(collection._groups[i]);
    					}

    					// Loop any groups we are part of and remove ourselves from them
    					for (i = 0; i < groupArr.length; i++) {
    						collection._groups[i].removeCollection(collection);
    					}
    				}

    				delete collection._groups;
    			});

    			// Add collection's data
    			this._data.insert(collection.find());
    		}
    	}

    	return this;
    };

    CollectionGroup.prototype.removeCollection = function (collection) {
    	Eif (collection) {
    		var collectionIndex = this._collections.indexOf(collection),
    			groupIndex;

    		Eif (collectionIndex !== -1) {
    			collection.unChain(this);
    			this._collections.splice(collectionIndex, 1);

    			collection._groups = collection._groups || [];
    			groupIndex = collection._groups.indexOf(this);

    			Eif (groupIndex !== -1) {
    				collection._groups.splice(groupIndex, 1);
    			}

    			collection.off('drop');
    		}

    		if (this._collections.length === 0) {
    			// Wipe the primary key
    			delete this._primaryKey;
    		}
    	}

    	return this;
    };

    CollectionGroup.prototype._chainHandler = function (chainPacket) {
    	//sender = chainPacket.sender;
    	switch (chainPacket.type) {
    		case 'setData':
    			// Decouple the data to ensure we are working with our own copy
    			chainPacket.data.dataSet = this.decouple(chainPacket.data.dataSet);

    			// Remove old data
    			this._data.remove(chainPacket.data.oldData);

    			// Add new data
    			this._data.insert(chainPacket.data.dataSet);
    			break;

    		case 'insert':
    			// Decouple the data to ensure we are working with our own copy
    			chainPacket.data.dataSet = this.decouple(chainPacket.data.dataSet);

    			// Add new data
    			this._data.insert(chainPacket.data.dataSet);
    			break;

    		case 'update':
    			// Update data
    			this._data.update(chainPacket.data.query, chainPacket.data.update, chainPacket.options);
    			break;

    		case 'remove':
    			this._data.remove(chainPacket.data.query, chainPacket.options);
    			break;

    		default:
    			break;
    	}
    };

    CollectionGroup.prototype.insert = function () {
    	this._collectionsRun('insert', arguments);
    };

    CollectionGroup.prototype.update = function () {
    	this._collectionsRun('update', arguments);
    };

    CollectionGroup.prototype.updateById = function () {
    	this._collectionsRun('updateById', arguments);
    };

    CollectionGroup.prototype.remove = function () {
    	this._collectionsRun('remove', arguments);
    };

    CollectionGroup.prototype._collectionsRun = function (type, args) {
    	for (var i = 0; i < this._collections.length; i++) {
    		this._collections[i][type].apply(this._collections[i], args);
    	}
    };

    CollectionGroup.prototype.find = function (query, options) {
    	return this._data.find(query, options);
    };

    /**
     * Helper method that removes a document that matches the given id.
     * @param {String} id The id of the document to remove.
     */
    CollectionGroup.prototype.removeById = function (id) {
    	// Loop the collections in this group and apply the remove
    	for (var i = 0; i < this._collections.length; i++) {
    		this._collections[i].removeById(id);
    	}
    };

    /**
     * Uses the passed query to generate a new collection with results
     * matching the query parameters.
     *
     * @param query
     * @param options
     * @returns {*}
     */
    CollectionGroup.prototype.subset = function (query, options) {
    	var result = this.find(query, options);

    	return new Collection()
    		.subsetOf(this)
    		.primaryKey(this._primaryKey)
    		.setData(result);
    };

    /**
     * Drops a collection group from the database.
     * @returns {boolean} True on success, false on failure.
     */
    CollectionGroup.prototype.drop = function (callback) {
    	if (!this.isDropped()) {
    		var i,
    			collArr,
    			viewArr;

    		if (this._debug) {
    			console.log(this.logIdentifier() + ' Dropping');
    		}

    		this._state = 'dropped';

    		if (this._collections && this._collections.length) {
    			collArr = [].concat(this._collections);

    			for (i = 0; i < collArr.length; i++) {
    				this.removeCollection(collArr[i]);
    			}
    		}

    		if (this._view && this._view.length) {
    			viewArr = [].concat(this._view);

    			for (i = 0; i < viewArr.length; i++) {
    				this._removeView(viewArr[i]);
    			}
    		}

    		this.emit('drop', this);

    		delete this._listeners;

    		if (callback) { callback(false, true); }
    	}

    	return true;
    };

    // Extend DB to include collection groups
    Db.prototype.init = function () {
    	this._collectionGroup = {};
    	DbInit.apply(this, arguments);
    };

    /**
     * Creates a new collectionGroup instance or returns an existing
     * instance if one already exists with the passed name.
     * @func collectionGroup
     * @memberOf Db
     * @param {String} name The name of the instance.
     * @returns {*}
     */
    Db.prototype.collectionGroup = function (name) {
    	var self = this;

    	Eif (name) {
    		// Handle being passed an instance
    		Iif (name instanceof CollectionGroup) {
    			return name;
    		}

    		Iif (this._collectionGroup && this._collectionGroup[name]) {
    			return this._collectionGroup[name];
    		}

    		this._collectionGroup[name] = new CollectionGroup(name).db(this);

    		self.emit('create', self._collectionGroup[name], 'collectionGroup', name);

    		return this._collectionGroup[name];
    	} else {
    		// Return an object of collection data
    		return this._collectionGroup;
    	}
    };

    /**
     * Returns an array of collection groups the DB currently has.
     * @returns {Array} An array of objects containing details of each collection group
     * the database is currently managing.
     */
    Db.prototype.collectionGroups = function () {
    	var arr = [],
    		i;

    	for (i in this._collectionGroup) {
    		if (this._collectionGroup.hasOwnProperty(i)) {
    			arr.push({
    				name: i
    			});
    		}
    	}

    	return arr;
    };

    module.exports = CollectionGroup;
    },{"./Collection":7,"./Shared":40}],9:[function(_dereq_,module,exports){
    /*
     License

     Copyright (c) 2015 Irrelon Software Limited
     http://www.irrelon.com
     http://www.forerunnerdb.com

     Please visit the license page to see latest license information:
     http://www.forerunnerdb.com/licensing.html
     */
    "use strict";

    var Shared,
    	Db,
    	Metrics,
    	Overload,
    	_instances = [];

    Shared = _dereq_('./Shared');
    Overload = _dereq_('./Overload');

    /**
     * Creates a new ForerunnerDB instance. Core instances handle the lifecycle of
     * multiple database instances.
     * @constructor
     */
    var Core = function (val) {
    	this.init.apply(this, arguments);
    };

    Core.prototype.init = function (name) {
    	this._db = {};
    	this._debug = {};
    	this._name = name || 'ForerunnerDB';

    	_instances.push(this);
    };

    /**
     * Returns the number of instantiated ForerunnerDB objects.
     * @returns {Number} The number of instantiated instances.
     */
    Core.prototype.instantiatedCount = function () {
    	return _instances.length;
    };

    /**
     * Get all instances as an array or a single ForerunnerDB instance
     * by it's array index.
     * @param {Number=} index Optional index of instance to get.
     * @returns {Array|Object} Array of instances or a single instance.
     */
    Core.prototype.instances = function (index) {
    	if (index !== undefined) {
    		return _instances[index];
    	}

    	return _instances;
    };

    /**
     * Get all instances as an array of instance names or a single ForerunnerDB
     * instance by it's name.
     * @param {String=} name Optional name of instance to get.
     * @returns {Array|Object} Array of instance names or a single instance.
     */
    Core.prototype.namedInstances = function (name) {
    	var i,
    		instArr;

    	if (name !== undefined) {
    		for (i = 0; i < _instances.length; i++) {
    			if (_instances[i].name === name) {
    				return _instances[i];
    			}
    		}

    		return undefined;
    	}

    	instArr = [];

    	for (i = 0; i < _instances.length; i++) {
    		instArr.push(_instances[i].name);
    	}

    	return instArr;
    };

    Core.prototype.moduleLoaded = new Overload({
    	/**
    	 * Checks if a module has been loaded into the database.
    	 * @func moduleLoaded
    	 * @memberof Core
    	 * @param {String} moduleName The name of the module to check for.
    	 * @returns {Boolean} True if the module is loaded, false if not.
    	 */
    	'string': function (moduleName) {
    		if (moduleName !== undefined) {
    			moduleName = moduleName.replace(/ /g, '');

    			var modules = moduleName.split(','),
    				index;

    			for (index = 0; index < modules.length; index++) {
    				if (!Shared.modules[modules[index]]) {
    					return false;
    				}
    			}

    			return true;
    		}

    		return false;
    	},

    	/**
    	 * Checks if a module is loaded and if so calls the passed
    	 * callback method.
    	 * @func moduleLoaded
    	 * @memberof Core
    	 * @param {String} moduleName The name of the module to check for.
    	 * @param {Function} callback The callback method to call if module is loaded.
    	 */
    	'string, function': function (moduleName, callback) {
    		Eif (moduleName !== undefined) {
    			moduleName = moduleName.replace(/ /g, '');

    			var modules = moduleName.split(','),
    				index;

    			for (index = 0; index < modules.length; index++) {
    				if (!Shared.modules[modules[index]]) {
    					return false;
    				}
    			}

    			Eif (callback) { callback(); }
    		}
    	},

    	/**
    	 * Checks if an array of named modules are loaded and if so
    	 * calls the passed callback method.
    	 * @func moduleLoaded
    	 * @memberof Core
    	 * @param {Array} moduleName The array of module names to check for.
    	 * @param {Function} callback The callback method to call if modules are loaded.
    	 */
    	'array, function': function (moduleNameArr, callback) {
    		var moduleName,
    			i;

    		for (i = 0; i < moduleNameArr.length; i++) {
    			moduleName = moduleNameArr[i];

    			Eif (moduleName !== undefined) {
    				moduleName = moduleName.replace(/ /g, '');

    				var modules = moduleName.split(','),
    					index;

    				for (index = 0; index < modules.length; index++) {
    					Iif (!Shared.modules[modules[index]]) {
    						return false;
    					}
    				}
    			}
    		}

    		Eif (callback) { callback(); }
    	},

    	/**
    	 * Checks if a module is loaded and if so calls the passed
    	 * success method, otherwise calls the failure method.
    	 * @func moduleLoaded
    	 * @memberof Core
    	 * @param {String} moduleName The name of the module to check for.
    	 * @param {Function} success The callback method to call if module is loaded.
    	 * @param {Function} failure The callback method to call if module not loaded.
    	 */
    	'string, function, function': function (moduleName, success, failure) {
    		if (moduleName !== undefined) {
    			moduleName = moduleName.replace(/ /g, '');

    			var modules = moduleName.split(','),
    				index;

    			for (index = 0; index < modules.length; index++) {
    				if (!Shared.modules[modules[index]]) {
    					failure();
    					return false;
    				}
    			}

    			success();
    		}
    	}
    });

    /**
     * Checks version against the string passed and if it matches (or partially matches)
     * then the callback is called.
     * @param {String} val The version to check against.
     * @param {Function} callback The callback to call if match is true.
     * @returns {Boolean}
     */
    Core.prototype.version = function (val, callback) {
    	Eif (val !== undefined) {
    		Iif (Shared.version.indexOf(val) === 0) {
    			if (callback) { callback(); }
    			return true;
    		}

    		return false;
    	}

    	return Shared.version;
    };

    // Expose moduleLoaded() method to non-instantiated object ForerunnerDB
    Core.moduleLoaded = Core.prototype.moduleLoaded;

    // Expose version() method to non-instantiated object ForerunnerDB
    Core.version = Core.prototype.version;

    // Expose instances() method to non-instantiated object ForerunnerDB
    Core.instances = Core.prototype.instances;

    // Expose instantiatedCount() method to non-instantiated object ForerunnerDB
    Core.instantiatedCount = Core.prototype.instantiatedCount;

    // Provide public access to the Shared object
    Core.shared = Shared;
    Core.prototype.shared = Shared;

    Shared.addModule('Core', Core);
    Shared.mixin(Core.prototype, 'Mixin.Common');
    Shared.mixin(Core.prototype, 'Mixin.Constants');

    Db = _dereq_('./Db.js');
    Metrics = _dereq_('./Metrics.js');

    /**
     * Gets / sets the name of the instance. This is primarily used for
     * name-spacing persistent storage.
     * @param {String=} val The name of the instance to set.
     * @returns {*}
     */
    Shared.synthesize(Core.prototype, 'name');

    /**
     * Gets / sets mongodb emulation mode.
     * @param {Boolean=} val True to enable, false to disable.
     * @returns {*}
     */
    Shared.synthesize(Core.prototype, 'mongoEmulation');

    // Set a flag to determine environment
    Core.prototype._isServer = false;

    /**
     * Checks if the database is running on a client (browser) or
     * a server (node.js).
     * @returns {Boolean} Returns true if running on a browser.
     */
    Core.prototype.isClient = function () {
    	return !this._isServer;
    };

    /**
     * Checks if the database is running on a client (browser) or
     * a server (node.js).
     * @returns {Boolean} Returns true if running on a server.
     */
    Core.prototype.isServer = function () {
    	return this._isServer;
    };

    /**
     * Added to provide an error message for users who have not seen
     * the new instantiation breaking change warning and try to get
     * a collection directly from the core instance.
     */
    Core.prototype.collection = function () {
    	throw("ForerunnerDB's instantiation has changed since version 1.3.36 to support multiple database instances. Please see the readme.md file for the minor change you have to make to get your project back up and running, or see the issue related to this change at https://github.com/Irrelon/ForerunnerDB/issues/44");
    };

    module.exports = Core;
    },{"./Db.js":10,"./Metrics.js":19,"./Overload":32,"./Shared":40}],10:[function(_dereq_,module,exports){
    "use strict";

    var Shared,
    	Core,
    	Collection,
    	Metrics,
    	Checksum,
    	Overload;

    Shared = _dereq_('./Shared');
    Overload = _dereq_('./Overload');

    /**
     * Creates a new ForerunnerDB database instance.
     * @constructor
     */
    var Db = function (name, core) {
    	this.init.apply(this, arguments);
    };

    Db.prototype.init = function (name, core) {
    	this.core(core);
    	this._primaryKey = '_id';
    	this._name = name;
    	this._collection = {};
    	this._debug = {};
    };

    Shared.addModule('Db', Db);

    Db.prototype.moduleLoaded = new Overload({
    	/**
    	 * Checks if a module has been loaded into the database.
    	 * @func moduleLoaded
    	 * @memberof Db
    	 * @param {String} moduleName The name of the module to check for.
    	 * @returns {Boolean} True if the module is loaded, false if not.
    	 */
    	'string': function (moduleName) {
    		if (moduleName !== undefined) {
    			moduleName = moduleName.replace(/ /g, '');

    			var modules = moduleName.split(','),
    				index;

    			for (index = 0; index < modules.length; index++) {
    				if (!Shared.modules[modules[index]]) {
    					return false;
    				}
    			}

    			return true;
    		}

    		return false;
    	},

    	/**
    	 * Checks if a module is loaded and if so calls the passed
    	 * callback method.
    	 * @func moduleLoaded
    	 * @memberof Db
    	 * @param {String} moduleName The name of the module to check for.
    	 * @param {Function} callback The callback method to call if module is loaded.
    	 */
    	'string, function': function (moduleName, callback) {
    		if (moduleName !== undefined) {
    			moduleName = moduleName.replace(/ /g, '');

    			var modules = moduleName.split(','),
    				index;

    			for (index = 0; index < modules.length; index++) {
    				if (!Shared.modules[modules[index]]) {
    					return false;
    				}
    			}

    			if (callback) { callback(); }
    		}
    	},

    	/**
    	 * Checks if a module is loaded and if so calls the passed
    	 * success method, otherwise calls the failure method.
    	 * @func moduleLoaded
    	 * @memberof Db
    	 * @param {String} moduleName The name of the module to check for.
    	 * @param {Function} success The callback method to call if module is loaded.
    	 * @param {Function} failure The callback method to call if module not loaded.
    	 */
    	'string, function, function': function (moduleName, success, failure) {
    		if (moduleName !== undefined) {
    			moduleName = moduleName.replace(/ /g, '');

    			var modules = moduleName.split(','),
    				index;

    			for (index = 0; index < modules.length; index++) {
    				if (!Shared.modules[modules[index]]) {
    					failure();
    					return false;
    				}
    			}

    			success();
    		}
    	}
    });

    /**
     * Checks version against the string passed and if it matches (or partially matches)
     * then the callback is called.
     * @param {String} val The version to check against.
     * @param {Function} callback The callback to call if match is true.
     * @returns {Boolean}
     */
    Db.prototype.version = function (val, callback) {
    	if (val !== undefined) {
    		if (Shared.version.indexOf(val) === 0) {
    			if (callback) { callback(); }
    			return true;
    		}

    		return false;
    	}

    	return Shared.version;
    };

    // Expose moduleLoaded method to non-instantiated object ForerunnerDB
    Db.moduleLoaded = Db.prototype.moduleLoaded;

    // Expose version method to non-instantiated object ForerunnerDB
    Db.version = Db.prototype.version;

    // Provide public access to the Shared object
    Db.shared = Shared;
    Db.prototype.shared = Shared;

    Shared.addModule('Db', Db);
    Shared.mixin(Db.prototype, 'Mixin.Common');
    Shared.mixin(Db.prototype, 'Mixin.ChainReactor');
    Shared.mixin(Db.prototype, 'Mixin.Constants');
    Shared.mixin(Db.prototype, 'Mixin.Tags');

    Core = Shared.modules.Core;
    Collection = _dereq_('./Collection.js');
    Metrics = _dereq_('./Metrics.js');
    Checksum = _dereq_('./Checksum.js');

    Db.prototype._isServer = false;

    /**
     * Gets / sets the core object this database belongs to.
     */
    Shared.synthesize(Db.prototype, 'core');

    /**
     * Gets / sets the default primary key for new collections.
     * @param {String=} val The name of the primary key to set.
     * @returns {*}
     */
    Shared.synthesize(Db.prototype, 'primaryKey');

    /**
     * Gets / sets the current state.
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(Db.prototype, 'state');

    /**
     * Gets / sets the name of the database.
     * @param {String=} val The name of the database to set.
     * @returns {*}
     */
    Shared.synthesize(Db.prototype, 'name');

    /**
     * Gets / sets mongodb emulation mode.
     * @param {Boolean=} val True to enable, false to disable.
     * @returns {*}
     */
    Shared.synthesize(Db.prototype, 'mongoEmulation');

    /**
     * Returns true if ForerunnerDB is running on a client browser.
     * @returns {boolean}
     */
    Db.prototype.isClient = function () {
    	return !this._isServer;
    };

    /**
     * Returns true if ForerunnerDB is running on a server.
     * @returns {boolean}
     */
    Db.prototype.isServer = function () {
    	return this._isServer;
    };

    /**
     * Returns a checksum of a string.
     * @param {String} string The string to checksum.
     * @return {String} The checksum generated.
     */
    Db.prototype.Checksum = Checksum;

    /**
     * Checks if the database is running on a client (browser) or
     * a server (node.js).
     * @returns {Boolean} Returns true if running on a browser.
     */
    Db.prototype.isClient = function () {
    	return !this._isServer;
    };

    /**
     * Checks if the database is running on a client (browser) or
     * a server (node.js).
     * @returns {Boolean} Returns true if running on a server.
     */
    Db.prototype.isServer = function () {
    	return this._isServer;
    };

    /**
     * Converts a normal javascript array of objects into a DB collection.
     * @param {Array} arr An array of objects.
     * @returns {Collection} A new collection instance with the data set to the
     * array passed.
     */
    Db.prototype.arrayToCollection = function (arr) {
    	return new Collection().setData(arr);
    };

    /**
     * Registers an event listener against an event name.
     * @param {String} event The name of the event to listen for.
     * @param {Function} listener The listener method to call when
     * the event is fired.
     * @returns {*}
     */
    Db.prototype.on = function(event, listener) {
    	this._listeners = this._listeners || {};
    	this._listeners[event] = this._listeners[event] || [];
    	this._listeners[event].push(listener);

    	return this;
    };

    /**
     * De-registers an event listener from an event name.
     * @param {String} event The name of the event to stop listening for.
     * @param {Function} listener The listener method passed to on() when
     * registering the event listener.
     * @returns {*}
     */
    Db.prototype.off = function(event, listener) {
    	if (event in this._listeners) {
    		var arr = this._listeners[event],
    			index = arr.indexOf(listener);

    		if (index > -1) {
    			arr.splice(index, 1);
    		}
    	}

    	return this;
    };

    /**
     * Emits an event by name with the given data.
     * @param {String} event The name of the event to emit.
     * @param {*=} data The data to emit with the event.
     * @returns {*}
     */
    Db.prototype.emit = function(event, data) {
    	this._listeners = this._listeners || {};

    	Iif (event in this._listeners) {
    		var arr = this._listeners[event],
    			arrCount = arr.length,
    			arrIndex;

    		for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    			arr[arrIndex].apply(this, Array.prototype.slice.call(arguments, 1));
    		}
    	}

    	return this;
    };

    Db.prototype.peek = function (search) {
    	var i,
    			coll,
    			arr = [],
    			typeOfSearch = typeof search;

    	// Loop collections
    	for (i in this._collection) {
    		if (this._collection.hasOwnProperty(i)) {
    			coll = this._collection[i];

    			if (typeOfSearch === 'string') {
    				arr = arr.concat(coll.peek(search));
    			} else {
    				arr = arr.concat(coll.find(search));
    			}
    		}
    	}

    	return arr;
    };

    /**
     * Find all documents across all collections in the database that match the passed
     * string or search object.
     * @param search String or search object.
     * @returns {Array}
     */
    Db.prototype.peek = function (search) {
    	var i,
    		coll,
    		arr = [],
    		typeOfSearch = typeof search;

    	// Loop collections
    	for (i in this._collection) {
    		Eif (this._collection.hasOwnProperty(i)) {
    			coll = this._collection[i];

    			Eif (typeOfSearch === 'string') {
    				arr = arr.concat(coll.peek(search));
    			} else {
    				arr = arr.concat(coll.find(search));
    			}
    		}
    	}

    	return arr;
    };

    /**
     * Find all documents across all collections in the database that match the passed
     * string or search object and return them in an object where each key is the name
     * of the collection that the document was matched in.
     * @param search String or search object.
     * @returns {object}
     */
    Db.prototype.peekCat = function (search) {
    	var i,
    		coll,
    		cat = {},
    		arr,
    		typeOfSearch = typeof search;

    	// Loop collections
    	for (i in this._collection) {
    		Eif (this._collection.hasOwnProperty(i)) {
    			coll = this._collection[i];

    			Eif (typeOfSearch === 'string') {
    				arr = coll.peek(search);

    				Eif (arr && arr.length) {
    					cat[coll.name()] = arr;
    				}
    			} else {
    				arr = coll.find(search);

    				if (arr && arr.length) {
    					cat[coll.name()] = arr;
    				}
    			}
    		}
    	}

    	return cat;
    };

    Db.prototype.drop = new Overload({
    	/**
    	 * Drops the database.
    	 * @func drop
    	 * @memberof Db
    	 */
    	'': function () {
    		if (!this.isDropped()) {
    			var arr = this.collections(),
    				arrCount = arr.length,
    				arrIndex;

    			this._state = 'dropped';

    			for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    				this.collection(arr[arrIndex].name).drop();
    				delete this._collection[arr[arrIndex].name];
    			}

    			this.emit('drop', this);

    			delete this._listeners;
    			delete this._core._db[this._name];
    		}

    		return true;
    	},

    	/**
    	 * Drops the database with optional callback method.
    	 * @func drop
    	 * @memberof Db
    	 * @param {Function} callback Optional callback method.
    	 */
    	'function': function (callback) {
    		if (!this.isDropped()) {
    			var arr = this.collections(),
    				arrCount = arr.length,
    				arrIndex,
    				finishCount = 0,
    				afterDrop = function () {
    					finishCount++;

    					if (finishCount === arrCount) {
    						if (callback) { callback();	}
    					}
    				};

    			this._state = 'dropped';

    			for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    				this.collection(arr[arrIndex].name).drop(afterDrop);

    				delete this._collection[arr[arrIndex].name];
    			}

    			this.emit('drop', this);

    			delete this._listeners;
    			delete this._core._db[this._name];
    		}

    		return true;
    	},

    	/**
    	 * Drops the database with optional persistent storage drop. Persistent
    	 * storage is dropped by default if no preference is provided.
    	 * @func drop
    	 * @memberof Db
    	 * @param {Boolean} removePersist Drop persistent storage for this database.
    	 */
    	'boolean': function (removePersist) {
    		Eif (!this.isDropped()) {
    			var arr = this.collections(),
    				arrCount = arr.length,
    				arrIndex;

    			this._state = 'dropped';

    			for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    				this.collection(arr[arrIndex].name).drop(removePersist);
    				delete this._collection[arr[arrIndex].name];
    			}

    			this.emit('drop', this);

    			delete this._listeners;
    			delete this._core._db[this._name];
    		}

    		return true;
    	},

    	/**
    	 * Drops the database and optionally controls dropping persistent storage
    	 * and callback method.
    	 * @func drop
    	 * @memberof Db
    	 * @param {Boolean} removePersist Drop persistent storage for this database.
    	 * @param {Function} callback Optional callback method.
    	 */
    	'boolean, function': function (removePersist, callback) {
    		if (!this.isDropped()) {
    			var arr = this.collections(),
    				arrCount = arr.length,
    				arrIndex,
    				finishCount = 0,
    				afterDrop = function () {
    					finishCount++;

    					if (finishCount === arrCount) {
    						if (callback) { callback();	}
    					}
    				};

    			this._state = 'dropped';

    			for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    				this.collection(arr[arrIndex].name).drop(removePersist, afterDrop);
    				delete this._collection[arr[arrIndex].name];
    			}

    			this.emit('drop', this);

    			delete this._listeners;
    			delete this._core._db[this._name];
    		}

    		return true;
    	}
    });

    /**
     * Gets a database instance by name.
     * @memberof Core
     * @param {String=} name Optional name of the database. If none is provided
     * a random name is assigned.
     * @returns {Db}
     */
    Core.prototype.db = function (name) {
    	// Handle being passed an instance
    	Iif (name instanceof Db) {
    		return name;
    	}

    	Iif (!name) {
    		name = this.objectId();
    	}

    	this._db[name] = this._db[name] || new Db(name, this);

    	this._db[name].mongoEmulation(this.mongoEmulation());

    	return this._db[name];
    };

    /**
     * Returns an array of databases that ForerunnerDB currently has.
     * @memberof Core
     * @param {String|RegExp=} search The optional search string or regular expression to use
     * to match collection names against.
     * @returns {Array} An array of objects containing details of each database
     * that ForerunnerDB is currently managing and it's child entities.
     */
    Core.prototype.databases = function (search) {
    	var arr = [],
    		tmpObj,
    		addDb,
    		i;

    	if (search) {
    		if (!(search instanceof RegExp)) {
    			// Turn the search into a regular expression
    			search = new RegExp(search);
    		}
    	}

    	for (i in this._db) {
    		if (this._db.hasOwnProperty(i)) {
    			addDb = true;

    			if (search) {
    				if (!search.exec(i)) {
    					addDb = false;
    				}
    			}

    			if (addDb) {
    				tmpObj = {
    					name: i,
    					children: []
    				};

    				if (this.shared.moduleExists('Collection')) {
    					tmpObj.children.push({
    						module: 'collection',
    						moduleName: 'Collections',
    						count: this._db[i].collections().length
    					});
    				}

    				if (this.shared.moduleExists('CollectionGroup')) {
    					tmpObj.children.push({
    						module: 'collectionGroup',
    						moduleName: 'Collection Groups',
    						count: this._db[i].collectionGroups().length
    					});
    				}

    				if (this.shared.moduleExists('Document')) {
    					tmpObj.children.push({
    						module: 'document',
    						moduleName: 'Documents',
    						count: this._db[i].documents().length
    					});
    				}

    				if (this.shared.moduleExists('Grid')) {
    					tmpObj.children.push({
    						module: 'grid',
    						moduleName: 'Grids',
    						count: this._db[i].grids().length
    					});
    				}

    				if (this.shared.moduleExists('Overview')) {
    					tmpObj.children.push({
    						module: 'overview',
    						moduleName: 'Overviews',
    						count: this._db[i].overviews().length
    					});
    				}

    				if (this.shared.moduleExists('View')) {
    					tmpObj.children.push({
    						module: 'view',
    						moduleName: 'Views',
    						count: this._db[i].views().length
    					});
    				}

    				arr.push(tmpObj);
    			}
    		}
    	}

    	arr.sort(function (a, b) {
    		return a.name.localeCompare(b.name);
    	});

    	return arr;
    };

    Shared.finishModule('Db');
    module.exports = Db;
    },{"./Checksum.js":6,"./Collection.js":7,"./Metrics.js":19,"./Overload":32,"./Shared":40}],11:[function(_dereq_,module,exports){
    "use strict";
    // TODO: Remove the _update* methods because we are already mixing them
    // TODO: in now via Mixin.Updating and update autobind to extend the _update*
    // TODO: methods like we already do with collection
    var Shared,
    	Collection,
    	Db;

    Shared = _dereq_('./Shared');

    /**
     * Creates a new Document instance. Documents allow you to create individual
     * objects that can have standard ForerunnerDB CRUD operations run against
     * them, as well as data-binding if the AutoBind module is included in your
     * project.
     * @name Document
     * @class Document
     * @constructor
     */
    var FdbDocument = function () {
    	this.init.apply(this, arguments);
    };

    FdbDocument.prototype.init = function (name) {
    	this._name = name;
    	this._data = {};
    };

    Shared.addModule('Document', FdbDocument);
    Shared.mixin(FdbDocument.prototype, 'Mixin.Common');
    Shared.mixin(FdbDocument.prototype, 'Mixin.Events');
    Shared.mixin(FdbDocument.prototype, 'Mixin.ChainReactor');
    Shared.mixin(FdbDocument.prototype, 'Mixin.Constants');
    Shared.mixin(FdbDocument.prototype, 'Mixin.Triggers');
    Shared.mixin(FdbDocument.prototype, 'Mixin.Matching');
    Shared.mixin(FdbDocument.prototype, 'Mixin.Updating');
    Shared.mixin(FdbDocument.prototype, 'Mixin.Tags');

    Collection = _dereq_('./Collection');
    Db = Shared.modules.Db;

    /**
     * Gets / sets the current state.
     * @func state
     * @memberof Document
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(FdbDocument.prototype, 'state');

    /**
     * Gets / sets the db instance this class instance belongs to.
     * @func db
     * @memberof Document
     * @param {Db=} db The db instance.
     * @returns {*}
     */
    Shared.synthesize(FdbDocument.prototype, 'db');

    /**
     * Gets / sets the document name.
     * @func name
     * @memberof Document
     * @param {String=} val The name to assign
     * @returns {*}
     */
    Shared.synthesize(FdbDocument.prototype, 'name');

    /**
     * Sets the data for the document.
     * @func setData
     * @memberof Document
     * @param data
     * @param options
     * @returns {Document}
     */
    FdbDocument.prototype.setData = function (data, options) {
    	var i,
    		$unset;

    	Eif (data) {
    		options = options || {
    			$decouple: true
    		};

    		if (options && options.$decouple === true) {
    			data = this.decouple(data);
    		}

    		if (this._linked) {
    			$unset = {};

    			// Remove keys that don't exist in the new data from the current object
    			for (i in this._data) {
    				Eif (i.substr(0, 6) !== 'jQuery' && this._data.hasOwnProperty(i)) {
    					// Check if existing data has key
    					if (data[i] === undefined) {
    						// Add property name to those to unset
    						$unset[i] = 1;
    					}
    				}
    			}

    			data.$unset = $unset;

    			// Now update the object with new data
    			this.updateObject(this._data, data, {});
    		} else {
    			// Straight data assignment
    			this._data = data;
    		}

    		this.deferEmit('change', {type: 'setData', data: this.decouple(this._data)});
    	}

    	return this;
    };

    /**
     * Gets the document's data returned as a single object.
     * @func find
     * @memberof Document
     * @param {Object} query The query object - currently unused, just
     * provide a blank object e.g. {}
     * @param {Object=} options An options object.
     * @returns {Object} The document's data object.
     */
    FdbDocument.prototype.find = function (query, options) {
    	var result;

    	if (options && options.$decouple === false) {
    		result = this._data;
    	} else {
    		result = this.decouple(this._data);
    	}

    	return result;
    };

    /**
     * Modifies the document. This will update the document with the data held in 'update'.
     * @func update
     * @memberof Document
     * @param {Object} query The query that must be matched for a document to be
     * operated on.
     * @param {Object} update The object containing updated key/values. Any keys that
     * match keys on the existing document will be overwritten with this data. Any
     * keys that do not currently exist on the document will be added to the document.
     * @param {Object=} options An options object.
     * @returns {Array} The items that were updated.
     */
    FdbDocument.prototype.update = function (query, update, options) {
    	var result = this.updateObject(this._data, update, query, options);

    	Eif (result) {
    		this.deferEmit('change', {type: 'update', data: this.decouple(this._data)});
    	}
    };

    /**
     * Internal method for document updating.
     * @func updateObject
     * @memberof Document
     * @param {Object} doc The document to update.
     * @param {Object} update The object with key/value pairs to update the document with.
     * @param {Object} query The query object that we need to match to perform an update.
     * @param {Object} options An options object.
     * @param {String} path The current recursive path.
     * @param {String} opType The type of update operation to perform, if none is specified
     * default is to set new data against matching fields.
     * @returns {Boolean} True if the document was updated with new / changed data or
     * false if it was not updated because the data was the same.
     * @private
     */
    FdbDocument.prototype.updateObject = Collection.prototype.updateObject;

    /**
     * Determines if the passed key has an array positional mark (a dollar at the end
     * of its name).
     * @func _isPositionalKey
     * @memberof Document
     * @param {String} key The key to check.
     * @returns {Boolean} True if it is a positional or false if not.
     * @private
     */
    FdbDocument.prototype._isPositionalKey = function (key) {
    	return key.substr(key.length - 2, 2) === '.$';
    };

    /**
     * Updates a property on an object depending on if the collection is
     * currently running data-binding or not.
     * @func _updateProperty
     * @memberof Document
     * @param {Object} doc The object whose property is to be updated.
     * @param {String} prop The property to update.
     * @param {*} val The new value of the property.
     * @private
     */
    FdbDocument.prototype._updateProperty = function (doc, prop, val) {
    	Eif (this._linked) {
    		window.jQuery.observable(doc).setProperty(prop, val);

    		Iif (this.debug()) {
    			console.log(this.logIdentifier() + ' Setting data-bound document property "' + prop + '"');
    		}
    	} else {
    		doc[prop] = val;

    		if (this.debug()) {
    			console.log(this.logIdentifier() + ' Setting non-data-bound document property "' + prop + '" to val "' + val + '"');
    		}
    	}
    };

    /**
     * Increments a value for a property on a document by the passed number.
     * @func _updateIncrement
     * @memberof Document
     * @param {Object} doc The document to modify.
     * @param {String} prop The property to modify.
     * @param {Number} val The amount to increment by.
     * @private
     */
    FdbDocument.prototype._updateIncrement = function (doc, prop, val) {
    	if (this._linked) {
    		window.jQuery.observable(doc).setProperty(prop, doc[prop] + val);
    	} else {
    		doc[prop] += val;
    	}
    };

    /**
     * Changes the index of an item in the passed array.
     * @func _updateSpliceMove
     * @memberof Document
     * @param {Array} arr The array to modify.
     * @param {Number} indexFrom The index to move the item from.
     * @param {Number} indexTo The index to move the item to.
     * @private
     */
    FdbDocument.prototype._updateSpliceMove = function (arr, indexFrom, indexTo) {
    	if (this._linked) {
    		window.jQuery.observable(arr).move(indexFrom, indexTo);

    		if (this.debug()) {
    			console.log(this.logIdentifier() + ' Moving data-bound document array index from "' + indexFrom + '" to "' + indexTo + '"');
    		}
    	} else {
    		arr.splice(indexTo, 0, arr.splice(indexFrom, 1)[0]);

    		if (this.debug()) {
    			console.log(this.logIdentifier() + ' Moving non-data-bound document array index from "' + indexFrom + '" to "' + indexTo + '"');
    		}
    	}
    };

    /**
     * Inserts an item into the passed array at the specified index.
     * @func _updateSplicePush
     * @memberof Document
     * @param {Array} arr The array to insert into.
     * @param {Number} index The index to insert at.
     * @param {Object} doc The document to insert.
     * @private
     */
    FdbDocument.prototype._updateSplicePush = function (arr, index, doc) {
    	if (arr.length > index) {
    		if (this._linked) {
    			window.jQuery.observable(arr).insert(index, doc);
    		} else {
    			arr.splice(index, 0, doc);
    		}
    	} else {
    		if (this._linked) {
    			window.jQuery.observable(arr).insert(doc);
    		} else {
    			arr.push(doc);
    		}
    	}
    };

    /**
     * Inserts an item at the end of an array.
     * @func _updatePush
     * @memberof Document
     * @param {Array} arr The array to insert the item into.
     * @param {Object} doc The document to insert.
     * @private
     */
    FdbDocument.prototype._updatePush = function (arr, doc) {
    	if (this._linked) {
    		window.jQuery.observable(arr).insert(doc);
    	} else {
    		arr.push(doc);
    	}
    };

    /**
     * Removes an item from the passed array.
     * @func _updatePull
     * @memberof Document
     * @param {Array} arr The array to modify.
     * @param {Number} index The index of the item in the array to remove.
     * @private
     */
    FdbDocument.prototype._updatePull = function (arr, index) {
    	if (this._linked) {
    		window.jQuery.observable(arr).remove(index);
    	} else {
    		arr.splice(index, 1);
    	}
    };

    /**
     * Multiplies a value for a property on a document by the passed number.
     * @func _updateMultiply
     * @memberof Document
     * @param {Object} doc The document to modify.
     * @param {String} prop The property to modify.
     * @param {Number} val The amount to multiply by.
     * @private
     */
    FdbDocument.prototype._updateMultiply = function (doc, prop, val) {
    	if (this._linked) {
    		window.jQuery.observable(doc).setProperty(prop, doc[prop] * val);
    	} else {
    		doc[prop] *= val;
    	}
    };

    /**
     * Renames a property on a document to the passed property.
     * @func _updateRename
     * @memberof Document
     * @param {Object} doc The document to modify.
     * @param {String} prop The property to rename.
     * @param {Number} val The new property name.
     * @private
     */
    FdbDocument.prototype._updateRename = function (doc, prop, val) {
    	var existingVal = doc[prop];
    	if (this._linked) {
    		window.jQuery.observable(doc).setProperty(val, existingVal);
    		window.jQuery.observable(doc).removeProperty(prop);
    	} else {
    		doc[val] = existingVal;
    		delete doc[prop];
    	}
    };

    /**
     * Deletes a property on a document.
     * @func _updateUnset
     * @memberof Document
     * @param {Object} doc The document to modify.
     * @param {String} prop The property to delete.
     * @private
     */
    FdbDocument.prototype._updateUnset = function (doc, prop) {
    	Eif (this._linked) {
    		window.jQuery.observable(doc).removeProperty(prop);
    	} else {
    		delete doc[prop];
    	}
    };

    /**
     * Drops the document.
     * @func drop
     * @memberof Document
     * @returns {boolean} True if successful, false if not.
     */
    FdbDocument.prototype.drop = function (callback) {
    	if (!this.isDropped()) {
    		if (this._db && this._name) {
    			if (this._db && this._db._document && this._db._document[this._name]) {
    				this._state = 'dropped';

    				delete this._db._document[this._name];
    				delete this._data;

    				this.emit('drop', this);

    				if (callback) { callback(false, true); }

    				delete this._listeners;

    				return true;
    			}
    		}
    	} else {
    		return true;
    	}

    	return false;
    };

    /**
     * Creates a new document instance or returns an existing
     * instance if one already exists with the passed name.
     * @func document
     * @memberOf Db
     * @param {String} name The name of the instance.
     * @returns {*}
     */
    Db.prototype.document = function (name) {
    	var self = this;

    	Eif (name) {
    		// Handle being passed an instance
    		Iif (name instanceof FdbDocument) {
    			if (name.state() !== 'droppped') {
    				return name;
    			} else {
    				name = name.name();
    			}
    		}

    		if (this._document && this._document[name]) {
    			return this._document[name];
    		}

    		this._document = this._document || {};
    		this._document[name] = new FdbDocument(name).db(this);

    		self.emit('create', self._document[name], 'document', name);

    		return this._document[name];
    	} else {
    		// Return an object of document data
    		return this._document;
    	}
    };

    /**
     * Returns an array of documents the DB currently has.
     * @func documents
     * @memberof Db
     * @returns {Array} An array of objects containing details of each document
     * the database is currently managing.
     */
    Db.prototype.documents = function () {
    	var arr = [],
    		item,
    		i;

    	for (i in this._document) {
    		if (this._document.hasOwnProperty(i)) {
    			item = this._document[i];

    			arr.push({
    				name: i,
    				linked: item.isLinked !== undefined ? item.isLinked() : false
    			});
    		}
    	}

    	return arr;
    };

    Shared.finishModule('Document');
    module.exports = FdbDocument;
    },{"./Collection":7,"./Shared":40}],12:[function(_dereq_,module,exports){
    // geohash.js
    // Geohash library for Javascript
    // (c) 2008 David Troy
    // Distributed under the MIT License
    // Original at: https://github.com/davetroy/geohash-js

    // Modified by Irrelon Software Limited (http://www.irrelon.com)
    // to clean up and modularise the code using Node.js-style exports
    // and add a few helper methods.
    // @by Rob Evans - rob@irrelon.com
    "use strict";

    /*
    Define some shared constants that will be used by all instances
    of the module.
     */
    var bits,
    	base32,
    	neighbors,
    	borders;

    bits = [16, 8, 4, 2, 1];

    base32 = "0123456789bcdefghjkmnpqrstuvwxyz";
    neighbors = {
    	right: {even: "bc01fg45238967deuvhjyznpkmstqrwx"},
    	left: {even: "238967debc01fg45kmstqrwxuvhjyznp"},
    	top: {even: "p0r21436x8zb9dcf5h7kjnmqesgutwvy"},
    	bottom: {even: "14365h7k9dcfesgujnmqp0r2twvyx8zb"}
    };

    borders = {
    	right: {even: "bcfguvyz"},
    	left: {even: "0145hjnp"},
    	top: {even: "prxz"},
    	bottom: {even: "028b"}
    };

    neighbors.bottom.odd = neighbors.left.even;
    neighbors.top.odd = neighbors.right.even;
    neighbors.left.odd = neighbors.bottom.even;
    neighbors.right.odd = neighbors.top.even;

    borders.bottom.odd = borders.left.even;
    borders.top.odd = borders.right.even;
    borders.left.odd = borders.bottom.even;
    borders.right.odd = borders.top.even;

    var GeoHash = function () {};

    GeoHash.prototype.refineInterval = function (interval, cd, mask) {
    	if (cd & mask) { //jshint ignore: line
    		interval[0] = (interval[0] + interval[1]) / 2;
    	} else {
    		interval[1] = (interval[0] + interval[1]) / 2;
    	}
    };

    /**
     * Calculates all surrounding neighbours of a hash and returns them.
     * @param {String} centerHash The hash at the center of the grid.
     * @param options
     * @returns {*}
     */
    GeoHash.prototype.calculateNeighbours = function (centerHash, options) {
    	var response;

    	Iif (!options || options.type === 'object') {
    		response = {
    			center: centerHash,
    			left: this.calculateAdjacent(centerHash, 'left'),
    			right: this.calculateAdjacent(centerHash, 'right'),
    			top: this.calculateAdjacent(centerHash, 'top'),
    			bottom: this.calculateAdjacent(centerHash, 'bottom')
    		};

    		response.topLeft = this.calculateAdjacent(response.left, 'top');
    		response.topRight = this.calculateAdjacent(response.right, 'top');
    		response.bottomLeft = this.calculateAdjacent(response.left, 'bottom');
    		response.bottomRight = this.calculateAdjacent(response.right, 'bottom');
    	} else {
    		response = [];

    		response[4] = centerHash;
    		response[3] = this.calculateAdjacent(centerHash, 'left');
    		response[5] = this.calculateAdjacent(centerHash, 'right');
    		response[1] = this.calculateAdjacent(centerHash, 'top');
    		response[7] = this.calculateAdjacent(centerHash, 'bottom');

    		response[0] = this.calculateAdjacent(response[3], 'top');
    		response[2] = this.calculateAdjacent(response[5], 'top');
    		response[6] = this.calculateAdjacent(response[3], 'bottom');
    		response[8] = this.calculateAdjacent(response[5], 'bottom');
    	}

    	return response;
    };

    /**
     * Calculates an adjacent hash to the hash passed, in the direction
     * specified.
     * @param {String} srcHash The hash to calculate adjacent to.
     * @param {String} dir Either "top", "left", "bottom" or "right".
     * @returns {String} The resulting geohash.
     */
    GeoHash.prototype.calculateAdjacent = function (srcHash, dir) {
    	srcHash = srcHash.toLowerCase();

    	var lastChr = srcHash.charAt(srcHash.length - 1),
    		type = (srcHash.length % 2) ? 'odd' : 'even',
    		base = srcHash.substring(0, srcHash.length - 1);

    	if (borders[dir][type].indexOf(lastChr) !== -1) {
    		base = this.calculateAdjacent(base, dir);
    	}

    	return base + base32[neighbors[dir][type].indexOf(lastChr)];
    };

    /**
     * Decodes a string geohash back to longitude/latitude.
     * @param {String} geohash The hash to decode.
     * @returns {Object}
     */
    GeoHash.prototype.decode = function (geohash) {
    	var isEven = 1,
    		lat = [],
    		lon = [],
    		i, c, cd, j, mask,
    		latErr,
    		lonErr;

    	lat[0] = -90.0;
    	lat[1] = 90.0;
    	lon[0] = -180.0;
    	lon[1] = 180.0;

    	latErr = 90.0;
    	lonErr = 180.0;

    	for (i = 0; i < geohash.length; i++) {
    		c = geohash[i];
    		cd = base32.indexOf(c);

    		for (j = 0; j < 5; j++) {
    			mask = bits[j];

    			if (isEven) {
    				lonErr /= 2;
    				this.refineInterval(lon, cd, mask);
    			} else {
    				latErr /= 2;
    				this.refineInterval(lat, cd, mask);
    			}

    			isEven = !isEven;
    		}
    	}

    	lat[2] = (lat[0] + lat[1]) / 2;
    	lon[2] = (lon[0] + lon[1]) / 2;

    	return {
    		latitude: lat,
    		longitude: lon
    	};
    };

    /**
     * Encodes a longitude/latitude to geohash string.
     * @param latitude
     * @param longitude
     * @param {Number=} precision Length of the geohash string. Defaults to 12.
     * @returns {String}
     */
    GeoHash.prototype.encode = function (latitude, longitude, precision) {
    	var isEven = 1,
    		mid,
    		lat = [],
    		lon = [],
    		bit = 0,
    		ch = 0,
    		geoHash = "";

    	if (!precision) { precision = 12; }

    	lat[0] = -90.0;
    	lat[1] = 90.0;
    	lon[0] = -180.0;
    	lon[1] = 180.0;

    	while (geoHash.length < precision) {
    		if (isEven) {
    			mid = (lon[0] + lon[1]) / 2;

    			if (longitude > mid) {
    				ch |= bits[bit]; //jshint ignore: line
    				lon[0] = mid;
    			} else {
    				lon[1] = mid;
    			}
    		} else {
    			mid = (lat[0] + lat[1]) / 2;

    			if (latitude > mid) {
    				ch |= bits[bit]; //jshint ignore: line
    				lat[0] = mid;
    			} else {
    				lat[1] = mid;
    			}
    		}

    		isEven = !isEven;

    		if (bit < 4) {
    			bit++;
    		} else {
    			geoHash += base32[ch];
    			bit = 0;
    			ch = 0;
    		}
    	}

    	return geoHash;
    };

    module.exports = GeoHash;
    },{}],13:[function(_dereq_,module,exports){
    "use strict";

    // Import external names locally
    var Shared,
    	Db,
    	Collection,
    	CollectionGroup,
    	View,
    	CollectionInit,
    	DbInit,
    	ReactorIO;

    //Shared = ForerunnerDB.shared;
    Shared = _dereq_('./Shared');

    /**
     * Creates a new grid instance.
     * @name Grid
     * @class Grid
     * @param {String} selector jQuery selector.
     * @param {String} template The template selector.
     * @param {Object=} options The options object to apply to the grid.
     * @constructor
     */
    var Grid = function (selector, template, options) {
    	this.init.apply(this, arguments);
    };

    Grid.prototype.init = function (selector, template, options) {
    	var self = this;

    	this._selector = selector;
    	this._template = template;
    	this._options = options || {};
    	this._debug = {};
    	this._id = this.objectId();

    	this._collectionDroppedWrap = function () {
    		self._collectionDropped.apply(self, arguments);
    	};
    };

    Shared.addModule('Grid', Grid);
    Shared.mixin(Grid.prototype, 'Mixin.Common');
    Shared.mixin(Grid.prototype, 'Mixin.ChainReactor');
    Shared.mixin(Grid.prototype, 'Mixin.Constants');
    Shared.mixin(Grid.prototype, 'Mixin.Triggers');
    Shared.mixin(Grid.prototype, 'Mixin.Events');
    Shared.mixin(Grid.prototype, 'Mixin.Tags');

    Collection = _dereq_('./Collection');
    CollectionGroup = _dereq_('./CollectionGroup');
    View = _dereq_('./View');
    ReactorIO = _dereq_('./ReactorIO');
    CollectionInit = Collection.prototype.init;
    Db = Shared.modules.Db;
    DbInit = Db.prototype.init;

    /**
     * Gets / sets the current state.
     * @func state
     * @memberof Grid
     * @param {String=} val The name of the state to set.
     * @returns {Grid}
     */
    Shared.synthesize(Grid.prototype, 'state');

    /**
     * Gets / sets the current name.
     * @func name
     * @memberof Grid
     * @param {String=} val The name to set.
     * @returns {Grid}
     */
    Shared.synthesize(Grid.prototype, 'name');

    /**
     * Executes an insert against the grid's underlying data-source.
     * @func insert
     * @memberof Grid
     */
    Grid.prototype.insert = function () {
    	this._from.insert.apply(this._from, arguments);
    };

    /**
     * Executes an update against the grid's underlying data-source.
     * @func update
     * @memberof Grid
     */
    Grid.prototype.update = function () {
    	this._from.update.apply(this._from, arguments);
    };

    /**
     * Executes an updateById against the grid's underlying data-source.
     * @func updateById
     * @memberof Grid
     */
    Grid.prototype.updateById = function () {
    	this._from.updateById.apply(this._from, arguments);
    };

    /**
     * Executes a remove against the grid's underlying data-source.
     * @func remove
     * @memberof Grid
     */
    Grid.prototype.remove = function () {
    	this._from.remove.apply(this._from, arguments);
    };

    /**
     * Sets the collection from which the grid will assemble its data.
     * @func from
     * @memberof Grid
     * @param {Collection} collection The collection to use to assemble grid data.
     * @returns {Grid}
     */
    Grid.prototype.from = function (collection) {
    	//var self = this;

    	Eif (collection !== undefined) {
    		// Check if we have an existing from
    		Iif (this._from) {
    			// Remove the listener to the drop event
    			this._from.off('drop', this._collectionDroppedWrap);
    			this._from._removeGrid(this);
    		}

    		Iif (typeof(collection) === 'string') {
    			collection = this._db.collection(collection);
    		}

    		this._from = collection;
    		this._from.on('drop', this._collectionDroppedWrap);
    		this.refresh();
    	}

    	return this;
    };

    /**
     * Gets / sets the db instance this class instance belongs to.
     * @func db
     * @memberof Grid
     * @param {Db=} db The db instance.
     * @returns {*}
     */
    Shared.synthesize(Grid.prototype, 'db', function (db) {
    	Eif (db) {
    		// Apply the same debug settings
    		this.debug(db.debug());
    	}

    	return this.$super.apply(this, arguments);
    });

    Grid.prototype._collectionDropped = function (collection) {
    	if (collection) {
    		// Collection was dropped, remove from grid
    		delete this._from;
    	}
    };

    /**
     * Drops a grid and all it's stored data from the database.
     * @func drop
     * @memberof Grid
     * @returns {boolean} True on success, false on failure.
     */
    Grid.prototype.drop = function (callback) {
    	Eif (!this.isDropped()) {
    		Eif (this._from) {
    			// Remove data-binding
    			this._from.unlink(this._selector, this.template());

    			// Kill listeners and references
    			this._from.off('drop', this._collectionDroppedWrap);
    			this._from._removeGrid(this);

    			Eif (this.debug() || (this._db && this._db.debug())) {
    				console.log(this.logIdentifier() + ' Dropping grid ' + this._selector);
    			}

    			this._state = 'dropped';

    			Eif (this._db && this._selector) {
    				delete this._db._grid[this._selector];
    			}

    			this.emit('drop', this);

    			Iif (callback) { callback(false, true); }

    			delete this._selector;
    			delete this._template;
    			delete this._from;
    			delete this._db;
    			delete this._listeners;

    			return true;
    		}
    	} else {
    		return true;
    	}

    	return false;
    };

    /**
     * Gets / sets the grid's HTML template to use when rendering.
     * @func template
     * @memberof Grid
     * @param {Selector} template The template's jQuery selector.
     * @returns {*}
     */
    Grid.prototype.template = function (template) {
    	Iif (template !== undefined) {
    		this._template = template;
    		return this;
    	}

    	return this._template;
    };

    Grid.prototype._sortGridClick = function (e) {
    	var elem = window.jQuery(e.currentTarget),
    		sortColText = elem.attr('data-grid-sort') || '',
    		sortColDir = parseInt((elem.attr('data-grid-dir') || "-1"), 10) === -1 ? 1 : -1,
    		sortCols = sortColText.split(','),
    		sortObj = {},
    		i;

    	// Remove all grid sort tags from the grid
    	window.jQuery(this._selector).find('[data-grid-dir]').removeAttr('data-grid-dir');

    	// Flip the sort direction
    	elem.attr('data-grid-dir', sortColDir);

    	for (i = 0; i < sortCols.length; i++) {
    		sortObj[sortCols] = sortColDir;
    	}

    	Shared.mixin(sortObj, this._options.$orderBy);

    	this._from.orderBy(sortObj);
    	this.emit('sort', sortObj);
    };

    /**
     * Refreshes the grid data such as ordering etc.
     * @func refresh
     * @memberof Grid
     */
    Grid.prototype.refresh = function () {
    	Eif (this._from) {
    		Eif (this._from.link) {
    			var self = this,
    				elem = window.jQuery(this._selector),
    				sortClickListener = function () {
    					self._sortGridClick.apply(self, arguments);
    				};

    			// Clear the container
    			elem.html('');

    			Eif (self._from.orderBy) {
    				// Remove listeners
    				elem.off('click', '[data-grid-sort]', sortClickListener);
    			}

    			Eif (self._from.query) {
    				// Remove listeners
    				elem.off('click', '[data-grid-filter]', sortClickListener);
    			}

    			// Set wrap name if none is provided
    			self._options.$wrap = self._options.$wrap || 'gridRow';

    			// Auto-bind the data to the grid template
    			self._from.link(self._selector, self.template(), self._options);

    			// Check if the data source (collection or view) has an
    			// orderBy method (usually only views) and if so activate
    			// the sorting system
    			Eif (self._from.orderBy) {
    				// Listen for sort requests
    				elem.on('click', '[data-grid-sort]', sortClickListener);
    			}

    			Eif (self._from.query) {
    				// Listen for filter requests
    				var queryObj = {};

    				elem.find('[data-grid-filter]').each(function (index, filterElem) {
    					filterElem = window.jQuery(filterElem);

    					var filterField = filterElem.attr('data-grid-filter'),
    						filterVarType = filterElem.attr('data-grid-vartype'),
    						filterSort = {},
    						title = filterElem.html(),
    						dropDownButton,
    						dropDownMenu,
    						template,
    						filterQuery,
    						filterView = self._db.view('tmpGridFilter_' + self._id + '_' + filterField);

    					filterSort[filterField] = 1;

    					filterQuery = {
    						$distinct: filterSort
    					};

    					filterView
    						.query(filterQuery)
    						.orderBy(filterSort)
    						.from(self._from._from);

    					template = [
    						'<div class="dropdown" id="' + self._id + '_' + filterField + '">',
    							'<button class="btn btn-default dropdown-toggle" type="button" id="' + self._id + '_' + filterField + '_dropdownButton" data-toggle="dropdown" aria-expanded="true">',
    								title + ' <span class="caret"></span>',
    							'</button>',
    						'</div>'
    					];

    					dropDownButton = window.jQuery(template.join(''));
    					dropDownMenu = window.jQuery('<ul class="dropdown-menu" role="menu" id="' + self._id + '_' + filterField + '_dropdownMenu"></ul>');

    					dropDownButton.append(dropDownMenu);

    					filterElem.html(dropDownButton);

    					// Data-link the underlying data to the grid filter drop-down
    					filterView.link(dropDownMenu, {
    						template: [
    							'<li role="presentation" class="input-group" style="width: 240px; padding-left: 10px; padding-right: 10px; padding-top: 5px;">',
    								'<input type="search" class="form-control gridFilterSearch" placeholder="Search...">',
    								'<span class="input-group-btn">',
    									'<button class="btn btn-default gridFilterClearSearch" type="button"><span class="glyphicon glyphicon-remove-circle glyphicons glyphicons-remove"></span></button>',
    								'</span>',
    							'</li>',
    							'<li role="presentation" class="divider"></li>',
    							'<li role="presentation" data-val="$all">',
    								'<a role="menuitem" tabindex="-1">',
    									'<input type="checkbox" checked>&nbsp;All',
    								'</a>',
    							'</li>',
    							'<li role="presentation" class="divider"></li>',
    							'{^{for options}}',
    								'<li role="presentation" data-link="data-val{:' + filterField + '}">',
    									'<a role="menuitem" tabindex="-1">',
    										'<input type="checkbox">&nbsp;{^{:' + filterField + '}}',
    									'</a>',
    								'</li>',
    							'{{/for}}'
    						].join('')
    					}, {
    						$wrap: 'options'
    					});

    					elem.on('keyup', '#' + self._id + '_' + filterField + '_dropdownMenu .gridFilterSearch', function (e) {
    						var elem = window.jQuery(this),
    							query = filterView.query(),
    							search = elem.val();

    						if (search) {
    							query[filterField] = new RegExp(search, 'gi');
    						} else {
    							delete query[filterField];
    						}

    						filterView.query(query);
    					});

    					elem.on('click', '#' + self._id + '_' + filterField + '_dropdownMenu .gridFilterClearSearch', function (e) {
    						// Clear search text box
    						window.jQuery(this).parents('li').find('.gridFilterSearch').val('');

    						// Clear view query
    						var query = filterView.query();
    						delete query[filterField];
    						filterView.query(query);
    					});

    					elem.on('click', '#' + self._id + '_' + filterField + '_dropdownMenu li', function (e) {
    						e.stopPropagation();

    						var fieldValue,
    							elem = $(this),
    							checkbox = elem.find('input[type="checkbox"]'),
    							checked,
    							addMode = true,
    							fieldInArr,
    							liElem,
    							i;

    						// If the checkbox is not the one clicked on
    						if (!window.jQuery(e.target).is('input')) {
    							// Set checkbox to opposite of current value
    							checkbox.prop('checked', !checkbox.prop('checked'));
    							checked = checkbox.is(':checked');
    						} else {
    							checkbox.prop('checked', checkbox.prop('checked'));
    							checked = checkbox.is(':checked');
    						}

    						liElem = window.jQuery(this);
    						fieldValue = liElem.attr('data-val');

    						// Check if the selection is the "all" option
    						if (fieldValue === '$all') {
    							// Remove the field from the query
    							delete queryObj[filterField];

    							// Clear all other checkboxes
    							liElem.parent().find('li[data-val!="$all"]').find('input[type="checkbox"]').prop('checked', false);
    						} else {
    							// Clear the "all" checkbox
    							liElem.parent().find('[data-val="$all"]').find('input[type="checkbox"]').prop('checked', false);

    							// Check if the type needs casting
    							switch (filterVarType) {
    								case 'integer':
    									fieldValue = parseInt(fieldValue, 10);
    									break;

    								case 'float':
    									fieldValue = parseFloat(fieldValue);
    									break;

    								default:
    							}

    							// Check if the item exists already
    							queryObj[filterField] = queryObj[filterField] || {
    								$in: []
    							};

    							fieldInArr = queryObj[filterField].$in;

    							for (i = 0; i < fieldInArr.length; i++) {
    								if (fieldInArr[i] === fieldValue) {
    									// Item already exists
    									if (checked === false) {
    										// Remove the item
    										fieldInArr.splice(i, 1);
    									}
    									addMode = false;
    									break;
    								}
    							}

    							if (addMode && checked) {
    								fieldInArr.push(fieldValue);
    							}

    							if (!fieldInArr.length) {
    								// Remove the field from the query
    								delete queryObj[filterField];
    							}
    						}

    						// Set the view query
    						self._from.queryData(queryObj);
    						if (self._from.pageFirst) {
    							self._from.pageFirst();
    						}
    					});
    				});
    			}

    			self.emit('refresh');
    		} else {
    			throw('Grid requires the AutoBind module in order to operate!');
    		}
    	}

    	return this;
    };

    /**
     * Returns the number of documents currently in the grid.
     * @func count
     * @memberof Grid
     * @returns {Number}
     */
    Grid.prototype.count = function () {
    	return this._from.count();
    };

    /**
     * Creates a grid and assigns the collection as its data source.
     * @func grid
     * @memberof Collection
     * @param {String} selector jQuery selector of grid output target.
     * @param {String} template The table template to use when rendering the grid.
     * @param {Object=} options The options object to apply to the grid.
     * @returns {*}
     */
    Collection.prototype.grid = View.prototype.grid = function (selector, template, options) {
    	Eif (this._db && this._db._grid ) {
    		Eif (selector !== undefined) {
    			Eif (template !== undefined) {
    				Eif (!this._db._grid[selector]) {
    					var grid = new Grid(selector, template, options)
    						.db(this._db)
    						.from(this);

    					this._grid = this._grid || [];
    					this._grid.push(grid);

    					this._db._grid[selector] = grid;

    					return grid;
    				} else {
    					throw(this.logIdentifier() + ' Cannot create a grid because a grid with this name already exists: ' + selector);
    				}
    			}

    			return this._db._grid[selector];
    		}

    		return this._db._grid;
    	}
    };

    /**
     * Removes a grid safely from the DOM. Must be called when grid is
     * no longer required / is being removed from DOM otherwise references
     * will stick around and cause memory leaks.
     * @func unGrid
     * @memberof Collection
     * @param {String} selector jQuery selector of grid output target.
     * @param {String} template The table template to use when rendering the grid.
     * @param {Object=} options The options object to apply to the grid.
     * @returns {*}
     */
    Collection.prototype.unGrid = View.prototype.unGrid = function (selector, template, options) {
    	var i,
    		grid;

    	if (this._db && this._db._grid ) {
    		if (selector && template) {
    			if (this._db._grid[selector]) {
    				grid = this._db._grid[selector];
    				delete this._db._grid[selector];

    				return grid.drop();
    			} else {
    				throw(this.logIdentifier() + ' Cannot remove grid because a grid with this name does not exist: ' + name);
    			}
    		} else {
    			// No parameters passed, remove all grids from this module
    			for (i in this._db._grid) {
    				if (this._db._grid.hasOwnProperty(i)) {
    					grid = this._db._grid[i];
    					delete this._db._grid[i];

    					grid.drop();

    					if (this.debug()) {
    						console.log(this.logIdentifier() + ' Removed grid binding "' + i + '"');
    					}
    				}
    			}

    			this._db._grid = {};
    		}
    	}
    };

    /**
     * Adds a grid to the internal grid lookup.
     * @func _addGrid
     * @memberof Collection
     * @param {Grid} grid The grid to add.
     * @returns {Collection}
     * @private
     */
    Collection.prototype._addGrid = CollectionGroup.prototype._addGrid = View.prototype._addGrid = function (grid) {
    	if (grid !== undefined) {
    		this._grid = this._grid || [];
    		this._grid.push(grid);
    	}

    	return this;
    };

    /**
     * Removes a grid from the internal grid lookup.
     * @func _removeGrid
     * @memberof Collection
     * @param {Grid} grid The grid to remove.
     * @returns {Collection}
     * @private
     */
    Collection.prototype._removeGrid = CollectionGroup.prototype._removeGrid = View.prototype._removeGrid = function (grid) {
    	Eif (grid !== undefined && this._grid) {
    		var index = this._grid.indexOf(grid);
    		Eif (index > -1) {
    			this._grid.splice(index, 1);
    		}
    	}

    	return this;
    };

    // Extend DB with grids init
    Db.prototype.init = function () {
    	this._grid = {};
    	DbInit.apply(this, arguments);
    };

    /**
     * Determine if a grid with the passed name already exists.
     * @func gridExists
     * @memberof Db
     * @param {String} selector The jQuery selector to bind the grid to.
     * @returns {boolean}
     */
    Db.prototype.gridExists = function (selector) {
    	return Boolean(this._grid[selector]);
    };

    /**
     * Creates a grid based on the passed arguments.
     * @func grid
     * @memberof Db
     * @param {String} selector The jQuery selector of the grid to retrieve.
     * @param {String} template The table template to use when rendering the grid.
     * @param {Object=} options The options object to apply to the grid.
     * @returns {*}
     */
    Db.prototype.grid = function (selector, template, options) {
    	Eif (!this._grid[selector]) {
    		Eif (this.debug() || (this._db && this._db.debug())) {
    			console.log(this.logIdentifier() + ' Creating grid ' + selector);
    		}
    	}

    	this._grid[selector] = this._grid[selector] || new Grid(selector, template, options).db(this);
    	return this._grid[selector];
    };

    /**
     * Removes a grid based on the passed arguments.
     * @func unGrid
     * @memberof Db
     * @param {String} selector The jQuery selector of the grid to retrieve.
     * @param {String} template The table template to use when rendering the grid.
     * @param {Object=} options The options object to apply to the grid.
     * @returns {*}
     */
    Db.prototype.unGrid = function (selector, template, options) {
    	if (!this._grid[selector]) {
    		if (this.debug() || (this._db && this._db.debug())) {
    			console.log(this.logIdentifier() + ' Creating grid ' + selector);
    		}
    	}

    	this._grid[selector] = this._grid[selector] || new Grid(selector, template, options).db(this);
    	return this._grid[selector];
    };

    /**
     * Returns an array of grids the DB currently has.
     * @func grids
     * @memberof Db
     * @returns {Array} An array of objects containing details of each grid
     * the database is currently managing.
     */
    Db.prototype.grids = function () {
    	var arr = [],
    		item,
    		i;

    	for (i in this._grid) {
    		if (this._grid.hasOwnProperty(i)) {
    			item = this._grid[i];

    			arr.push({
    				name: i,
    				count: item.count(),
    				linked: item.isLinked !== undefined ? item.isLinked() : false
    			});
    		}
    	}

    	return arr;
    };

    Shared.finishModule('Grid');
    module.exports = Grid;
    },{"./Collection":7,"./CollectionGroup":8,"./ReactorIO":38,"./Shared":40,"./View":42}],14:[function(_dereq_,module,exports){
    "use strict";

    // Import external names locally
    var Shared,
    	Collection,
    	CollectionInit,
    	Overload;

    Shared = _dereq_('./Shared');
    Overload = _dereq_('./Overload');

    /**
     * The constructor.
     *
     * @constructor
     */
    var Highchart = function (collection, options) {
    	this.init.apply(this, arguments);
    };

    Highchart.prototype.init = function (collection, options) {
    	this._options = options;
    	this._selector = window.jQuery(this._options.selector);

    	Iif (!this._selector[0]) {
    		throw(this.classIdentifier() + ' "' + collection.name() + '": Chart target element does not exist via selector: ' + this._options.selector);
    	}

    	this._listeners = {};
    	this._collection = collection;

    	// Setup the chart
    	this._options.series = [];

    	// Disable attribution on highcharts
    	options.chartOptions = options.chartOptions || {};
    	options.chartOptions.credits = false;

    	// Set the data for the chart
    	var data,
    		seriesObj,
    		chartData;

    	switch (this._options.type) {
    		case 'pie':
    			// Create chart from data
    			this._selector.highcharts(this._options.chartOptions);
    			this._chart = this._selector.highcharts();

    			// Generate graph data from collection data
    			data = this._collection.find();

    			seriesObj = {
    				allowPointSelect: true,
    				cursor: 'pointer',
    				dataLabels: {
    					enabled: true,
    					format: '<b>{point.name}</b>: {y} ({point.percentage:.0f}%)',
    					style: {
    						color: (window.Highcharts.theme && window.Highcharts.theme.contrastTextColor) || 'black'
    					}
    				}
    			};

    			chartData = this.pieDataFromCollectionData(data, this._options.keyField, this._options.valField);

    			window.jQuery.extend(seriesObj, this._options.seriesOptions);

    			window.jQuery.extend(seriesObj, {
    				name: this._options.seriesName,
    				data: chartData
    			});

    			this._chart.addSeries(seriesObj, true, true);
    			break;

    		case 'line':
    		case 'area':
    		case 'column':
    		case 'bar':
    			// Generate graph data from collection data
    			chartData = this.seriesDataFromCollectionData(
    				this._options.seriesField,
    				this._options.keyField,
    				this._options.valField,
    				this._options.orderBy,
    				this._options
    			);

    			this._options.chartOptions.xAxis = chartData.xAxis;
    			this._options.chartOptions.series = chartData.series;

    			this._selector.highcharts(this._options.chartOptions);
    			this._chart = this._selector.highcharts();
    			break;

    		default:
    			throw(this.classIdentifier() + ' "' + collection.name() + '": Chart type specified is not currently supported by ForerunnerDB: ' + this._options.type);
    	}

    	// Hook the collection events to auto-update the chart
    	this._hookEvents();
    };

    Shared.addModule('Highchart', Highchart);

    Collection = Shared.modules.Collection;
    CollectionInit = Collection.prototype.init;

    Shared.mixin(Highchart.prototype, 'Mixin.Common');
    Shared.mixin(Highchart.prototype, 'Mixin.Events');

    /**
     * Gets / sets the current state.
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(Highchart.prototype, 'state');

    /**
     * Generate pie-chart series data from the given collection data array.
     * @param data
     * @param keyField
     * @param valField
     * @returns {Array}
     */
    Highchart.prototype.pieDataFromCollectionData = function (data, keyField, valField) {
    	var graphData = [],
    		i;

    	for (i = 0; i < data.length; i++) {
    		graphData.push([data[i][keyField], data[i][valField]]);
    	}

    	return graphData;
    };

    /**
     * Generate line-chart series data from the given collection data array.
     * @param seriesField
     * @param keyField
     * @param valField
     * @param orderBy
     */
    Highchart.prototype.seriesDataFromCollectionData = function (seriesField, keyField, valField, orderBy, options) {
    	var data = this._collection.distinct(seriesField),
    		seriesData = [],
    		xAxis = options && options.chartOptions && options.chartOptions.xAxis ? options.chartOptions.xAxis : {
    			categories: []
    		},
    		seriesName,
    		query,
    		dataSearch,
    		seriesValues,
    		sData,
    		i, k;

    	// What we WANT to output:
    	/*series: [{
    		name: 'Responses',
    		data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
    	}]*/

    	// Loop keys
    	for (i = 0; i < data.length; i++) {
    		seriesName = data[i];
    		query = {};
    		query[seriesField] = seriesName;

    		seriesValues = [];
    		dataSearch = this._collection.find(query, {
    			orderBy: orderBy
    		});

    		// Loop the keySearch data and grab the value for each item
    		for (k = 0; k < dataSearch.length; k++) {
    			Eif (xAxis.categories) {
    				xAxis.categories.push(dataSearch[k][keyField]);
    				seriesValues.push(dataSearch[k][valField]);
    			} else {
    				seriesValues.push([dataSearch[k][keyField], dataSearch[k][valField]]);
    			}
    		}

    		sData = {
    			name: seriesName,
    			data: seriesValues
    		};

    		Iif (options.seriesOptions) {
    			for (k in options.seriesOptions) {
    				if (options.seriesOptions.hasOwnProperty(k)) {
    					sData[k] = options.seriesOptions[k];
    				}
    			}
    		}

    		seriesData.push(sData);
    	}

    	return {
    		xAxis: xAxis,
    		series: seriesData
    	};
    };

    /**
     * Hook the events the chart needs to know about from the internal collection.
     * @private
     */
    Highchart.prototype._hookEvents = function () {
    	var self = this;

    	self._collection.on('change', function () {
    		self._changeListener.apply(self, arguments);
    	});

    	// If the collection is dropped, clean up after ourselves
    	self._collection.on('drop', function () {
    		self.drop.apply(self);
    	});
    };

    /**
     * Handles changes to the collection data that the chart is reading from and then
     * updates the data in the chart display.
     * @private
     */
    Highchart.prototype._changeListener = function () {
    	var self = this;

    	// Update the series data on the chart
    	if (typeof self._collection !== 'undefined' && self._chart) {
    		var data = self._collection.find(),
    			i;

    		switch (self._options.type) {
    			case 'pie':
    				self._chart.series[0].setData(
    					self.pieDataFromCollectionData(
    						data,
    						self._options.keyField,
    						self._options.valField
    					),
    					true,
    					true
    				);
    				break;

    			case 'bar':
    			case 'line':
    			case 'area':
    			case 'column':
    				var seriesData = self.seriesDataFromCollectionData(
    					self._options.seriesField,
    					self._options.keyField,
    					self._options.valField,
    					self._options.orderBy,
    					self._options
    				);

    				if (seriesData.xAxis.categories) {
    					self._chart.xAxis[0].setCategories(
    						seriesData.xAxis.categories
    					);
    				}

    				for (i = 0; i < seriesData.series.length; i++) {
    					if (self._chart.series[i]) {
    						// Series exists, set it's data
    						self._chart.series[i].setData(
    							seriesData.series[i].data,
    							true,
    							true
    						);
    					} else {
    						// Series data does not yet exist, add a new series
    						self._chart.addSeries(
    							seriesData.series[i],
    							true,
    							true
    						);
    					}
    				}
    				break;

    			default:
    				break;
    		}
    	}
    };

    /**
     * Destroys the chart and all internal references.
     * @returns {Boolean}
     */
    Highchart.prototype.drop = function (callback) {
    	Eif (!this.isDropped()) {
    		this._state = 'dropped';

    		Eif (this._chart) {
    			this._chart.destroy();
    		}

    		Eif (this._collection) {
    			this._collection.off('change', this._changeListener);
    			this._collection.off('drop', this.drop);

    			Eif (this._collection._highcharts) {
    				delete this._collection._highcharts[this._options.selector];
    			}
    		}

    		delete this._chart;
    		delete this._options;
    		delete this._collection;

    		this.emit('drop', this);

    		Iif (callback) {
    			callback(false, true);
    		}

    		delete this._listeners;

    		return true;
    	} else {
    		return true;
    	}
    };

    // Extend collection with highchart init
    Collection.prototype.init = function () {
    	this._highcharts = {};
    	CollectionInit.apply(this, arguments);
    };

    /**
     * Creates a pie chart from the collection.
     * @type {Overload}
     */
    Collection.prototype.pieChart = new Overload({
    	/**
    	 * Chart via options object.
    	 * @func pieChart
    	 * @memberof Highchart
    	 * @param {Object} options The options object.
    	 * @returns {*}
    	 */
    	'object': function (options) {
    		options.type = 'pie';

    		options.chartOptions = options.chartOptions || {};
    		options.chartOptions.chart = options.chartOptions.chart || {};
    		options.chartOptions.chart.type = 'pie';

    		if (!this._highcharts[options.selector]) {
    			// Store new chart in charts array
    			this._highcharts[options.selector] = new Highchart(this, options);
    		}

    		return this._highcharts[options.selector];
    	},

    	/**
    	 * Chart via defined params and an options object.
    	 * @func pieChart
    	 * @memberof Highchart
    	 * @param {String|jQuery} selector The element to render the chart to.
    	 * @param {String} keyField The field to use as the data key.
    	 * @param {String} valField The field to use as the data value.
    	 * @param {String} seriesName The name of the series to display on the chart.
    	 * @param {Object} options The options object.
    	 */
    	'*, string, string, string, ...': function (selector, keyField, valField, seriesName, options) {
    		options = options || {};

    		options.selector = selector;
    		options.keyField = keyField;
    		options.valField = valField;
    		options.seriesName = seriesName;

    		// Call the main chart method
    		this.pieChart(options);
    	}
    });

    /**
     * Creates a line chart from the collection.
     * @type {Overload}
     */
    Collection.prototype.lineChart = new Overload({
    	/**
    	 * Chart via selector.
    	 * @func lineChart
    	 * @memberof Highchart
    	 * @param {String} selector The chart selector.
    	 * @returns {*}
    	 */
    	'string': function (selector) {
    		return this._highcharts[selector];
    	},

    	/**
    	 * Chart via options object.
    	 * @func lineChart
    	 * @memberof Highchart
    	 * @param {Object} options The options object.
    	 * @returns {*}
    	 */
    	'object': function (options) {
    		options.type = 'line';

    		options.chartOptions = options.chartOptions || {};
    		options.chartOptions.chart = options.chartOptions.chart || {};
    		options.chartOptions.chart.type = 'line';

    		Eif (!this._highcharts[options.selector]) {
    			// Store new chart in charts array
    			this._highcharts[options.selector] = new Highchart(this, options);
    		}

    		return this._highcharts[options.selector];
    	},

    	/**
    	 * Chart via defined params and an options object.
    	 * @func lineChart
    	 * @memberof Highchart
    	 * @param {String|jQuery} selector The element to render the chart to.
    	 * @param {String} seriesField The name of the series to plot.
    	 * @param {String} keyField The field to use as the data key.
    	 * @param {String} valField The field to use as the data value.
    	 * @param {Object} options The options object.
    	 */
    	'*, string, string, string, ...': function (selector, seriesField, keyField, valField, options) {
    		options = options || {};

    		options.seriesField = seriesField;
    		options.selector = selector;
    		options.keyField = keyField;
    		options.valField = valField;

    		// Call the main chart method
    		this.lineChart(options);
    	}
    });

    /**
     * Creates an area chart from the collection.
     * @type {Overload}
     */
    Collection.prototype.areaChart = new Overload({
    	/**
    	 * Chart via options object.
    	 * @func areaChart
    	 * @memberof Highchart
    	 * @param {Object} options The options object.
    	 * @returns {*}
    	 */
    	'object': function (options) {
    		options.type = 'area';

    		options.chartOptions = options.chartOptions || {};
    		options.chartOptions.chart = options.chartOptions.chart || {};
    		options.chartOptions.chart.type = 'area';

    		if (!this._highcharts[options.selector]) {
    			// Store new chart in charts array
    			this._highcharts[options.selector] = new Highchart(this, options);
    		}

    		return this._highcharts[options.selector];
    	},

    	/**
    	 * Chart via defined params and an options object.
    	 * @func areaChart
    	 * @memberof Highchart
    	 * @param {String|jQuery} selector The element to render the chart to.
    	 * @param {String} seriesField The name of the series to plot.
    	 * @param {String} keyField The field to use as the data key.
    	 * @param {String} valField The field to use as the data value.
    	 * @param {Object} options The options object.
    	 */
    	'*, string, string, string, ...': function (selector, seriesField, keyField, valField, options) {
    		options = options || {};

    		options.seriesField = seriesField;
    		options.selector = selector;
    		options.keyField = keyField;
    		options.valField = valField;

    		// Call the main chart method
    		this.areaChart(options);
    	}
    });

    /**
     * Creates a column chart from the collection.
     * @type {Overload}
     */
    Collection.prototype.columnChart = new Overload({
    	/**
    	 * Chart via options object.
    	 * @func columnChart
    	 * @memberof Highchart
    	 * @param {Object} options The options object.
    	 * @returns {*}
    	 */
    	'object': function (options) {
    		options.type = 'column';

    		options.chartOptions = options.chartOptions || {};
    		options.chartOptions.chart = options.chartOptions.chart || {};
    		options.chartOptions.chart.type = 'column';

    		if (!this._highcharts[options.selector]) {
    			// Store new chart in charts array
    			this._highcharts[options.selector] = new Highchart(this, options);
    		}

    		return this._highcharts[options.selector];
    	},

    	/**
    	 * Chart via defined params and an options object.
    	 * @func columnChart
    	 * @memberof Highchart
    	 * @param {String|jQuery} selector The element to render the chart to.
    	 * @param {String} seriesField The name of the series to plot.
    	 * @param {String} keyField The field to use as the data key.
    	 * @param {String} valField The field to use as the data value.
    	 * @param {Object} options The options object.
    	 */
    	'*, string, string, string, ...': function (selector, seriesField, keyField, valField, options) {
    		options = options || {};

    		options.seriesField = seriesField;
    		options.selector = selector;
    		options.keyField = keyField;
    		options.valField = valField;

    		// Call the main chart method
    		this.columnChart(options);
    	}
    });

    /**
     * Creates a bar chart from the collection.
     * @type {Overload}
     */
    Collection.prototype.barChart = new Overload({
    	/**
    	 * Chart via options object.
    	 * @func barChart
    	 * @memberof Highchart
    	 * @param {Object} options The options object.
    	 * @returns {*}
    	 */
    	'object': function (options) {
    		options.type = 'bar';

    		options.chartOptions = options.chartOptions || {};
    		options.chartOptions.chart = options.chartOptions.chart || {};
    		options.chartOptions.chart.type = 'bar';

    		if (!this._highcharts[options.selector]) {
    			// Store new chart in charts array
    			this._highcharts[options.selector] = new Highchart(this, options);
    		}

    		return this._highcharts[options.selector];
    	},

    	/**
    	 * Chart via defined params and an options object.
    	 * @func barChart
    	 * @memberof Highchart
    	 * @param {String|jQuery} selector The element to render the chart to.
    	 * @param {String} seriesField The name of the series to plot.
    	 * @param {String} keyField The field to use as the data key.
    	 * @param {String} valField The field to use as the data value.
    	 * @param {Object} options The options object.
    	 */
    	'*, string, string, string, ...': function (selector, seriesField, keyField, valField, options) {
    		options = options || {};

    		options.seriesField = seriesField;
    		options.selector = selector;
    		options.keyField = keyField;
    		options.valField = valField;

    		// Call the main chart method
    		this.barChart(options);
    	}
    });

    /**
     * Creates a stacked bar chart from the collection.
     * @type {Overload}
     */
    Collection.prototype.stackedBarChart = new Overload({
    	/**
    	 * Chart via options object.
    	 * @func stackedBarChart
    	 * @memberof Highchart
    	 * @param {Object} options The options object.
    	 * @returns {*}
    	 */
    	'object': function (options) {
    		options.type = 'bar';

    		options.chartOptions = options.chartOptions || {};
    		options.chartOptions.chart = options.chartOptions.chart || {};
    		options.chartOptions.chart.type = 'bar';

    		options.plotOptions = options.plotOptions || {};
    		options.plotOptions.series = options.plotOptions.series || {};
    		options.plotOptions.series.stacking = options.plotOptions.series.stacking || 'normal';

    		if (!this._highcharts[options.selector]) {
    			// Store new chart in charts array
    			this._highcharts[options.selector] = new Highchart(this, options);
    		}

    		return this._highcharts[options.selector];
    	},

    	/**
    	 * Chart via defined params and an options object.
    	 * @func stackedBarChart
    	 * @memberof Highchart
    	 * @param {String|jQuery} selector The element to render the chart to.
    	 * @param {String} seriesField The name of the series to plot.
    	 * @param {String} keyField The field to use as the data key.
    	 * @param {String} valField The field to use as the data value.
    	 * @param {Object} options The options object.
    	 */
    	'*, string, string, string, ...': function (selector, seriesField, keyField, valField, options) {
    		options = options || {};

    		options.seriesField = seriesField;
    		options.selector = selector;
    		options.keyField = keyField;
    		options.valField = valField;

    		// Call the main chart method
    		this.stackedBarChart(options);
    	}
    });

    /**
     * Removes a chart from the page by it's selector.
     * @memberof Collection
     * @param {String} selector The chart selector.
     */
    Collection.prototype.dropChart = function (selector) {
    	if (this._highcharts && this._highcharts[selector]) {
    		this._highcharts[selector].drop();
    	}
    };

    Shared.finishModule('Highchart');
    module.exports = Highchart;
    },{"./Overload":32,"./Shared":40}],15:[function(_dereq_,module,exports){
    "use strict";

    /*
    name(string)
    id(string)
    rebuild(null)
    state ?? needed?
    match(query, options)
    lookup(query, options)
    insert(doc)
    remove(doc)
    primaryKey(string)
    collection(collection)
    */

    var Shared = _dereq_('./Shared'),
    	Path = _dereq_('./Path'),
    	BinaryTree = _dereq_('./BinaryTree'),
    	GeoHash = _dereq_('./GeoHash'),
    	sharedPathSolver = new Path(),
    	sharedGeoHashSolver = new GeoHash(),
    	// GeoHash Distances in Kilometers
    	geoHashDistance = [
    		5000,
    		1250,
    		156,
    		39.1,
    		4.89,
    		1.22,
    		0.153,
    		0.0382,
    		0.00477,
    		0.00119,
    		0.000149,
    		0.0000372
    	];

    /**
     * The index class used to instantiate 2d indexes that the database can
     * use to handle high-performance geospatial queries.
     * @constructor
     */
    var Index2d = function () {
    	this.init.apply(this, arguments);
    };

    /**
     * Create the index.
     * @param {Object} keys The object with the keys that the user wishes the index
     * to operate on.
     * @param {Object} options Can be undefined, if passed is an object with arbitrary
     * options keys and values.
     * @param {Collection} collection The collection the index should be created for.
     */
    Index2d.prototype.init = function (keys, options, collection) {
    	this._btree = new BinaryTree();
    	this._btree.index(keys);
    	this._size = 0;
    	this._id = this._itemKeyHash(keys, keys);
    	this._debug = options && options.debug ? options.debug : false;

    	this.unique(options && options.unique ? options.unique : false);

    	Eif (keys !== undefined) {
    		this.keys(keys);
    	}

    	Eif (collection !== undefined) {
    		this.collection(collection);
    		this._btree.primaryKey(collection.primaryKey());
    	}

    	this.name(options && options.name ? options.name : this._id);
    	this._btree.debug(this._debug);
    };

    Shared.addModule('Index2d', Index2d);
    Shared.mixin(Index2d.prototype, 'Mixin.Common');
    Shared.mixin(Index2d.prototype, 'Mixin.ChainReactor');
    Shared.mixin(Index2d.prototype, 'Mixin.Sorting');

    Index2d.prototype.id = function () {
    	return this._id;
    };

    Index2d.prototype.state = function () {
    	return this._state;
    };

    Index2d.prototype.size = function () {
    	return this._size;
    };

    Shared.synthesize(Index2d.prototype, 'data');
    Shared.synthesize(Index2d.prototype, 'name');
    Shared.synthesize(Index2d.prototype, 'collection');
    Shared.synthesize(Index2d.prototype, 'type');
    Shared.synthesize(Index2d.prototype, 'unique');

    Index2d.prototype.keys = function (val) {
    	Eif (val !== undefined) {
    		this._keys = val;

    		// Count the keys
    		this._keyCount = sharedPathSolver.parse(this._keys).length;
    		return this;
    	}

    	return this._keys;
    };

    Index2d.prototype.rebuild = function () {
    	// Do we have a collection?
    	Eif (this._collection) {
    		// Get sorted data
    		var collection = this._collection.subset({}, {
    				$decouple: false,
    				$orderBy: this._keys
    			}),
    			collectionData = collection.find(),
    			dataIndex,
    			dataCount = collectionData.length;

    		// Clear the index data for the index
    		this._btree.clear();
    		this._size = 0;

    		Iif (this._unique) {
    			this._uniqueLookup = {};
    		}

    		// Loop the collection data
    		for (dataIndex = 0; dataIndex < dataCount; dataIndex++) {
    			this.insert(collectionData[dataIndex]);
    		}
    	}

    	this._state = {
    		name: this._name,
    		keys: this._keys,
    		indexSize: this._size,
    		built: new Date(),
    		updated: new Date(),
    		ok: true
    	};
    };

    Index2d.prototype.insert = function (dataItem, options) {
    	var uniqueFlag = this._unique,
    		uniqueHash;

    	dataItem = this.decouple(dataItem);

    	Iif (uniqueFlag) {
    		uniqueHash = this._itemHash(dataItem, this._keys);
    		this._uniqueLookup[uniqueHash] = dataItem;
    	}

    	// Convert 2d indexed values to geohashes
    	var keys = this._btree.keys(),
    		pathVal,
    		geoHash,
    		lng,
    		lat,
    		i;

    	for (i = 0; i < keys.length; i++) {
    		pathVal = sharedPathSolver.get(dataItem, keys[i].path);

    		Eif (pathVal instanceof Array) {
    			lng = pathVal[0];
    			lat = pathVal[1];

    			geoHash = sharedGeoHashSolver.encode(lng, lat);

    			sharedPathSolver.set(dataItem, keys[i].path, geoHash);
    		}
    	}

    	Eif (this._btree.insert(dataItem)) {
    		this._size++;

    		return true;
    	}

    	return false;
    };

    Index2d.prototype.remove = function (dataItem, options) {
    	var uniqueFlag = this._unique,
    		uniqueHash;

    	if (uniqueFlag) {
    		uniqueHash = this._itemHash(dataItem, this._keys);
    		delete this._uniqueLookup[uniqueHash];
    	}

    	if (this._btree.remove(dataItem)) {
    		this._size--;

    		return true;
    	}

    	return false;
    };

    Index2d.prototype.violation = function (dataItem) {
    	// Generate item hash
    	var uniqueHash = this._itemHash(dataItem, this._keys);

    	// Check if the item breaks the unique constraint
    	return Boolean(this._uniqueLookup[uniqueHash]);
    };

    Index2d.prototype.hashViolation = function (uniqueHash) {
    	// Check if the item breaks the unique constraint
    	return Boolean(this._uniqueLookup[uniqueHash]);
    };

    Index2d.prototype.lookup = function (query, options) {
    	// Loop the indexed keys and determine if the query has any operators
    	// that we want to handle differently from a standard lookup
    	var keys = this._btree.keys(),
    		pathStr,
    		pathVal,
    		results,
    		i;

    	for (i = 0; i < keys.length; i++) {
    		pathStr = keys[i].path;
    		pathVal = sharedPathSolver.get(query, pathStr);

    		Eif (typeof pathVal === 'object') {
    			Eif (pathVal.$near) {
    				results = [];

    				// Do a near point lookup
    				results = results.concat(this.near(pathStr, pathVal.$near, options));
    			}

    			Iif (pathVal.$geoWithin) {
    				results = [];

    				// Do a geoWithin shape lookup
    				results = results.concat(this.geoWithin(pathStr, pathVal.$geoWithin, options));
    			}

    			return results;
    		}
    	}

    	return this._btree.lookup(query, options);
    };

    Index2d.prototype.near = function (pathStr, query, options) {
    	var self = this,
    		geoHash,
    		neighbours,
    		visited,
    		search,
    		results,
    		finalResults = [],
    		precision,
    		maxDistanceKm,
    		distance,
    		distCache,
    		latLng,
    		pk = this._collection.primaryKey(),
    		i;

    	// Calculate the required precision to encapsulate the distance
    	// TODO: Instead of opting for the "one size larger" than the distance boxes,
    	// TODO: we should calculate closest divisible box size as a multiple and then
    	// TODO: scan neighbours until we have covered the area otherwise we risk
    	// TODO: opening the results up to vastly more information as the box size
    	// TODO: increases dramatically between the geohash precisions
    	Iif (query.$distanceUnits === 'km') {
    		maxDistanceKm = query.$maxDistance;

    		for (i = 0; i < geoHashDistance.length; i++) {
    			if (maxDistanceKm > geoHashDistance[i]) {
    				precision = i;
    				break;
    			}
    		}

    		if (precision === 0) {
    			precision = 1;
    		}
    	} else Eif (query.$distanceUnits === 'miles') {
    		maxDistanceKm = query.$maxDistance * 1.60934;

    		for (i = 0; i < geoHashDistance.length; i++) {
    			if (maxDistanceKm > geoHashDistance[i]) {
    				precision = i;
    				break;
    			}
    		}

    		Iif (precision === 0) {
    			precision = 1;
    		}
    	}

    	// Get the lngLat geohash from the query
    	geoHash = sharedGeoHashSolver.encode(query.$point[0], query.$point[1], precision);

    	// Calculate 9 box geohashes
    	neighbours = sharedGeoHashSolver.calculateNeighbours(geoHash, {type: 'array'});

    	// Lookup all matching co-ordinates from the btree
    	results = [];
    	visited = 0;

    	for (i = 0; i < 9; i++) {
    		search = this._btree.startsWith(pathStr, neighbours[i]);
    		visited += search._visited;
    		results = results.concat(search);
    	}

    	// Work with original data
    	results = this._collection._primaryIndex.lookup(results);

    	Eif (results.length) {
    		distance = {};

    		// Loop the results and calculate distance
    		for (i = 0; i < results.length; i++) {
    			latLng = sharedPathSolver.get(results[i], pathStr);
    			distCache = distance[results[i][pk]] = this.distanceBetweenPoints(query.$point[0], query.$point[1], latLng[0], latLng[1]);

    			Eif (distCache <= maxDistanceKm) {
    				// Add item inside radius distance
    				finalResults.push(results[i]);
    			}
    		}

    		// Sort by distance from center
    		finalResults.sort(function (a, b) {
    			return self.sortAsc(distance[a[pk]], distance[b[pk]]);
    		});
    	}

    	// Return data
    	return finalResults;
    };

    Index2d.prototype.geoWithin = function (pathStr, query, options) {
    	return [];
    };

    Index2d.prototype.distanceBetweenPoints = function (lat1, lng1, lat2, lng2) {
    	var R = 6371; // kilometres
    	var lat1Rad = this.toRadians(lat1);
    	var lat2Rad = this.toRadians(lat2);
    	var lat2MinusLat1Rad = this.toRadians(lat2-lat1);
    	var lng2MinusLng1Rad = this.toRadians(lng2-lng1);

    	var a = Math.sin(lat2MinusLat1Rad/2) * Math.sin(lat2MinusLat1Rad/2) +
    			Math.cos(lat1Rad) * Math.cos(lat2Rad) *
    			Math.sin(lng2MinusLng1Rad/2) * Math.sin(lng2MinusLng1Rad/2);

    	var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

    	return R * c;
    };

    Index2d.prototype.toRadians = function (degrees) {
    	return degrees * 0.01747722222222;
    };

    Index2d.prototype.match = function (query, options) {
    	// TODO: work out how to represent that this is a better match if the query has $near than
    	// TODO: a basic btree index which will not be able to resolve a $near operator
    	return this._btree.match(query, options);
    };

    Index2d.prototype._itemHash = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		hash = '',
    		k;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		if (hash) { hash += '_'; }
    		hash += path.value(item, pathData[k].path).join(':');
    	}

    	return hash;
    };

    Index2d.prototype._itemKeyHash = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		hash = '',
    		k;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		Iif (hash) { hash += '_'; }
    		hash += path.keyValue(item, pathData[k].path);
    	}

    	return hash;
    };

    Index2d.prototype._itemHashArr = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		//hash = '',
    		hashArr = [],
    		valArr,
    		i, k, j;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		valArr = path.value(item, pathData[k].path);

    		for (i = 0; i < valArr.length; i++) {
    			if (k === 0) {
    				// Setup the initial hash array
    				hashArr.push(valArr[i]);
    			} else {
    				// Loop the hash array and concat the value to it
    				for (j = 0; j < hashArr.length; j++) {
    					hashArr[j] = hashArr[j] + '_' + valArr[i];
    				}
    			}
    		}
    	}

    	return hashArr;
    };

    // Register this index on the shared object
    Shared.index['2d'] = Index2d;

    Shared.finishModule('Index2d');
    module.exports = Index2d;
    },{"./BinaryTree":5,"./GeoHash":12,"./Path":34,"./Shared":40}],16:[function(_dereq_,module,exports){
    "use strict";

    /*
    name(string)
    id(string)
    rebuild(null)
    state ?? needed?
    match(query, options)
    lookup(query, options)
    insert(doc)
    remove(doc)
    primaryKey(string)
    collection(collection)
    */

    var Shared = _dereq_('./Shared'),
    	Path = _dereq_('./Path'),
    	BinaryTree = _dereq_('./BinaryTree');

    /**
     * The index class used to instantiate btree indexes that the database can
     * use to speed up queries on collections and views.
     * @constructor
     */
    var IndexBinaryTree = function () {
    	this.init.apply(this, arguments);
    };

    IndexBinaryTree.prototype.init = function (keys, options, collection) {
    	this._btree = new BinaryTree();
    	this._btree.index(keys);
    	this._size = 0;
    	this._id = this._itemKeyHash(keys, keys);
    	this._debug = options && options.debug ? options.debug : false;

    	this.unique(options && options.unique ? options.unique : false);

    	Eif (keys !== undefined) {
    		this.keys(keys);
    	}

    	Eif (collection !== undefined) {
    		this.collection(collection);
    		this._btree.primaryKey(collection.primaryKey());
    	}

    	this.name(options && options.name ? options.name : this._id);
    	this._btree.debug(this._debug);
    };

    Shared.addModule('IndexBinaryTree', IndexBinaryTree);
    Shared.mixin(IndexBinaryTree.prototype, 'Mixin.ChainReactor');
    Shared.mixin(IndexBinaryTree.prototype, 'Mixin.Sorting');

    IndexBinaryTree.prototype.id = function () {
    	return this._id;
    };

    IndexBinaryTree.prototype.state = function () {
    	return this._state;
    };

    IndexBinaryTree.prototype.size = function () {
    	return this._size;
    };

    Shared.synthesize(IndexBinaryTree.prototype, 'data');
    Shared.synthesize(IndexBinaryTree.prototype, 'name');
    Shared.synthesize(IndexBinaryTree.prototype, 'collection');
    Shared.synthesize(IndexBinaryTree.prototype, 'type');
    Shared.synthesize(IndexBinaryTree.prototype, 'unique');

    IndexBinaryTree.prototype.keys = function (val) {
    	Eif (val !== undefined) {
    		this._keys = val;

    		// Count the keys
    		this._keyCount = (new Path()).parse(this._keys).length;
    		return this;
    	}

    	return this._keys;
    };

    IndexBinaryTree.prototype.rebuild = function () {
    	// Do we have a collection?
    	Eif (this._collection) {
    		// Get sorted data
    		var collection = this._collection.subset({}, {
    				$decouple: false,
    				$orderBy: this._keys
    			}),
    			collectionData = collection.find(),
    			dataIndex,
    			dataCount = collectionData.length;

    		// Clear the index data for the index
    		this._btree.clear();
    		this._size = 0;

    		if (this._unique) {
    			this._uniqueLookup = {};
    		}

    		// Loop the collection data
    		for (dataIndex = 0; dataIndex < dataCount; dataIndex++) {
    			this.insert(collectionData[dataIndex]);
    		}
    	}

    	this._state = {
    		name: this._name,
    		keys: this._keys,
    		indexSize: this._size,
    		built: new Date(),
    		updated: new Date(),
    		ok: true
    	};
    };

    IndexBinaryTree.prototype.insert = function (dataItem, options) {
    	var uniqueFlag = this._unique,
    		uniqueHash;

    	if (uniqueFlag) {
    		uniqueHash = this._itemHash(dataItem, this._keys);
    		this._uniqueLookup[uniqueHash] = dataItem;
    	}

    	Eif (this._btree.insert(dataItem)) {
    		this._size++;

    		return true;
    	}

    	return false;
    };

    IndexBinaryTree.prototype.remove = function (dataItem, options) {
    	var uniqueFlag = this._unique,
    		uniqueHash;

    	Eif (uniqueFlag) {
    		uniqueHash = this._itemHash(dataItem, this._keys);
    		delete this._uniqueLookup[uniqueHash];
    	}

    	Eif (this._btree.remove(dataItem)) {
    		this._size--;

    		return true;
    	}

    	return false;
    };

    IndexBinaryTree.prototype.violation = function (dataItem) {
    	// Generate item hash
    	var uniqueHash = this._itemHash(dataItem, this._keys);

    	// Check if the item breaks the unique constraint
    	return Boolean(this._uniqueLookup[uniqueHash]);
    };

    IndexBinaryTree.prototype.hashViolation = function (uniqueHash) {
    	// Check if the item breaks the unique constraint
    	return Boolean(this._uniqueLookup[uniqueHash]);
    };

    IndexBinaryTree.prototype.lookup = function (query, options) {
    	return this._btree.lookup(query, options);
    };

    IndexBinaryTree.prototype.match = function (query, options) {
    	return this._btree.match(query, options);
    };

    IndexBinaryTree.prototype._itemHash = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		hash = '',
    		k;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		if (hash) { hash += '_'; }
    		hash += path.value(item, pathData[k].path).join(':');
    	}

    	return hash;
    };

    IndexBinaryTree.prototype._itemKeyHash = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		hash = '',
    		k;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		if (hash) { hash += '_'; }
    		hash += path.keyValue(item, pathData[k].path);
    	}

    	return hash;
    };

    IndexBinaryTree.prototype._itemHashArr = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		//hash = '',
    		hashArr = [],
    		valArr,
    		i, k, j;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		valArr = path.value(item, pathData[k].path);

    		for (i = 0; i < valArr.length; i++) {
    			if (k === 0) {
    				// Setup the initial hash array
    				hashArr.push(valArr[i]);
    			} else {
    				// Loop the hash array and concat the value to it
    				for (j = 0; j < hashArr.length; j++) {
    					hashArr[j] = hashArr[j] + '_' + valArr[i];
    				}
    			}
    		}
    	}

    	return hashArr;
    };

    // Register this index on the shared object
    Shared.index.btree = IndexBinaryTree;

    Shared.finishModule('IndexBinaryTree');
    module.exports = IndexBinaryTree;
    },{"./BinaryTree":5,"./Path":34,"./Shared":40}],17:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared'),
    	Path = _dereq_('./Path');

    /**
     * The index class used to instantiate hash map indexes that the database can
     * use to speed up queries on collections and views.
     * @constructor
     */
    var IndexHashMap = function () {
    	this.init.apply(this, arguments);
    };

    IndexHashMap.prototype.init = function (keys, options, collection) {
    	this._crossRef = {};
    	this._size = 0;
    	this._id = this._itemKeyHash(keys, keys);

    	this.data({});
    	this.unique(options && options.unique ? options.unique : false);

    	Eif (keys !== undefined) {
    		this.keys(keys);
    	}

    	Eif (collection !== undefined) {
    		this.collection(collection);
    	}

    	this.name(options && options.name ? options.name : this._id);
    };

    Shared.addModule('IndexHashMap', IndexHashMap);
    Shared.mixin(IndexHashMap.prototype, 'Mixin.ChainReactor');

    IndexHashMap.prototype.id = function () {
    	return this._id;
    };

    IndexHashMap.prototype.state = function () {
    	return this._state;
    };

    IndexHashMap.prototype.size = function () {
    	return this._size;
    };

    Shared.synthesize(IndexHashMap.prototype, 'data');
    Shared.synthesize(IndexHashMap.prototype, 'name');
    Shared.synthesize(IndexHashMap.prototype, 'collection');
    Shared.synthesize(IndexHashMap.prototype, 'type');
    Shared.synthesize(IndexHashMap.prototype, 'unique');

    IndexHashMap.prototype.keys = function (val) {
    	Eif (val !== undefined) {
    		this._keys = val;

    		// Count the keys
    		this._keyCount = (new Path()).parse(this._keys).length;
    		return this;
    	}

    	return this._keys;
    };

    IndexHashMap.prototype.rebuild = function () {
    	// Do we have a collection?
    	Eif (this._collection) {
    		// Get sorted data
    		var collection = this._collection.subset({}, {
    				$decouple: false,
    				$orderBy: this._keys
    			}),
    			collectionData = collection.find(),
    			dataIndex,
    			dataCount = collectionData.length;

    		// Clear the index data for the index
    		this._data = {};
    		this._size = 0;

    		if (this._unique) {
    			this._uniqueLookup = {};
    		}

    		// Loop the collection data
    		for (dataIndex = 0; dataIndex < dataCount; dataIndex++) {
    			this.insert(collectionData[dataIndex]);
    		}
    	}

    	this._state = {
    		name: this._name,
    		keys: this._keys,
    		indexSize: this._size,
    		built: new Date(),
    		updated: new Date(),
    		ok: true
    	};
    };

    IndexHashMap.prototype.insert = function (dataItem, options) {
    	var uniqueFlag = this._unique,
    		uniqueHash,
    		itemHashArr,
    		hashIndex;

    	if (uniqueFlag) {
    		uniqueHash = this._itemHash(dataItem, this._keys);
    		this._uniqueLookup[uniqueHash] = dataItem;
    	}

    	// Generate item hash
    	itemHashArr = this._itemHashArr(dataItem, this._keys);

    	// Get the path search results and store them
    	for (hashIndex = 0; hashIndex < itemHashArr.length; hashIndex++) {
    		this.pushToPathValue(itemHashArr[hashIndex], dataItem);
    	}
    };

    IndexHashMap.prototype.update = function (dataItem, options) {
    	// TODO: Write updates to work
    	// 1: Get uniqueHash for the dataItem primary key value (may need to generate a store for this)
    	// 2: Remove the uniqueHash as it currently stands
    	// 3: Generate a new uniqueHash for dataItem
    	// 4: Insert the new uniqueHash
    };

    IndexHashMap.prototype.remove = function (dataItem, options) {
    	var uniqueFlag = this._unique,
    		uniqueHash,
    		itemHashArr,
    		hashIndex;

    	Eif (uniqueFlag) {
    		uniqueHash = this._itemHash(dataItem, this._keys);
    		delete this._uniqueLookup[uniqueHash];
    	}

    	// Generate item hash
    	itemHashArr = this._itemHashArr(dataItem, this._keys);

    	// Get the path search results and store them
    	for (hashIndex = 0; hashIndex < itemHashArr.length; hashIndex++) {
    		this.pullFromPathValue(itemHashArr[hashIndex], dataItem);
    	}
    };

    IndexHashMap.prototype.violation = function (dataItem) {
    	// Generate item hash
    	var uniqueHash = this._itemHash(dataItem, this._keys);

    	// Check if the item breaks the unique constraint
    	return Boolean(this._uniqueLookup[uniqueHash]);
    };

    IndexHashMap.prototype.hashViolation = function (uniqueHash) {
    	// Check if the item breaks the unique constraint
    	return Boolean(this._uniqueLookup[uniqueHash]);
    };

    IndexHashMap.prototype.pushToPathValue = function (hash, obj) {
    	var pathValArr = this._data[hash] = this._data[hash] || [];

    	// Make sure we have not already indexed this object at this path/value
    	Eif (pathValArr.indexOf(obj) === -1) {
    		// Index the object
    		pathValArr.push(obj);

    		// Record the reference to this object in our index size
    		this._size++;

    		// Cross-reference this association for later lookup
    		this.pushToCrossRef(obj, pathValArr);
    	}
    };

    IndexHashMap.prototype.pullFromPathValue = function (hash, obj) {
    	var pathValArr = this._data[hash],
    		indexOfObject;

    	// Make sure we have already indexed this object at this path/value
    	indexOfObject = pathValArr.indexOf(obj);

    	Eif (indexOfObject > -1) {
    		// Un-index the object
    		pathValArr.splice(indexOfObject, 1);

    		// Record the reference to this object in our index size
    		this._size--;

    		// Remove object cross-reference
    		this.pullFromCrossRef(obj, pathValArr);
    	}

    	// Check if we should remove the path value array
    	Eif (!pathValArr.length) {
    		// Remove the array
    		delete this._data[hash];
    	}
    };

    IndexHashMap.prototype.pull = function (obj) {
    	// Get all places the object has been used and remove them
    	var id = obj[this._collection.primaryKey()],
    		crossRefArr = this._crossRef[id],
    		arrIndex,
    		arrCount = crossRefArr.length,
    		arrItem;

    	for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    		arrItem = crossRefArr[arrIndex];

    		// Remove item from this index lookup array
    		this._pullFromArray(arrItem, obj);
    	}

    	// Record the reference to this object in our index size
    	this._size--;

    	// Now remove the cross-reference entry for this object
    	delete this._crossRef[id];
    };

    IndexHashMap.prototype._pullFromArray = function (arr, obj) {
    	var arrCount = arr.length;

    	while (arrCount--) {
    		if (arr[arrCount] === obj) {
    			arr.splice(arrCount, 1);
    		}
    	}
    };

    IndexHashMap.prototype.pushToCrossRef = function (obj, pathValArr) {
    	var id = obj[this._collection.primaryKey()],
    		crObj;

    	this._crossRef[id] = this._crossRef[id] || [];

    	// Check if the cross-reference to the pathVal array already exists
    	crObj = this._crossRef[id];

    	Eif (crObj.indexOf(pathValArr) === -1) {
    		// Add the cross-reference
    		crObj.push(pathValArr);
    	}
    };

    IndexHashMap.prototype.pullFromCrossRef = function (obj, pathValArr) {
    	var id = obj[this._collection.primaryKey()];

    	delete this._crossRef[id];
    };

    IndexHashMap.prototype.lookup = function (query) {
    	return this._data[this._itemHash(query, this._keys)] || [];
    };

    IndexHashMap.prototype.match = function (query, options) {
    	// Check if the passed query has data in the keys our index
    	// operates on and if so, is the query sort matching our order
    	var pathSolver = new Path();
    	var indexKeyArr = pathSolver.parseArr(this._keys),
    		queryArr = pathSolver.parseArr(query),
    		matchedKeys = [],
    		matchedKeyCount = 0,
    		i;

    	// Loop the query array and check the order of keys against the
    	// index key array to see if this index can be used
    	for (i = 0; i < indexKeyArr.length; i++) {
    		if (queryArr[i] === indexKeyArr[i]) {
    			matchedKeyCount++;
    			matchedKeys.push(queryArr[i]);
    		} else {
    			// Query match failed - this is a hash map index so partial key match won't work
    			return {
    				matchedKeys: [],
    				totalKeyCount: queryArr.length,
    				score: 0
    			};
    		}
    	}

    	return {
    		matchedKeys: matchedKeys,
    		totalKeyCount: queryArr.length,
    		score: matchedKeyCount
    	};

    	//return pathSolver.countObjectPaths(this._keys, query);
    };

    IndexHashMap.prototype._itemHash = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		hash = '',
    		k;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		if (hash) { hash += '_'; }
    		hash += path.value(item, pathData[k].path).join(':');
    	}

    	return hash;
    };

    IndexHashMap.prototype._itemKeyHash = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		hash = '',
    		k;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		if (hash) { hash += '_'; }
    		hash += path.keyValue(item, pathData[k].path);
    	}

    	return hash;
    };

    IndexHashMap.prototype._itemHashArr = function (item, keys) {
    	var path = new Path(),
    		pathData,
    		//hash = '',
    		hashArr = [],
    		valArr,
    		i, k, j;

    	pathData = path.parse(keys);

    	for (k = 0; k < pathData.length; k++) {
    		valArr = path.value(item, pathData[k].path);

    		for (i = 0; i < valArr.length; i++) {
    			if (k === 0) {
    				// Setup the initial hash array
    				hashArr.push(valArr[i]);
    			} else {
    				// Loop the hash array and concat the value to it
    				for (j = 0; j < hashArr.length; j++) {
    					hashArr[j] = hashArr[j] + '_' + valArr[i];
    				}
    			}
    		}
    	}

    	return hashArr;
    };

    // Register this index on the shared object
    Shared.index.hashed = IndexHashMap;

    Shared.finishModule('IndexHashMap');
    module.exports = IndexHashMap;
    },{"./Path":34,"./Shared":40}],18:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared');

    /**
     * The key value store class used when storing basic in-memory KV data,
     * and can be queried for quick retrieval. Mostly used for collection
     * primary key indexes and lookups.
     * @param {String=} name Optional KV store name.
     * @constructor
     */
    var KeyValueStore = function (name) {
    	this.init.apply(this, arguments);
    };

    KeyValueStore.prototype.init = function (name) {
    	this._name = name;
    	this._data = {};
    	this._primaryKey = '_id';
    };

    Shared.addModule('KeyValueStore', KeyValueStore);
    Shared.mixin(KeyValueStore.prototype, 'Mixin.ChainReactor');

    /**
     * Get / set the name of the key/value store.
     * @param {String} val The name to set.
     * @returns {*}
     */
    Shared.synthesize(KeyValueStore.prototype, 'name');

    /**
     * Get / set the primary key.
     * @param {String} key The key to set.
     * @returns {*}
     */
    KeyValueStore.prototype.primaryKey = function (key) {
    	Eif (key !== undefined) {
    		this._primaryKey = key;
    		return this;
    	}

    	return this._primaryKey;
    };

    /**
     * Removes all data from the store.
     * @returns {*}
     */
    KeyValueStore.prototype.truncate = function () {
    	this._data = {};
    	return this;
    };

    /**
     * Sets data against a key in the store.
     * @param {String} key The key to set data for.
     * @param {*} value The value to assign to the key.
     * @returns {*}
     */
    KeyValueStore.prototype.set = function (key, value) {
    	this._data[key] = value ? value : true;
    	return this;
    };

    /**
     * Gets data stored for the passed key.
     * @param {String} key The key to get data for.
     * @returns {*}
     */
    KeyValueStore.prototype.get = function (key) {
    	return this._data[key];
    };

    /**
     * Get / set the primary key.
     * @param {*} val A lookup query.
     * @returns {*}
     */
    KeyValueStore.prototype.lookup = function (val) {
    	var pk = this._primaryKey,
    		valType = typeof val,
    		arrIndex,
    		arrCount,
    		lookupItem,
    		result = [];

    	// Check for early exit conditions
    	if (valType === 'string' || valType === 'number') {
    		lookupItem = this.get(val);
    		if (lookupItem !== undefined) {
    			return [lookupItem];
    		} else {
    			return [];
    		}
    	} else Eif (valType === 'object') {
    		if (val instanceof Array) {
    			// An array of primary keys, find all matches
    			arrCount = val.length;
    			result = [];

    			for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    				lookupItem = this.lookup(val[arrIndex]);

    				Eif (lookupItem) {
    					Eif (lookupItem instanceof Array) {
    						result = result.concat(lookupItem);
    					} else {
    						result.push(lookupItem);
    					}
    				}
    			}

    			return result;
    		} else Eif (val[pk]) {
    			return this.lookup(val[pk]);
    		}
    	}

    	// COMMENTED AS CODE WILL NEVER BE REACHED
    	// Complex lookup
    	/*lookupData = this._lookupKeys(val);
    	keys = lookupData.keys;
    	negate = lookupData.negate;

    	if (!negate) {
    		// Loop keys and return values
    		for (arrIndex = 0; arrIndex < keys.length; arrIndex++) {
    			result.push(this.get(keys[arrIndex]));
    		}
    	} else {
    		// Loop data and return non-matching keys
    		for (arrIndex in this._data) {
    			if (this._data.hasOwnProperty(arrIndex)) {
    				if (keys.indexOf(arrIndex) === -1) {
    					result.push(this.get(arrIndex));
    				}
    			}
    		}
    	}

    	return result;*/
    };

    // COMMENTED AS WE ARE NOT CURRENTLY PASSING COMPLEX QUERIES TO KEYVALUESTORE INDEXES
    /*KeyValueStore.prototype._lookupKeys = function (val) {
    	var pk = this._primaryKey,
    		valType = typeof val,
    		arrIndex,
    		arrCount,
    		lookupItem,
    		bool,
    		result;

    	if (valType === 'string' || valType === 'number') {
    		return {
    			keys: [val],
    			negate: false
    		};
    	} else if (valType === 'object') {
    		if (val instanceof RegExp) {
    			// Create new data
    			result = [];

    			for (arrIndex in this._data) {
    				if (this._data.hasOwnProperty(arrIndex)) {
    					if (val.test(arrIndex)) {
    						result.push(arrIndex);
    					}
    				}
    			}

    			return {
    				keys: result,
    				negate: false
    			};
    		} else if (val instanceof Array) {
    			// An array of primary keys, find all matches
    			arrCount = val.length;
    			result = [];

    			for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    				result = result.concat(this._lookupKeys(val[arrIndex]).keys);
    			}

    			return {
    				keys: result,
    				negate: false
    			};
    		} else if (val.$in && (val.$in instanceof Array)) {
    			return {
    				keys: this._lookupKeys(val.$in).keys,
    				negate: false
    			};
    		} else if (val.$nin && (val.$nin instanceof Array)) {
    			return {
    				keys: this._lookupKeys(val.$nin).keys,
    				negate: true
    			};
    		} else if (val.$ne) {
    			return {
    				keys: this._lookupKeys(val.$ne, true).keys,
    				negate: true
    			};
    		} else if (val.$or && (val.$or instanceof Array)) {
    			// Create new data
    			result = [];

    			for (arrIndex = 0; arrIndex < val.$or.length; arrIndex++) {
    				result = result.concat(this._lookupKeys(val.$or[arrIndex]).keys);
    			}

    			return {
    				keys: result,
    				negate: false
    			};
    		} else if (val[pk]) {
    			return this._lookupKeys(val[pk]);
    		}
    	}
    };*/

    /**
     * Removes data for the given key from the store.
     * @param {String} key The key to un-set.
     * @returns {*}
     */
    KeyValueStore.prototype.unSet = function (key) {
    	delete this._data[key];
    	return this;
    };

    /**
     * Sets data for the give key in the store only where the given key
     * does not already have a value in the store.
     * @param {String} key The key to set data for.
     * @param {*} value The value to assign to the key.
     * @returns {Boolean} True if data was set or false if data already
     * exists for the key.
     */
    KeyValueStore.prototype.uniqueSet = function (key, value) {
    	Eif (this._data[key] === undefined) {
    		this._data[key] = value;
    		return true;
    	}

    	return false;
    };

    Shared.finishModule('KeyValueStore');
    module.exports = KeyValueStore;
    },{"./Shared":40}],19:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared'),
    	Operation = _dereq_('./Operation');

    /**
     * The metrics class used to store details about operations.
     * @constructor
     */
    var Metrics = function () {
    	this.init.apply(this, arguments);
    };

    Metrics.prototype.init = function () {
    	this._data = [];
    };

    Shared.addModule('Metrics', Metrics);
    Shared.mixin(Metrics.prototype, 'Mixin.ChainReactor');

    /**
     * Creates an operation within the metrics instance and if metrics
     * are currently enabled (by calling the start() method) the operation
     * is also stored in the metrics log.
     * @param {String} name The name of the operation.
     * @returns {Operation}
     */
    Metrics.prototype.create = function (name) {
    	var op = new Operation(name);

    	Iif (this._enabled) {
    		this._data.push(op);
    	}

    	return op;
    };

    /**
     * Starts logging operations.
     * @returns {Metrics}
     */
    Metrics.prototype.start = function () {
    	this._enabled = true;
    	return this;
    };

    /**
     * Stops logging operations.
     * @returns {Metrics}
     */
    Metrics.prototype.stop = function () {
    	this._enabled = false;
    	return this;
    };

    /**
     * Clears all logged operations.
     * @returns {Metrics}
     */
    Metrics.prototype.clear = function () {
    	this._data = [];
    	return this;
    };

    /**
     * Returns an array of all logged operations.
     * @returns {Array}
     */
    Metrics.prototype.list = function () {
    	return this._data;
    };

    Shared.finishModule('Metrics');
    module.exports = Metrics;
    },{"./Operation":31,"./Shared":40}],20:[function(_dereq_,module,exports){
    "use strict";

    var CRUD = {
    	preSetData: function () {

    	},

    	postSetData: function () {

    	}
    };

    module.exports = CRUD;
    },{}],21:[function(_dereq_,module,exports){
    "use strict";

    /**
     * The chain reactor mixin, provides methods to the target object that allow chain
     * reaction events to propagate to the target and be handled, processed and passed
     * on down the chain.
     * @mixin
     */
    var ChainReactor = {
    	/**
    	 * Creates a chain link between the current reactor node and the passed
    	 * reactor node. Chain packets that are send by this reactor node will
    	 * then be propagated to the passed node for subsequent packets.
    	 * @param {*} obj The chain reactor node to link to.
    	 */
    	chain: function (obj) {
    		if (this.debug && this.debug()) {
    			if (obj._reactorIn && obj._reactorOut) {
    				console.log(obj._reactorIn.logIdentifier() + ' Adding target "' + obj._reactorOut.instanceIdentifier() + '" to the chain reactor target list');
    			} else {
    				console.log(this.logIdentifier() + ' Adding target "' + obj.instanceIdentifier() + '" to the chain reactor target list');
    			}
    		}

    		this._chain = this._chain || [];
    		var index = this._chain.indexOf(obj);

    		Eif (index === -1) {
    			this._chain.push(obj);
    		}
    	},

    	/**
    	 * Removes a chain link between the current reactor node and the passed
    	 * reactor node. Chain packets sent from this reactor node will no longer
    	 * be received by the passed node.
    	 * @param {*} obj The chain reactor node to unlink from.
    	 */
    	unChain: function (obj) {
    		if (this.debug && this.debug()) {
    			if (obj._reactorIn && obj._reactorOut) {
    				console.log(obj._reactorIn.logIdentifier() + ' Removing target "' + obj._reactorOut.instanceIdentifier() + '" from the chain reactor target list');
    			} else {
    				console.log(this.logIdentifier() + ' Removing target "' + obj.instanceIdentifier() + '" from the chain reactor target list');
    			}
    		}

    		Eif (this._chain) {
    			var index = this._chain.indexOf(obj);

    			Eif (index > -1) {
    				this._chain.splice(index, 1);
    			}
    		}
    	},

    	/**
    	 * Determines if this chain reactor node has any listeners downstream.
    	 * @returns {Boolean} True if there are nodes downstream of this node.
    	 */
    	chainWillSend: function () {
    		return Boolean(this._chain);
    	},

    	/**
    	 * Sends a chain reactor packet downstream from this node to any of its
    	 * chained targets that were linked to this node via a call to chain().
    	 * @param {String} type The type of chain reactor packet to send. This
    	 * can be any string but the receiving reactor nodes will not react to
    	 * it unless they recognise the string. Built-in strings include: "insert",
    	 * "update", "remove", "setData" and "debug".
    	 * @param {Object} data A data object that usually contains a key called
    	 * "dataSet" which is an array of items to work on, and can contain other
    	 * custom keys that help describe the operation.
    	 * @param {Object=} options An options object. Can also contain custom
    	 * key/value pairs that your custom chain reactor code can operate on.
    	 */
    	chainSend: function (type, data, options) {
    		if (this._chain) {
    			var arr = this._chain,
    				arrItem,
    				count = arr.length,
    				index,
    				dataCopy = this.decouple(data, count);

    			for (index = 0; index < count; index++) {
    				arrItem = arr[index];

    				Eif (!arrItem._state || (arrItem._state && !arrItem.isDropped())) {
    					if (this.debug && this.debug()) {
    						if (arrItem._reactorIn && arrItem._reactorOut) {
    							console.log(arrItem._reactorIn.logIdentifier() + ' Sending data down the chain reactor pipe to "' + arrItem._reactorOut.instanceIdentifier() + '"');
    						} else {
    							console.log(this.logIdentifier() + ' Sending data down the chain reactor pipe to "' + arrItem.instanceIdentifier() + '"');
    						}
    					}

    					Eif (arrItem.chainReceive) {
    						arrItem.chainReceive(this, type, dataCopy[index], options);
    					}
    				} else {
    					console.log('Reactor Data:', type, data, options);
    					console.log('Reactor Node:', arrItem);
    					throw('Chain reactor attempting to send data to target reactor node that is in a dropped state!');
    				}

    			}
    		}
    	},

    	/**
    	 * Handles receiving a chain reactor message that was sent via the chainSend()
    	 * method. Creates the chain packet object and then allows it to be processed.
    	 * @param {Object} sender The node that is sending the packet.
    	 * @param {String} type The type of packet.
    	 * @param {Object} data The data related to the packet.
    	 * @param {Object=} options An options object.
    	 */
    	chainReceive: function (sender, type, data, options) {
    		var chainPacket = {
    				sender: sender,
    				type: type,
    				data: data,
    				options: options
    			},
    			cancelPropagate = false;

    		if (this.debug && this.debug()) {
    			console.log(this.logIdentifier() + ' Received data from parent reactor node');
    		}

    		// Check if we have a chain handler method
    		if (this._chainHandler) {
    			// Fire our internal handler
    			cancelPropagate = this._chainHandler(chainPacket);
    		}

    		// Check if we were told to cancel further propagation
    		if (!cancelPropagate) {
    			// Propagate the message down the chain
    			this.chainSend(chainPacket.type, chainPacket.data, chainPacket.options);
    		}
    	}
    };

    module.exports = ChainReactor;
    },{}],22:[function(_dereq_,module,exports){
    "use strict";

    var idCounter = 0,
    	Overload = _dereq_('./Overload'),
    	Serialiser = _dereq_('./Serialiser'),
    	Common,
    	serialiser = new Serialiser();

    /**
     * Provides commonly used methods to most classes in ForerunnerDB.
     * @mixin
     */
    Common = {
    	// Expose the serialiser object so it can be extended with new data handlers.
    	serialiser: serialiser,

    	/**
    	 * Generates a JSON serialisation-compatible object instance. After the
    	 * instance has been passed through this method, it will be able to survive
    	 * a JSON.stringify() and JSON.parse() cycle and still end up as an
    	 * instance at the end. Further information about this process can be found
    	 * in the ForerunnerDB wiki at: https://github.com/Irrelon/ForerunnerDB/wiki/Serialiser-&-Performance-Benchmarks
    	 * @param {*} val The object instance such as "new Date()" or "new RegExp()".
    	 */
    	make: function (val) {
    		// This is a conversion request, hand over to serialiser
    		return serialiser.convert(val);
    	},

    	/**
    	 * Gets / sets data in the item store. The store can be used to set and
    	 * retrieve data against a key. Useful for adding arbitrary key/value data
    	 * to a collection / view etc and retrieving it later.
    	 * @param {String|*} key The key under which to store the passed value or
    	 * retrieve the existing stored value.
    	 * @param {*=} val Optional value. If passed will overwrite the existing value
    	 * stored against the specified key if one currently exists.
    	 * @returns {*}
    	 */
    	store: function (key, val) {
    		if (key !== undefined) {
    			if (val !== undefined) {
    				// Store the data
    				this._store = this._store || {};
    				this._store[key] = val;

    				return this;
    			}

    			if (this._store) {
    				return this._store[key];
    			}
    		}

    		return undefined;
    	},

    	/**
    	 * Removes a previously stored key/value pair from the item store, set previously
    	 * by using the store() method.
    	 * @param {String|*} key The key of the key/value pair to remove;
    	 * @returns {Common} Returns this for chaining.
    	 */
    	unStore: function (key) {
    		if (key !== undefined) {
    			delete this._store[key];
    		}

    		return this;
    	},

    	/**
    	 * Returns a non-referenced version of the passed object / array.
    	 * @param {Object} data The object or array to return as a non-referenced version.
    	 * @param {Number=} copies Optional number of copies to produce. If specified, the return
    	 * value will be an array of decoupled objects, each distinct from the other.
    	 * @returns {*}
    	 */
    	decouple: function (data, copies) {
    		if (data !== undefined && data !== "") {
    			if (!copies) {
    				return this.jParse(this.jStringify(data));
    			} else {
    				var i,
    					json = this.jStringify(data),
    					copyArr = [];

    				for (i = 0; i < copies; i++) {
    					copyArr.push(this.jParse(json));
    				}

    				return copyArr;
    			}
    		}

    		return undefined;
    	},

    	/**
    	 * Parses and returns data from stringified version.
    	 * @param {String} data The stringified version of data to parse.
    	 * @returns {Object} The parsed JSON object from the data.
    	 */
    	jParse: function (data) {
    		return JSON.parse(data, serialiser.reviver());
    	},

    	/**
    	 * Converts a JSON object into a stringified version.
    	 * @param {Object} data The data to stringify.
    	 * @returns {String} The stringified data.
    	 */
    	jStringify: function (data) {
    		//return serialiser.stringify(data);
    		return JSON.stringify(data);
    	},

    	/**
    	 * Generates a new 16-character hexadecimal unique ID or
    	 * generates a new 16-character hexadecimal ID based on
    	 * the passed string. Will always generate the same ID
    	 * for the same string.
    	 * @param {String=} str A string to generate the ID from.
    	 * @return {String}
    	 */
    	objectId: function (str) {
    		var id,
    			pow = Math.pow(10, 17);

    		if (!str) {
    			idCounter++;

    			id = (idCounter + (
    				Math.random() * pow +
    				Math.random() * pow +
    				Math.random() * pow +
    				Math.random() * pow
    			)).toString(16);
    		} else {
    			var val = 0,
    				count = str.length,
    				i;

    			for (i = 0; i < count; i++) {
    				val += str.charCodeAt(i) * pow;
    			}

    			id = val.toString(16);
    		}

    		return id;
    	},

    	/**
    	 * Generates a unique hash for the passed object.
    	 * @param {Object} obj The object to generate a hash for.
    	 * @returns {String}
    	 */
    	hash: function (obj) {
    		return JSON.stringify(obj);
    	},

    	/**
    	 * Gets / sets debug flag that can enable debug message output to the
    	 * console if required.
    	 * @param {Boolean} val The value to set debug flag to.
    	 * @return {Boolean} True if enabled, false otherwise.
    	 */
    	/**
    	 * Sets debug flag for a particular type that can enable debug message
    	 * output to the console if required.
    	 * @param {String} type The name of the debug type to set flag for.
    	 * @param {Boolean} val The value to set debug flag to.
    	 * @return {Boolean} True if enabled, false otherwise.
    	 */
    	debug: new Overload([
    		function () {
    			return this._debug && this._debug.all;
    		},

    		function (val) {
    			if (val !== undefined) {
    				Eif (typeof val === 'boolean') {
    					this._debug = this._debug || {};
    					this._debug.all = val;
    					this.chainSend('debug', this._debug);
    					return this;
    				} else {
    					return (this._debug && this._debug[val]) || (this._db && this._db._debug && this._db._debug[val]) || (this._debug && this._debug.all);
    				}
    			}

    			return this._debug && this._debug.all;
    		},

    		function (type, val) {
    			if (type !== undefined) {
    				if (val !== undefined) {
    					this._debug = this._debug || {};
    					this._debug[type] = val;
    					this.chainSend('debug', this._debug);
    					return this;
    				}

    				return (this._debug && this._debug[val]) || (this._db && this._db._debug && this._db._debug[type]);
    			}

    			return this._debug && this._debug.all;
    		}
    	]),

    	/**
    	 * Returns a string describing the class this instance is derived from.
    	 * @returns {string}
    	 */
    	classIdentifier: function () {
    		return 'ForerunnerDB.' + this.className;
    	},

    	/**
    	 * Returns a string describing the instance by it's class name and instance
    	 * object name.
    	 * @returns {String} The instance identifier.
    	 */
    	instanceIdentifier: function () {
    		return '[' + this.className + ']' + this.name();
    	},

    	/**
    	 * Returns a string used to denote a console log against this instance,
    	 * consisting of the class identifier and instance identifier.
    	 * @returns {string} The log identifier.
    	 */
    	logIdentifier: function () {
    		return 'ForerunnerDB ' + this.instanceIdentifier();
    	},

    	/**
    	 * Converts a query object with MongoDB dot notation syntax
    	 * to Forerunner's object notation syntax.
    	 * @param {Object} obj The object to convert.
    	 */
    	convertToFdb: function (obj) {
    		var varName,
    			splitArr,
    			objCopy,
    			i;

    		for (i in obj) {
    			Eif (obj.hasOwnProperty(i)) {
    				objCopy = obj;

    				if (i.indexOf('.') > -1) {
    					// Replace .$ with a placeholder before splitting by . char
    					i = i.replace('.$', '[|$|]');
    					splitArr = i.split('.');

    					while ((varName = splitArr.shift())) {
    						// Replace placeholder back to original .$
    						varName = varName.replace('[|$|]', '.$');

    						if (splitArr.length) {
    							objCopy[varName] = {};
    						} else {
    							objCopy[varName] = obj[i];
    						}

    						objCopy = objCopy[varName];
    					}

    					delete obj[i];
    				}
    			}
    		}
    	},

    	/**
    	 * Checks if the state is dropped.
    	 * @returns {boolean} True when dropped, false otherwise.
    	 */
    	isDropped: function () {
    		return this._state === 'dropped';
    	},

    	/**
    	 * Registers a timed callback that will overwrite itself if
    	 * the same id is used within the timeout period. Useful
    	 * for de-bouncing fast-calls.
    	 * @param {String} id An ID for the call (use the same one
    	 * to debounce the same calls).
    	 * @param {Function} callback The callback method to call on
    	 * timeout.
    	 * @param {Number} timeout The timeout in milliseconds before
    	 * the callback is called.
    	 */
    	debounce: function (id, callback, timeout) {
    		var self = this,
    			newData;

    		self._debounce = self._debounce || {};

    		if (self._debounce[id]) {
    			// Clear timeout for this item
    			clearTimeout(self._debounce[id].timeout);
    		}

    		newData = {
    			callback: callback,
    			timeout: setTimeout(function () {
    				// Delete existing reference
    				delete self._debounce[id];

    				// Call the callback
    				callback();
    			}, timeout)
    		};

    		// Save current data
    		self._debounce[id] = newData;
    	}
    };

    module.exports = Common;
    },{"./Overload":32,"./Serialiser":39}],23:[function(_dereq_,module,exports){
    "use strict";

    /**
     * Provides some database constants.
     * @mixin
     */
    var Constants = {
    	TYPE_INSERT: 0,
    	TYPE_UPDATE: 1,
    	TYPE_REMOVE: 2,

    	PHASE_BEFORE: 0,
    	PHASE_AFTER: 1
    };

    module.exports = Constants;
    },{}],24:[function(_dereq_,module,exports){
    "use strict";

    var Overload = _dereq_('./Overload');

    /**
     * Provides event emitter functionality including the methods: on, off, once, emit, deferEmit.
     * @mixin
     */
    var Events = {
    	on: new Overload({
    		/**
    		 * Attach an event listener to the passed event.
    		 * @param {String} event The name of the event to listen for.
    		 * @param {Function} listener The method to call when the event is fired.
    		 */
    		'string, function': function (event, listener) {
    			this._listeners = this._listeners || {};
    			this._listeners[event] = this._listeners[event] || {};
    			this._listeners[event]['*'] = this._listeners[event]['*'] || [];
    			this._listeners[event]['*'].push(listener);

    			return this;
    		},

    		/**
    		 * Attach an event listener to the passed event only if the passed
    		 * id matches the document id for the event being fired.
    		 * @param {String} event The name of the event to listen for.
    		 * @param {*} id The document id to match against.
    		 * @param {Function} listener The method to call when the event is fired.
    		 */
    		'string, *, function': function (event, id, listener) {
    			this._listeners = this._listeners || {};
    			this._listeners[event] = this._listeners[event] || {};
    			this._listeners[event][id] = this._listeners[event][id] || [];
    			this._listeners[event][id].push(listener);

    			return this;
    		}
    	}),

    	once: new Overload({
    		'string, function': function (eventName, callback) {
    			var self = this,
    				internalCallback = function () {
    					self.off(eventName, internalCallback);
    					callback.apply(self, arguments);
    				};

    			return this.on(eventName, internalCallback);
    		},

    		'string, *, function': function (eventName, id, callback) {
    			var self = this,
    				internalCallback = function () {
    					self.off(eventName, id, internalCallback);
    					callback.apply(self, arguments);
    				};

    			return this.on(eventName, id, internalCallback);
    		}
    	}),

    	off: new Overload({
    		'string': function (event) {
    			Eif (this._listeners && this._listeners[event] && event in this._listeners) {
    				delete this._listeners[event];
    			}

    			return this;
    		},

    		'string, function': function (event, listener) {
    			var arr,
    				index;

    			Iif (typeof(listener) === 'string') {
    				if (this._listeners && this._listeners[event] && this._listeners[event][listener]) {
    					delete this._listeners[event][listener];
    				}
    			} else {
    				Eif (this._listeners && event in this._listeners) {
    					arr = this._listeners[event]['*'];
    					index = arr.indexOf(listener);

    					if (index > -1) {
    						arr.splice(index, 1);
    					}
    				}
    			}

    			return this;
    		},

    		'string, *, function': function (event, id, listener) {
    			if (this._listeners && event in this._listeners && id in this.listeners[event]) {
    				var arr = this._listeners[event][id],
    					index = arr.indexOf(listener);

    				if (index > -1) {
    					arr.splice(index, 1);
    				}
    			}
    		},

    		'string, *': function (event, id) {
    			if (this._listeners && event in this._listeners && id in this._listeners[event]) {
    				// Kill all listeners for this event id
    				delete this._listeners[event][id];
    			}
    		}
    	}),

    	emit: function (event, data) {
    		this._listeners = this._listeners || {};

    		if (event in this._listeners) {
    			var arrIndex,
    				arrCount,
    				tmpFunc,
    				arr,
    				listenerIdArr,
    				listenerIdCount,
    				listenerIdIndex;

    			// Handle global emit
    			if (this._listeners[event]['*']) {
    				arr = this._listeners[event]['*'];
    				arrCount = arr.length;

    				for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    					// Check we have a function to execute
    					tmpFunc = arr[arrIndex];

    					Eif (typeof tmpFunc === 'function') {
    						tmpFunc.apply(this, Array.prototype.slice.call(arguments, 1));
    					}
    				}
    			}

    			// Handle individual emit
    			if (data instanceof Array) {
    				// Check if the array is an array of objects in the collection
    				if (data[0] && data[0][this._primaryKey]) {
    					// Loop the array and check for listeners against the primary key
    					listenerIdArr = this._listeners[event];
    					arrCount = data.length;

    					for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
    						if (listenerIdArr[data[arrIndex][this._primaryKey]]) {
    							// Emit for this id
    							listenerIdCount = listenerIdArr[data[arrIndex][this._primaryKey]].length;
    							for (listenerIdIndex = 0; listenerIdIndex < listenerIdCount; listenerIdIndex++) {
    								tmpFunc = listenerIdArr[data[arrIndex][this._primaryKey]][listenerIdIndex];

    								Eif (typeof tmpFunc === 'function') {
    									listenerIdArr[data[arrIndex][this._primaryKey]][listenerIdIndex].apply(this, Array.prototype.slice.call(arguments, 1));
    								}
    							}
    						}
    					}
    				}
    			}
    		}

    		return this;
    	},

    	/**
    	 * Queues an event to be fired. This has automatic de-bouncing so that any
    	 * events of the same type that occur within 100 milliseconds of a previous
    	 * one will all be wrapped into a single emit rather than emitting tons of
    	 * events for lots of chained inserts etc. Only the data from the last
    	 * de-bounced event will be emitted.
    	 * @param {String} eventName The name of the event to emit.
    	 * @param {*=} data Optional data to emit with the event.
    	 */
    	deferEmit: function (eventName, data) {
    		var self = this,
    			args;

    		if (!this._noEmitDefer && (!this._db || (this._db && !this._db._noEmitDefer))) {
    			args = arguments;

    			// Check for an existing timeout
    			this._deferTimeout = this._deferTimeout || {};
    			if (this._deferTimeout[eventName]) {
    				clearTimeout(this._deferTimeout[eventName]);
    			}

    			// Set a timeout
    			this._deferTimeout[eventName] = setTimeout(function () {
    				if (self.debug()) {
    					console.log(self.logIdentifier() + ' Emitting ' + args[0]);
    				}

    				self.emit.apply(self, args);
    			}, 1);
    		} else {
    			this.emit.apply(this, arguments);
    		}

    		return this;
    	}
    };

    module.exports = Events;
    },{"./Overload":32}],25:[function(_dereq_,module,exports){
    "use strict";

    /**
     * Provides object matching algorithm methods.
     * @mixin
     */
    var Matching = {
    	/**
    	 * Internal method that checks a document against a test object.
    	 * @param {*} source The source object or value to test against.
    	 * @param {*} test The test object or value to test with.
    	 * @param {Object} queryOptions The options the query was passed with.
    	 * @param {String=} opToApply The special operation to apply to the test such
    	 * as 'and' or an 'or' operator.
    	 * @param {Object=} options An object containing options to apply to the
    	 * operation such as limiting the fields returned etc.
    	 * @returns {Boolean} True if the test was positive, false on negative.
    	 * @private
    	 */
    	_match: function (source, test, queryOptions, opToApply, options) {
    		// TODO: This method is quite long, break into smaller pieces
    		var operation,
    			applyOp = opToApply,
    			recurseVal,
    			tmpIndex,
    			sourceType = typeof source,
    			testType = typeof test,
    			matchedAll = true,
    			opResult,
    			substringCache,
    			i;

    		if (sourceType === 'object' && source === null) {
    			sourceType = 'null';
    		}

    		if (testType === 'object' && test === null) {
    			testType = 'null';
    		}

    		options = options || {};
    		queryOptions = queryOptions || {};

    		// Check if options currently holds a root query object
    		if (!options.$rootQuery) {
    			// Root query not assigned, hold the root query
    			options.$rootQuery = test;
    		}

    		// Check if options currently holds a root source object
    		if (!options.$rootSource) {
    			// Root query not assigned, hold the root query
    			options.$rootSource = source;
    		}

    		// Assign current query data
    		options.$currentQuery = test;

    		options.$rootData = options.$rootData || {};

    		// Check if the comparison data are both strings or numbers
    		if ((sourceType === 'string' || sourceType === 'number' || sourceType === 'null') && (testType === 'string' || testType === 'number' || testType === 'null')) {
    			// The source and test data are flat types that do not require recursive searches,
    			// so just compare them and return the result
    			if (sourceType === 'number' || sourceType === 'null' || testType === 'null') {
    				// Number or null comparison
    				if (source !== test) {
    					matchedAll = false;
    				}
    			} else {
    				// String comparison
    				// TODO: We can probably use a queryOptions.$locale as a second parameter here
    				// TODO: to satisfy https://github.com/Irrelon/ForerunnerDB/issues/35
    				if (source.localeCompare(test)) {
    					matchedAll = false;
    				}
    			}
    		} else if ((sourceType === 'string' || sourceType === 'number') && (testType === 'object' && test instanceof RegExp)) {
    			if (!test.test(source)) {
    				matchedAll = false;
    			}
    		} else {
    			for (i in test) {
    				Eif (test.hasOwnProperty(i)) {
    					// Assign previous query data
    					options.$previousQuery = options.$parent;

    					// Assign parent query data
    					options.$parent = {
    						query: test[i],
    						key: i,
    						parent: options.$previousQuery
    					};

    					// Reset operation flag
    					operation = false;

    					// Grab first two chars of the key name to check for $
    					substringCache = i.substr(0, 2);

    					// Check if the property is a comment (ignorable)
    					if (substringCache === '//') {
    						// Skip this property
    						continue;
    					}

    					// Check if the property starts with a dollar (function)
    					if (substringCache.indexOf('$') === 0) {
    						// Ask the _matchOp method to handle the operation
    						opResult = this._matchOp(i, source, test[i], queryOptions, options);

    						// Check the result of the matchOp operation
    						// If the result is -1 then no operation took place, otherwise the result
    						// will be a boolean denoting a match (true) or no match (false)
    						Eif (opResult > -1) {
    							if (opResult) {
    								Iif (opToApply === 'or') {
    									return true;
    								}
    							} else {
    								// Set the matchedAll flag to the result of the operation
    								// because the operation did not return true
    								matchedAll = opResult;
    							}

    							// Record that an operation was handled
    							operation = true;
    						}
    					}

    					// Check for regex
    					if (!operation && test[i] instanceof RegExp) {
    						operation = true;

    						if (sourceType === 'object' && source[i] !== undefined && test[i].test(source[i])) {
    							Iif (opToApply === 'or') {
    								return true;
    							}
    						} else {
    							matchedAll = false;
    						}
    					}

    					if (!operation) {
    						// Check if our query is an object
    						if (typeof(test[i]) === 'object') {
    							// Because test[i] is an object, source must also be an object

    							// Check if our source data we are checking the test query against
    							// is an object or an array
    							if (source[i] !== undefined) {
    								if (source[i] instanceof Array && !(test[i] instanceof Array)) {
    									// The source data is an array, so check each item until a
    									// match is found
    									recurseVal = false;
    									for (tmpIndex = 0; tmpIndex < source[i].length; tmpIndex++) {
    										recurseVal = this._match(source[i][tmpIndex], test[i], queryOptions, applyOp, options);

    										if (recurseVal) {
    											// One of the array items matched the query so we can
    											// include this item in the results, so break now
    											break;
    										}
    									}

    									if (recurseVal) {
    										Iif (opToApply === 'or') {
    											return true;
    										}
    									} else {
    										matchedAll = false;
    									}
    								} else if (!(source[i] instanceof Array) && test[i] instanceof Array) {
    									// The test key data is an array and the source key data is not so check
    									// each item in the test key data to see if the source item matches one
    									// of them. This is effectively an $in search.
    									recurseVal = false;

    									for (tmpIndex = 0; tmpIndex < test[i].length; tmpIndex++) {
    										recurseVal = this._match(source[i], test[i][tmpIndex], queryOptions, applyOp, options);

    										if (recurseVal) {
    											// One of the array items matched the query so we can
    											// include this item in the results, so break now
    											break;
    										}
    									}

    									Eif (recurseVal) {
    										Iif (opToApply === 'or') {
    											return true;
    										}
    									} else {
    										matchedAll = false;
    									}
    								} else Eif (typeof(source) === 'object') {
    									// Recurse down the object tree
    									recurseVal = this._match(source[i], test[i], queryOptions, applyOp, options);

    									if (recurseVal) {
    										Iif (opToApply === 'or') {
    											return true;
    										}
    									} else {
    										matchedAll = false;
    									}
    								} else {
    									recurseVal = this._match(undefined, test[i], queryOptions, applyOp, options);

    									if (recurseVal) {
    										if (opToApply === 'or') {
    											return true;
    										}
    									} else {
    										matchedAll = false;
    									}
    								}
    							} else {
    								// First check if the test match is an $exists
    								Eif (test[i] && test[i].$exists !== undefined) {
    									// Push the item through another match recurse
    									recurseVal = this._match(undefined, test[i], queryOptions, applyOp, options);

    									if (recurseVal) {
    										Iif (opToApply === 'or') {
    											return true;
    										}
    									} else {
    										matchedAll = false;
    									}
    								} else {
    									matchedAll = false;
    								}
    							}
    						} else {
    							// Check if the prop matches our test value
    							if (source && source[i] === test[i]) {
    								Iif (opToApply === 'or') {
    									return true;
    								}
    							} else if (source && source[i] && source[i] instanceof Array && test[i] && typeof(test[i]) !== "object") {
    								// We are looking for a value inside an array

    								// The source data is an array, so check each item until a
    								// match is found
    								recurseVal = false;
    								for (tmpIndex = 0; tmpIndex < source[i].length; tmpIndex++) {
    									recurseVal = this._match(source[i][tmpIndex], test[i], queryOptions, applyOp, options);

    									if (recurseVal) {
    										// One of the array items matched the query so we can
    										// include this item in the results, so break now
    										break;
    									}
    								}

    								if (recurseVal) {
    									Iif (opToApply === 'or') {
    										return true;
    									}
    								} else {
    									matchedAll = false;
    								}
    							} else {
    								matchedAll = false;
    							}
    						}
    					}

    					if (opToApply === 'and' && !matchedAll) {
    						return false;
    					}
    				}
    			}
    		}

    		return matchedAll;
    	},

    	/**
    	 * Internal method, performs a matching process against a query operator such as $gt or $nin.
    	 * @param {String} key The property name in the test that matches the operator to perform
    	 * matching against.
    	 * @param {*} source The source data to match the query against.
    	 * @param {*} test The query to match the source against.
    	 * @param {Object} queryOptions The options the query was passed with.
    	 * @param {Object=} options An options object.
    	 * @returns {*}
    	 * @private
    	 */
    	_matchOp: function (key, source, test, queryOptions, options) {
    		// Check for commands
    		switch (key) {
    			case '$gt':
    				// Greater than
    				return source > test;

    			case '$gte':
    				// Greater than or equal
    				return source >= test;

    			case '$lt':
    				// Less than
    				return source < test;

    			case '$lte':
    				// Less than or equal
    				return source <= test;

    			case '$exists':
    				// Property exists
    				return (source === undefined) !== test;

    			case '$eq': // Equals
    				return source == test; // jshint ignore:line

    			case '$eeq': // Equals equals
    				return source === test;

    			case '$ne': // Not equals
    				return source != test; // jshint ignore:line

    			case '$nee': // Not equals equals
    				return source !== test;

    			case '$or':
    				// Match true on ANY check to pass
    				for (var orIndex = 0; orIndex < test.length; orIndex++) {
    					if (this._match(source, test[orIndex], queryOptions, 'and', options)) {
    						return true;
    					}
    				}

    				return false;

    			case '$and':
    				// Match true on ALL checks to pass
    				for (var andIndex = 0; andIndex < test.length; andIndex++) {
    					if (!this._match(source, test[andIndex], queryOptions, 'and', options)) {
    						return false;
    					}
    				}

    				return true;

    			case '$in': // In
    				// Check that the in test is an array
    				if (test instanceof Array) {
    					var inArr = test,
    						inArrCount = inArr.length,
    						inArrIndex;

    					for (inArrIndex = 0; inArrIndex < inArrCount; inArrIndex++) {
    						if (this._match(source, inArr[inArrIndex], queryOptions, 'and', options)) {
    							return true;
    						}
    					}

    					return false;
    				} else Eif (typeof test === 'object') {
    					return this._match(source, test, queryOptions, 'and', options);
    				} else {
    					console.log(this.logIdentifier() + ' Cannot use an $in operator on a non-array key: ' + key, options.$rootQuery);
    					return false;
    				}
    				break;

    			case '$nin': // Not in
    				// Check that the not-in test is an array
    				if (test instanceof Array) {
    					var notInArr = test,
    						notInArrCount = notInArr.length,
    						notInArrIndex;

    					for (notInArrIndex = 0; notInArrIndex < notInArrCount; notInArrIndex++) {
    						if (this._match(source, notInArr[notInArrIndex], queryOptions, 'and', options)) {
    							return false;
    						}
    					}

    					return true;
    				} else Eif (typeof test === 'object') {
    					return this._match(source, test, queryOptions, 'and', options);
    				} else {
    					console.log(this.logIdentifier() + ' Cannot use a $nin operator on a non-array key: ' + key, options.$rootQuery);
    					return false;
    				}
    				break;

    			case '$distinct':
    				// Ensure options holds a distinct lookup
    				options.$rootData['//distinctLookup'] = options.$rootData['//distinctLookup'] || {};

    				for (var distinctProp in test) {
    					Eif (test.hasOwnProperty(distinctProp)) {
    						options.$rootData['//distinctLookup'][distinctProp] = options.$rootData['//distinctLookup'][distinctProp] || {};
    						// Check if the options distinct lookup has this field's value
    						if (options.$rootData['//distinctLookup'][distinctProp][source[distinctProp]]) {
    							// Value is already in use
    							return false;
    						} else {
    							// Set the value in the lookup
    							options.$rootData['//distinctLookup'][distinctProp][source[distinctProp]] = true;

    							// Allow the item in the results
    							return true;
    						}
    					}
    				}
    				break;

    			case '$count':
    				var countKey,
    					countArr,
    					countVal;

    				// Iterate the count object's keys
    				for (countKey in test) {
    					Eif (test.hasOwnProperty(countKey)) {
    						// Check the property exists and is an array. If the property being counted is not
    						// an array (or doesn't exist) then use a value of zero in any further count logic
    						countArr = source[countKey];
    						Eif (typeof countArr === 'object' && countArr instanceof Array) {
    							countVal = countArr.length;
    						} else {
    							countVal = 0;
    						}

    						// Now recurse down the query chain further to satisfy the query for this key (countKey)
    						if (!this._match(countVal, test[countKey], queryOptions, 'and', options)) {
    							return false;
    						}
    					}
    				}

    				// Allow the item in the results
    				return true;

    			case '$find':
    			case '$findOne':
    			case '$findSub':
    				var fromType = 'collection',
    					findQuery,
    					findOptions,
    					subQuery,
    					subOptions,
    					subPath,
    					result,
    					operation = {};

    				// Check all parts of the $find operation exist
    				Iif (!test.$from) {
    					throw(key + ' missing $from property!');
    				}

    				Iif (test.$fromType) {
    					fromType = test.$fromType;

    					// Check the fromType exists as a method
    					if (!this.db()[fromType] || typeof this.db()[fromType] !== 'function') {
    						throw(key + ' cannot operate against $fromType "' + fromType + '" because the database does not recognise this type of object!');
    					}
    				}

    				// Perform the find operation
    				findQuery = test.$query || {};
    				findOptions = test.$options || {};

    				if (key === '$findSub') {
    					Iif (!test.$path) {
    						throw(key + ' missing $path property!');
    					}

    					subPath = test.$path;
    					subQuery = test.$subQuery || {};
    					subOptions = test.$subOptions || {};

    					Eif (options.$parent && options.$parent.parent && options.$parent.parent.key) {
    						result = this.db()[fromType](test.$from).findSub(findQuery, subPath, subQuery, subOptions);
    					} else {
    						// This is a root $find* query
    						// Test the source against the main findQuery
    						if (this._match(source, findQuery, {}, 'and', options)) {
    							result = this._findSub([source], subPath, subQuery, subOptions);
    						}

    						return result && result.length > 0;
    					}
    				} else {
    					result = this.db()[fromType](test.$from)[key.substr(1)](findQuery, findOptions);
    				}

    				operation[options.$parent.parent.key] = result;
    				return this._match(source, operation, queryOptions, 'and', options);
    		}

    		return -1;
    	},

    	/**
    	 *
    	 * @param {Array | Object} docArr An array of objects to run the join
    	 * operation against or a single object.
    	 * @param {Array} joinClause The join clause object array (the array in
    	 * the $join key of a normal join options object).
    	 * @param {Object} joinSource An object containing join source reference
    	 * data or a blank object if you are doing a bespoke join operation.
    	 * @param {Object} options An options object or blank object if no options.
    	 * @returns {Array}
    	 * @private
    	 */
    	applyJoin: function (docArr, joinClause, joinSource, options) {
    		var self = this,
    			joinSourceIndex,
    			joinSourceKey,
    			joinMatch,
    			joinSourceType,
    			joinSourceIdentifier,
    			resultKeyName,
    			joinSourceInstance,
    			resultIndex,
    			joinSearchQuery,
    			joinMulti,
    			joinRequire,
    			joinPrefix,
    			joinMatchIndex,
    			joinMatchData,
    			joinSearchOptions,
    			joinFindResults,
    			joinFindResult,
    			joinItem,
    			resultRemove = [],
    			l;

    		Iif (!(docArr instanceof Array)) {
    			// Turn the document into an array
    			docArr = [docArr];
    		}

    		for (joinSourceIndex = 0; joinSourceIndex < joinClause.length; joinSourceIndex++) {
    			for (joinSourceKey in joinClause[joinSourceIndex]) {
    				Eif (joinClause[joinSourceIndex].hasOwnProperty(joinSourceKey)) {
    					// Get the match data for the join
    					joinMatch = joinClause[joinSourceIndex][joinSourceKey];

    					// Check if the join is to a collection (default) or a specified source type
    					// e.g 'view' or 'collection'
    					joinSourceType = joinMatch.$sourceType || 'collection';
    					joinSourceIdentifier = '$' + joinSourceType + '.' + joinSourceKey;

    					// Set the key to store the join result in to the collection name by default
    					// can be overridden by the '$as' clause in the join object
    					resultKeyName = joinSourceKey;

    					// Get the join collection instance from the DB
    					if (joinSource[joinSourceIdentifier]) {
    						// We have a joinSource for this identifier already (given to us by
    						// an index when we analysed the query earlier on) and we can use
    						// that source instead.
    						joinSourceInstance = joinSource[joinSourceIdentifier];
    					} else {
    						// We do not already have a joinSource so grab the instance from the db
    						Eif (this._db[joinSourceType] && typeof this._db[joinSourceType] === 'function') {
    							joinSourceInstance = this._db[joinSourceType](joinSourceKey);
    						}
    					}

    					// Loop our result data array
    					for (resultIndex = 0; resultIndex < docArr.length; resultIndex++) {
    						// Loop the join conditions and build a search object from them
    						joinSearchQuery = {};
    						joinMulti = false;
    						joinRequire = false;
    						joinPrefix = '';

    						for (joinMatchIndex in joinMatch) {
    							Eif (joinMatch.hasOwnProperty(joinMatchIndex)) {
    								joinMatchData = joinMatch[joinMatchIndex];

    								// Check the join condition name for a special command operator
    								if (joinMatchIndex.substr(0, 1) === '$') {
    									// Special command
    									switch (joinMatchIndex) {
    										case '$where':
    											Eif (joinMatchData.$query || joinMatchData.$options) {
    												if (joinMatchData.$query) {
    													// Commented old code here, new one does dynamic reverse lookups
    													//joinSearchQuery = joinMatchData.query;
    													joinSearchQuery = self.resolveDynamicQuery(joinMatchData.$query, docArr[resultIndex]);
    												}
    												if (joinMatchData.$options) {
    													joinSearchOptions = joinMatchData.$options;
    												}
    											} else {
    												throw('$join $where clause requires "$query" and / or "$options" keys to work!');
    											}
    											break;

    										case '$as':
    											// Rename the collection when stored in the result document
    											resultKeyName = joinMatchData;
    											break;

    										case '$multi':
    											// Return an array of documents instead of a single matching document
    											joinMulti = joinMatchData;
    											break;

    										case '$require':
    											// Remove the result item if no matching join data is found
    											joinRequire = joinMatchData;
    											break;

    										case '$prefix':
    											// Add a prefix to properties mixed in
    											joinPrefix = joinMatchData;
    											break;

    										default:
    											break;
    									}
    								} else {
    									// Get the data to match against and store in the search object
    									// Resolve complex referenced query
    									joinSearchQuery[joinMatchIndex] = self.resolveDynamicQuery(joinMatchData, docArr[resultIndex]);
    								}
    							}
    						}

    						// Do a find on the target collection against the match data
    						joinFindResults = joinSourceInstance.find(joinSearchQuery, joinSearchOptions);

    						// Check if we require a joined row to allow the result item
    						if (!joinRequire || (joinRequire && joinFindResults[0])) {
    							// Join is not required or condition is met
    							if (resultKeyName === '$root') {
    								// The property name to store the join results in is $root
    								// which means we need to mixin the results but this only
    								// works if joinMulti is disabled
    								Iif (joinMulti !== false) {
    									// Throw an exception here as this join is not physically possible!
    									throw(this.logIdentifier() + ' Cannot combine [$as: "$root"] with [$multi: true] in $join clause!');
    								}

    								// Mixin the result
    								joinFindResult = joinFindResults[0];
    								joinItem = docArr[resultIndex];

    								for (l in joinFindResult) {
    									if (joinFindResult.hasOwnProperty(l) && joinItem[joinPrefix + l] === undefined) {
    										// Properties are only mixed in if they do not already exist
    										// in the target item (are undefined). Using a prefix denoted via
    										// $prefix is a good way to prevent property name conflicts
    										joinItem[joinPrefix + l] = joinFindResult[l];
    									}
    								}
    							} else {
    								docArr[resultIndex][resultKeyName] = joinMulti === false ? joinFindResults[0] : joinFindResults;
    							}
    						} else {
    							// Join required but condition not met, add item to removal queue
    							resultRemove.push(resultIndex);
    						}
    					}
    				}
    			}
    		}

    		return resultRemove;
    	},

    	/**
    	 * Takes a query object with dynamic references and converts the references
    	 * into actual values from the references source.
    	 * @param {Object} query The query object with dynamic references.
    	 * @param {Object} item The document to apply the references to.
    	 * @returns {*}
    	 * @private
    	 */
    	resolveDynamicQuery: function (query, item) {
    		var self = this,
    			newQuery,
    			propType,
    			propVal,
    			pathResult,
    			i;

    		// Check for early exit conditions
    		if (typeof query === 'string') {
    			// Check if the property name starts with a back-reference
    			if (query.substr(0, 3) === '$$.') {
    				// Fill the query with a back-referenced value
    				pathResult = this.sharedPathSolver.value(item, query.substr(3, query.length - 3));
    			} else {
    				pathResult = this.sharedPathSolver.value(item, query);
    			}

    			if (pathResult.length > 1) {
    				return {$in: pathResult};
    			} else {
    				return pathResult[0];
    			}
    		}

    		newQuery = {};

    		for (i in query) {
    			Eif (query.hasOwnProperty(i)) {
    				propType = typeof query[i];
    				propVal = query[i];

    				switch (propType) {
    					case 'string':
    						// Check if the property name starts with a back-reference
    						if (propVal.substr(0, 3) === '$$.') {
    							// Fill the query with a back-referenced value
    							newQuery[i] = this.sharedPathSolver.value(item, propVal.substr(3, propVal.length - 3))[0];
    						} else {
    							newQuery[i] = propVal;
    						}
    						break;

    					case 'object':
    						newQuery[i] = self.resolveDynamicQuery(propVal, item);
    						break;

    					default:
    						newQuery[i] = propVal;
    						break;
    				}
    			}
    		}

    		return newQuery;
    	},

    	spliceArrayByIndexList: function (arr, list) {
    		var i;

    		for (i = list.length - 1; i >= 0; i--) {
    			arr.splice(list[i], 1);
    		}
    	}
    };

    module.exports = Matching;
    },{}],26:[function(_dereq_,module,exports){
    "use strict";

    /**
     * Provides sorting methods.
     * @mixin
     */
    var Sorting = {
    	/**
    	 * Sorts the passed value a against the passed value b ascending.
    	 * @param {*} a The first value to compare.
    	 * @param {*} b The second value to compare.
    	 * @returns {*} 1 if a is sorted after b, -1 if a is sorted before b.
    	 */
    	sortAsc: function (a, b) {
    		if (typeof(a) === 'string' && typeof(b) === 'string') {
    			return a.localeCompare(b);
    		} else {
    			if (a > b) {
    				return 1;
    			} else if (a < b) {
    				return -1;
    			}
    		}

    		return 0;
    	},

    	/**
    	 * Sorts the passed value a against the passed value b descending.
    	 * @param {*} a The first value to compare.
    	 * @param {*} b The second value to compare.
    	 * @returns {*} 1 if a is sorted after b, -1 if a is sorted before b.
    	 */
    	sortDesc: function (a, b) {
    		if (typeof(a) === 'string' && typeof(b) === 'string') {
    			return b.localeCompare(a);
    		} else {
    			if (a > b) {
    				return -1;
    			} else if (a < b) {
    				return 1;
    			}
    		}

    		return 0;
    	}
    };

    module.exports = Sorting;
    },{}],27:[function(_dereq_,module,exports){
    "use strict";

    var Tags,
    	tagMap = {};

    /**
     * Provides class instance tagging and tag operation methods.
     * @mixin
     */
    Tags = {
    	/**
    	 * Tags a class instance for later lookup.
    	 * @param {String} name The tag to add.
    	 * @returns {boolean}
    	 */
    	tagAdd: function (name) {
    		var i,
    			self = this,
    			mapArr = tagMap[name] = tagMap[name] || [];

    		for (i = 0; i < mapArr.length; i++) {
    			Iif (mapArr[i] === self) {
    				return true;
    			}
    		}

    		mapArr.push(self);

    		// Hook the drop event for this so we can react
    		Eif (self.on) {
    			self.on('drop', function () {
    				// We've been dropped so remove ourselves from the tag map
    				self.tagRemove(name);
    			});
    		}

    		return true;
    	},

    	/**
    	 * Removes a tag from a class instance.
    	 * @param {String} name The tag to remove.
    	 * @returns {boolean}
    	 */
    	tagRemove: function (name) {
    		var i,
    			mapArr = tagMap[name];

    		Eif (mapArr) {
    			for (i = 0; i < mapArr.length; i++) {
    				if (mapArr[i] === this) {
    					mapArr.splice(i, 1);
    					return true;
    				}
    			}
    		}

    		return false;
    	},

    	/**
    	 * Gets an array of all instances tagged with the passed tag name.
    	 * @param {String} name The tag to lookup.
    	 * @returns {Array} The array of instances that have the passed tag.
    	 */
    	tagLookup: function (name) {
    		return tagMap[name] || [];
    	},

    	/**
    	 * Drops all instances that are tagged with the passed tag name.
    	 * @param {String} name The tag to lookup.
    	 * @param {Function} callback Callback once dropping has completed
    	 * for all instances that match the passed tag name.
    	 * @returns {boolean}
    	 */
    	tagDrop: function (name, callback) {
    		var arr = this.tagLookup(name),
    			dropCb,
    			dropCount,
    			i;

    		dropCb = function () {
    			dropCount--;

    			if (callback && dropCount === 0) {
    				callback(false);
    			}
    		};

    		Eif (arr.length) {
    			dropCount = arr.length;

    			// Loop the array and drop all items
    			for (i = arr.length - 1; i >= 0; i--) {
    				arr[i].drop(dropCb);
    			}
    		}

    		return true;
    	}
    };

    module.exports = Tags;
    },{}],28:[function(_dereq_,module,exports){
    "use strict";

    var Overload = _dereq_('./Overload');

    /**
     * Provides trigger functionality methods.
     * @mixin
     */
    var Triggers = {
    	/**
    	 * When called in a before phase the newDoc object can be directly altered
    	 * to modify the data in it before the operation is carried out.
    	 * @callback addTriggerCallback
    	 * @param {Object} operation The details about the operation.
    	 * @param {Object} oldDoc The document before the operation.
    	 * @param {Object} newDoc The document after the operation.
    	 */

    	/**
    	 * Add a trigger by id.
    	 * @param {String} id The id of the trigger. This must be unique to the type and
    	 * phase of the trigger. Only one trigger may be added with this id per type and
    	 * phase.
    	 * @param {Constants} type The type of operation to apply the trigger to. See
    	 * Mixin.Constants for constants to use.
    	 * @param {Constants} phase The phase of an operation to fire the trigger on. See
    	 * Mixin.Constants for constants to use.
    	 * @param {addTriggerCallback} method The method to call when the trigger is fired.
    	 * @returns {boolean} True if the trigger was added successfully, false if not.
    	 */
    	addTrigger: function (id, type, phase, method) {
    		var self = this,
    			triggerIndex;

    		// Check if the trigger already exists
    		triggerIndex = self._triggerIndexOf(id, type, phase);

    		Eif (triggerIndex === -1) {
    			self.triggerStack = {};

    			// The trigger does not exist, create it
    			self._trigger = self._trigger || {};
    			self._trigger[type] = self._trigger[type] || {};
    			self._trigger[type][phase] = self._trigger[type][phase] || [];

    			self._trigger[type][phase].push({
    				id: id,
    				method: method,
    				enabled: true
    			});

    			return true;
    		}

    		return false;
    	},

    	/**
    	 *
    	 * @param {String} id The id of the trigger to remove.
    	 * @param {Number} type The type of operation to remove the trigger from. See
    	 * Mixin.Constants for constants to use.
    	 * @param {Number} phase The phase of the operation to remove the trigger from.
    	 * See Mixin.Constants for constants to use.
    	 * @returns {boolean} True if removed successfully, false if not.
    	 */
    	removeTrigger: function (id, type, phase) {
    		var self = this,
    			triggerIndex;

    		// Check if the trigger already exists
    		triggerIndex = self._triggerIndexOf(id, type, phase);

    		if (triggerIndex > -1) {
    			// The trigger exists, remove it
    			self._trigger[type][phase].splice(triggerIndex, 1);
    		}

    		return false;
    	},

    	/**
    	 * Tells the current instance to fire or ignore all triggers whether they
    	 * are enabled or not.
    	 * @param {Boolean} val Set to true to ignore triggers or false to not
    	 * ignore them.
    	 * @returns {*}
    	 */
    	ignoreTriggers: function (val) {
    		if (val !== undefined) {
    			this._ignoreTriggers = val;
    			return this;
    		}

    		return this._ignoreTriggers;
    	},

    	/**
    	 * Generates triggers that fire in the after phase for all CRUD ops
    	 * that automatically transform data back and forth and keep both
    	 * import and export collections in sync with each other.
    	 * @param {String} id The unique id for this link IO.
    	 * @param {Object} ioData The settings for the link IO.
    	 */
    	addLinkIO: function (id, ioData) {
    		var self = this,
    			matchAll,
    			exportData,
    			importData,
    			exportTriggerMethod,
    			importTriggerMethod,
    			exportTo,
    			importFrom,
    			allTypes,
    			i;

    		// Store the linkIO
    		self._linkIO = self._linkIO || {};
    		self._linkIO[id] = ioData;

    		exportData = ioData['export'];
    		importData = ioData['import'];

    		if (exportData) {
    			exportTo = self.db().collection(exportData.to);
    		}

    		if (importData) {
    			importFrom = self.db().collection(importData.from);
    		}

    		allTypes = [
    			self.TYPE_INSERT,
    			self.TYPE_UPDATE,
    			self.TYPE_REMOVE
    		];

    		matchAll = function (data, callback) {
    			// Match all
    			callback(false, true);
    		};

    		if (exportData) {
    			// Check for export match method
    			if (!exportData.match) {
    				// No match method found, use the match all method
    				exportData.match = matchAll;
    			}

    			// Check for export types
    			if (!exportData.types) {
    				exportData.types = allTypes;
    			}

    			exportTriggerMethod = function (operation, oldDoc, newDoc) {
    				// Check if we should execute against this data
    				exportData.match(newDoc, function (err, doExport) {
    					if (doExport) {
    						// Get data to upsert (if any)
    						exportData.data(newDoc, operation.type, function (err, data, callback) {
    							if (data) {
    								// Disable all currently enabled triggers so that we
    								// don't go into a trigger loop
    								exportTo.ignoreTriggers(true);

    								if (operation.type !== 'remove') {
    									// Do upsert
    									exportTo.upsert(data, callback);
    								} else {
    									// Do remove
    									exportTo.remove(data, callback);
    								}

    								// Re-enable the previous triggers
    								exportTo.ignoreTriggers(false);
    							}
    						});
    					}
    				});
    			};
    		}

    		if (importData) {
    			// Check for import match method
    			if (!importData.match) {
    				// No match method found, use the match all method
    				importData.match = matchAll;
    			}

    			// Check for import types
    			if (!importData.types) {
    				importData.types = allTypes;
    			}

    			importTriggerMethod = function (operation, oldDoc, newDoc) {
    				// Check if we should execute against this data
    				importData.match(newDoc, function (err, doExport) {
    					if (doExport) {
    						// Get data to upsert (if any)
    						importData.data(newDoc, operation.type, function (err, data, callback) {
    							if (data) {
    								// Disable all currently enabled triggers so that we
    								// don't go into a trigger loop
    								exportTo.ignoreTriggers(true);

    								if (operation.type !== 'remove') {
    									// Do upsert
    									self.upsert(data, callback);
    								} else {
    									// Do remove
    									self.remove(data, callback);
    								}

    								// Re-enable the previous triggers
    								exportTo.ignoreTriggers(false);
    							}
    						});
    					}
    				});
    			};
    		}

    		if (exportData) {
    			for (i = 0; i < exportData.types.length; i++) {
    				self.addTrigger(id + 'export' + exportData.types[i], exportData.types[i], self.PHASE_AFTER, exportTriggerMethod);
    			}
    		}

    		if (importData) {
    			for (i = 0; i < importData.types.length; i++) {
    				importFrom.addTrigger(id + 'import' + importData.types[i], importData.types[i], self.PHASE_AFTER, importTriggerMethod);
    			}
    		}
    	},

    	/**
    	 * Removes a previously added link IO via it's ID.
    	 * @param {String} id The id of the link IO to remove.
    	 * @returns {boolean} True if successful, false if the link IO
    	 * was not found.
    	 */
    	removeLinkIO: function (id) {
    		var self = this,
    			linkIO = self._linkIO[id],
    			exportData,
    			importData,
    			importFrom,
    			i;

    		if (linkIO) {
    			exportData = linkIO['export'];
    			importData = linkIO['import'];

    			if (exportData) {
    				for (i = 0; i < exportData.types.length; i++) {
    					self.removeTrigger(id + 'export' + exportData.types[i], exportData.types[i], self.db.PHASE_AFTER);
    				}
    			}

    			if (importData) {
    				importFrom = self.db().collection(importData.from);

    				for (i = 0; i < importData.types.length; i++) {
    					importFrom.removeTrigger(id + 'import' + importData.types[i], importData.types[i], self.db.PHASE_AFTER);
    				}
    			}

    			delete self._linkIO[id];
    			return true;
    		}

    		return false;
    	},

    	enableTrigger: new Overload({
    		'string': function (id) {
    			// Alter all triggers of this type
    			var self = this,
    				types = self._trigger,
    				phases,
    				triggers,
    				result = false,
    				i, k, j;

    			Eif (types) {
    				for (j in types) {
    					Eif (types.hasOwnProperty(j)) {
    						phases = types[j];

    						Eif (phases) {
    							for (i in phases) {
    								Eif (phases.hasOwnProperty(i)) {
    									triggers = phases[i];

    									// Loop triggers and set enabled flag
    									for (k = 0; k < triggers.length; k++) {
    										Eif (triggers[k].id === id) {
    											triggers[k].enabled = true;
    											result = true;
    										}
    									}
    								}
    							}
    						}
    					}
    				}
    			}

    			return result;
    		},

    		'number': function (type) {
    			// Alter all triggers of this type
    			var self = this,
    				phases = self._trigger[type],
    				triggers,
    				result = false,
    				i, k;

    			if (phases) {
    				for (i in phases) {
    					if (phases.hasOwnProperty(i)) {
    						triggers = phases[i];

    						// Loop triggers and set to enabled
    						for (k = 0; k < triggers.length; k++) {
    							triggers[k].enabled = true;
    							result = true;
    						}
    					}
    				}
    			}

    			return result;
    		},

    		'number, number': function (type, phase) {
    			// Alter all triggers of this type and phase
    			var self = this,
    				phases = self._trigger[type],
    				triggers,
    				result = false,
    				k;

    			if (phases) {
    				triggers = phases[phase];

    				if (triggers) {
    					// Loop triggers and set to enabled
    					for (k = 0; k < triggers.length; k++) {
    						triggers[k].enabled = true;
    						result = true;
    					}
    				}
    			}

    			return result;
    		},

    		'string, number, number': function (id, type, phase) {
    			// Check if the trigger already exists
    			var self = this,
    				triggerIndex = self._triggerIndexOf(id, type, phase);

    			if (triggerIndex > -1) {
    				// Update the trigger
    				self._trigger[type][phase][triggerIndex].enabled = true;

    				return true;
    			}

    			return false;
    		}
    	}),

    	disableTrigger: new Overload({
    		'string': function (id) {
    			// Alter all triggers of this type
    			var self = this,
    				types = self._trigger,
    				phases,
    				triggers,
    				result = false,
    				i, k, j;

    			Eif (types) {
    				for (j in types) {
    					Eif (types.hasOwnProperty(j)) {
    						phases = types[j];

    						Eif (phases) {
    							for (i in phases) {
    								Eif (phases.hasOwnProperty(i)) {
    									triggers = phases[i];

    									// Loop triggers and set enabled flag
    									for (k = 0; k < triggers.length; k++) {
    										Eif (triggers[k].id === id) {
    											triggers[k].enabled = false;
    											result = true;
    										}
    									}
    								}
    							}
    						}
    					}
    				}
    			}

    			return result;
    		},

    		'number': function (type) {
    			// Alter all triggers of this type
    			var self = this,
    				phases = self._trigger[type],
    				triggers,
    				result = false,
    				i, k;

    			Eif (phases) {
    				for (i in phases) {
    					Eif (phases.hasOwnProperty(i)) {
    						triggers = phases[i];

    						// Loop triggers and set to disabled
    						for (k = 0; k < triggers.length; k++) {
    							triggers[k].enabled = false;
    							result = true;
    						}
    					}
    				}
    			}

    			return result;
    		},

    		'number, number': function (type, phase) {
    			// Alter all triggers of this type and phase
    			var self = this,
    				phases = self._trigger[type],
    				triggers,
    				result = false,
    				k;

    			Eif (phases) {
    				triggers = phases[phase];

    				Eif (triggers) {
    					// Loop triggers and set to disabled
    					for (k = 0; k < triggers.length; k++) {
    						triggers[k].enabled = false;
    						result = true;
    					}
    				}
    			}

    			return result;
    		},

    		'string, number, number': function (id, type, phase) {
    			// Check if the trigger already exists
    			var self = this,
    				triggerIndex = self._triggerIndexOf(id, type, phase);

    			Eif (triggerIndex > -1) {
    				// Update the trigger
    				self._trigger[type][phase][triggerIndex].enabled = false;

    				return true;
    			}

    			return false;
    		}
    	}),

    	/**
    	 * Checks if a trigger will fire based on the type and phase provided.
    	 * @param {Number} type The type of operation. See Mixin.Constants for
    	 * constants to use.
    	 * @param {Number} phase The phase of the operation. See Mixin.Constants
    	 * for constants to use.
    	 * @returns {Boolean} True if the trigger will fire, false otherwise.
    	 */
    	willTrigger: function (type, phase) {
    		if (!this._ignoreTriggers && this._trigger && this._trigger[type] && this._trigger[type][phase] && this._trigger[type][phase].length) {
    			// Check if a trigger in this array is enabled
    			var arr = this._trigger[type][phase],
    				i;

    			for (i = 0; i < arr.length; i++) {
    				if (arr[i].enabled) {
    					return true;
    				}
    			}
    		}

    		return false;
    	},

    	/**
    	 * Processes trigger actions based on the operation, type and phase.
    	 * @param {Object} operation Operation data to pass to the trigger.
    	 * @param {Number} type The type of operation. See Mixin.Constants for
    	 * constants to use.
    	 * @param {Number} phase The phase of the operation. See Mixin.Constants
    	 * for constants to use.
    	 * @param {Object} oldDoc The document snapshot before operations are
    	 * carried out against the data.
    	 * @param {Object} newDoc The document snapshot after operations are
    	 * carried out against the data.
    	 * @returns {boolean}
    	 */
    	processTrigger: function (operation, type, phase, oldDoc, newDoc) {
    		var self = this,
    			triggerArr,
    			triggerIndex,
    			triggerCount,
    			triggerItem,
    			response,
    			typeName,
    			phaseName;

    		if (!self._ignoreTriggers && self._trigger && self._trigger[type] && self._trigger[type][phase]) {
    			triggerArr = self._trigger[type][phase];
    			triggerCount = triggerArr.length;

    			for (triggerIndex = 0; triggerIndex < triggerCount; triggerIndex++) {
    				triggerItem = triggerArr[triggerIndex];

    				// Check if the trigger is enabled
    				Eif (triggerItem.enabled) {
    					Eif (self.debug()) {
    						switch (type) {
    							case this.TYPE_INSERT:
    								typeName = 'insert';
    								break;

    							case this.TYPE_UPDATE:
    								typeName = 'update';
    								break;

    							case this.TYPE_REMOVE:
    								typeName = 'remove';
    								break;

    							default:
    								typeName = '';
    								break;
    						}

    						switch (phase) {
    							case this.PHASE_BEFORE:
    								phaseName = 'before';
    								break;

    							case this.PHASE_AFTER:
    								phaseName = 'after';
    								break;

    							default:
    								phaseName = '';
    								break;
    						}

    						console.log('Triggers: Processing trigger "' + triggerItem.id + '" for ' + typeName + ' in phase "' + phaseName + '"');
    					}

    					// Check if the trigger is already in the stack, if it is,
    					// don't fire it again (this is so we avoid infinite loops
    					// where a trigger triggers another trigger which calls this
    					// one and so on)
    					if  (self.triggerStack && self.triggerStack[type] && self.triggerStack[type][phase] && self.triggerStack[type][phase][triggerItem.id]) {
    						// The trigger is already in the stack, do not fire the trigger again
    						Eif (self.debug()) {
    							console.log('Triggers: Will not run trigger "' + triggerItem.id + '" for ' + typeName + ' in phase "' + phaseName + '" as it is already in the stack!');
    						}

    						continue;
    					}

    					// Add the trigger to the stack so we don't go down an endless
    					// trigger loop
    					self.triggerStack[type] = {};
    					self.triggerStack[type][phase] = {};
    					self.triggerStack[type][phase][triggerItem.id] = true;

    					// Run the trigger's method and store the response
    					response = triggerItem.method.call(self, operation, oldDoc, newDoc);

    					// Remove the trigger from the stack
    					self.triggerStack[type][phase][triggerItem.id] = false;

    					// Check the response for a non-expected result (anything other than
    					// [undefined, true or false] is considered a throwable error)
    					if (response === false) {
    						// The trigger wants us to cancel operations
    						return false;
    					}

    					Iif (response !== undefined && response !== true && response !== false) {
    						// Trigger responded with error, throw the error
    						throw('ForerunnerDB.Mixin.Triggers: Trigger error: ' + response);
    					}
    				}
    			}

    			// Triggers all ran without issue, return a success (true)
    			return true;
    		}
    	},

    	/**
    	 * Returns the index of a trigger by id based on type and phase.
    	 * @param {String} id The id of the trigger to find the index of.
    	 * @param {Number} type The type of operation. See Mixin.Constants for
    	 * constants to use.
    	 * @param {Number} phase The phase of the operation. See Mixin.Constants
    	 * for constants to use.
    	 * @returns {number}
    	 * @private
    	 */
    	_triggerIndexOf: function (id, type, phase) {
    		var self = this,
    			triggerArr,
    			triggerCount,
    			triggerIndex;

    		if (self._trigger && self._trigger[type] && self._trigger[type][phase]) {
    			triggerArr = self._trigger[type][phase];
    			triggerCount = triggerArr.length;

    			for (triggerIndex = 0; triggerIndex < triggerCount; triggerIndex++) {
    				Eif (triggerArr[triggerIndex].id === id) {
    					return triggerIndex;
    				}
    			}
    		}

    		return -1;
    	}
    };

    module.exports = Triggers;
    },{"./Overload":32}],29:[function(_dereq_,module,exports){
    "use strict";

    /**
     * Provides methods to handle object update operations.
     * @mixin
     */
    var Updating = {
    	/**
    	 * Updates a property on an object.
    	 * @param {Object} doc The object whose property is to be updated.
    	 * @param {String} prop The property to update.
    	 * @param {*} val The new value of the property.
    	 * @private
    	 */
    	_updateProperty: function (doc, prop, val) {
    		doc[prop] = val;

    		if (this.debug()) {
    			console.log(this.logIdentifier() + ' Setting non-data-bound document property "' + prop + '" to val "' + val + '"');
    		}
    	},

    	/**
    	 * Increments a value for a property on a document by the passed number.
    	 * @param {Object} doc The document to modify.
    	 * @param {String} prop The property to modify.
    	 * @param {Number} val The amount to increment by.
    	 * @private
    	 */
    	_updateIncrement: function (doc, prop, val) {
    		doc[prop] += val;
    	},

    	/**
    	 * Changes the index of an item in the passed array.
    	 * @param {Array} arr The array to modify.
    	 * @param {Number} indexFrom The index to move the item from.
    	 * @param {Number} indexTo The index to move the item to.
    	 * @private
    	 */
    	_updateSpliceMove: function (arr, indexFrom, indexTo) {
    		arr.splice(indexTo, 0, arr.splice(indexFrom, 1)[0]);

    		Eif (this.debug()) {
    			console.log(this.logIdentifier() + ' Moving non-data-bound document array index from "' + indexFrom + '" to "' + indexTo + '"');
    		}
    	},

    	/**
    	 * Inserts an item into the passed array at the specified index.
    	 * @param {Array} arr The array to insert into.
    	 * @param {Number} index The index to insert at.
    	 * @param {Object} doc The document to insert.
    	 * @private
    	 */
    	_updateSplicePush: function (arr, index, doc) {
    		Eif (arr.length > index) {
    			arr.splice(index, 0, doc);
    		} else {
    			arr.push(doc);
    		}
    	},

    	/**
    	 * Inserts an item at the end of an array.
    	 * @param {Array} arr The array to insert the item into.
    	 * @param {Object} doc The document to insert.
    	 * @private
    	 */
    	_updatePush: function (arr, doc) {
    		arr.push(doc);
    	},

    	/**
    	 * Removes an item from the passed array.
    	 * @param {Array} arr The array to modify.
    	 * @param {Number} index The index of the item in the array to remove.
    	 * @private
    	 */
    	_updatePull: function (arr, index) {
    		arr.splice(index, 1);
    	},

    	/**
    	 * Multiplies a value for a property on a document by the passed number.
    	 * @param {Object} doc The document to modify.
    	 * @param {String} prop The property to modify.
    	 * @param {Number} val The amount to multiply by.
    	 * @private
    	 */
    	_updateMultiply: function (doc, prop, val) {
    		doc[prop] *= val;
    	},

    	/**
    	 * Renames a property on a document to the passed property.
    	 * @param {Object} doc The document to modify.
    	 * @param {String} prop The property to rename.
    	 * @param {Number} val The new property name.
    	 * @private
    	 */
    	_updateRename: function (doc, prop, val) {
    		doc[val] = doc[prop];
    		delete doc[prop];
    	},

    	/**
    	 * Sets a property on a document to the passed value.
    	 * @param {Object} doc The document to modify.
    	 * @param {String} prop The property to set.
    	 * @param {*} val The new property value.
    	 * @private
    	 */
    	_updateOverwrite: function (doc, prop, val) {
    		doc[prop] = val;
    	},

    	/**
    	 * Deletes a property on a document.
    	 * @param {Object} doc The document to modify.
    	 * @param {String} prop The property to delete.
    	 * @private
    	 */
    	_updateUnset: function (doc, prop) {
    		delete doc[prop];
    	},

    	/**
    	 * Removes all properties from an object without destroying
    	 * the object instance, thereby maintaining data-bound linking.
    	 * @param {Object} doc The parent object to modify.
    	 * @param {String} prop The name of the child object to clear.
    	 * @private
    	 */
    	_updateClear: function (doc, prop) {
    		var obj = doc[prop],
    			i;

    		if (obj && typeof obj === 'object') {
    			for (i in obj) {
    				if (obj.hasOwnProperty(i)) {
    					this._updateUnset(obj, i);
    				}
    			}
    		}
    	},

    	/**
    	 * Pops an item or items from the array stack.
    	 * @param {Object} doc The document to modify.
    	 * @param {Number} val If set to a positive integer, will pop the number specified
    	 * from the stack, if set to a negative integer will shift the number specified
    	 * from the stack.
    	 * @return {Boolean}
    	 * @private
    	 */
    	_updatePop: function (doc, val) {
    		var updated = false,
    			i;

    		if (doc.length > 0) {
    			if (val > 0) {
    				for (i = 0; i < val; i++) {
    					doc.pop();
    				}
    				updated = true;
    			} else if (val < 0) {
    				for (i = 0; i > val; i--) {
    					doc.shift();
    				}
    				updated = true;
    			}
    		}

    		return updated;
    	}
    };

    module.exports = Updating;
    },{}],30:[function(_dereq_,module,exports){
    "use strict";

    // Tell JSHint about EventSource
    /*global
    	EventSource
    */

    // Import external names locally
    var Shared = _dereq_('./Shared'),
    	Core,
    	CoreInit,
    	Collection,
    	NodeApiClient,
    	Overload;

    NodeApiClient = function () {
    	this.init.apply(this, arguments);
    };

    /**
     * The init method that can be overridden or extended.
     * @param {Core} core The ForerunnerDB core instance.
     */
    NodeApiClient.prototype.init = function (core) {
    	var self = this;
    	self._core = core;

    	self.rootPath('/fdb');
    };

    Shared.addModule('NodeApiClient', NodeApiClient);
    Shared.mixin(NodeApiClient.prototype, 'Mixin.Common');
    Shared.mixin(NodeApiClient.prototype, 'Mixin.Events');
    Shared.mixin(NodeApiClient.prototype, 'Mixin.ChainReactor');

    Core = Shared.modules.Core;
    CoreInit = Core.prototype.init;
    Collection = Shared.modules.Collection;
    Overload = Shared.overload;

    Shared.synthesize(NodeApiClient.prototype, 'rootPath');

    /**
     * Set the url of the server to use for API.
     * @name server
     * @param {String} host The server host name including protocol. E.g.
     * "https://0.0.0.0".
     * @param {String} port The server port number e.g. "8080".
     */
    NodeApiClient.prototype.server = function (host, port) {
    	if (host !== undefined) {
    		if (host.substr(host.length - 1, 1) === '/') {
    			// Strip trailing /
    			host = host.substr(0, host.length - 1);
    		}

    		if (port !== undefined) {
    			this._server = host + ":" + port;
    		} else {
    			this._server = host;
    		}

    		this._host = host;
    		this._port = port;

    		return this;
    	}

    	if (port !== undefined) {
    		return {
    			host: this._host,
    			port: this._port,
    			url: this._server
    		};
    	} else {
    		return this._server;
    	}
    };

    NodeApiClient.prototype.http = function (method, url, data, options, callback) {
    	var self = this,
    		finalUrl,
    		sessionData,
    		bodyData,
    		xmlHttp = new XMLHttpRequest();

    	method = method.toUpperCase();

    	xmlHttp.onreadystatechange = function () {
    		if (xmlHttp.readyState === 4) {
    			if (xmlHttp.status === 200) {
    				// Tell the callback about success
    				if (xmlHttp.responseText) {
    					callback(false, self.jParse(xmlHttp.responseText));
    				} else {
    					callback(false, {});
    				}
    			} else if (xmlHttp.status === 204) {
    				callback(false, {});
    			} else {
    				// Tell the callback about the error
    				callback(xmlHttp.status, xmlHttp.responseText);

    				// Emit the error code
    				self.emit('httpError', xmlHttp.status, xmlHttp.responseText);
    			}
    		}
    	};

    	switch (method) {
    		case 'GET':
    		case 'DELETE':
    		case 'HEAD':
    			// Check for global auth
    			if (this._sessionData) {
    				data = data !== undefined ? data : {};

    				// Add the session data to the key specified
    				data[this._sessionData.key] = this._sessionData.obj;
    			}

    			finalUrl = url + (data !== undefined ? '?' + self.jStringify(data) : '');
    			bodyData = null;
    			break;

    		case 'POST':
    		case 'PUT':
    		case 'PATCH':
    			// Check for global auth
    			if (this._sessionData) {
    				sessionData = {};

    				// Add the session data to the key specified
    				sessionData[this._sessionData.key] = this._sessionData.obj;
    			}

    			finalUrl = url + (sessionData !== undefined ? '?' + self.jStringify(sessionData) : '');
    			bodyData = (data !== undefined ? self.jStringify(data) : null);
    			break;

    		default:
    			return false;
    	}

    	xmlHttp.open(method, finalUrl, true);
    	xmlHttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    	xmlHttp.send(bodyData);

    	return this;
    };

    // Define HTTP helper methods
    NodeApiClient.prototype.head = new Overload({
    	'string, function': function (path, callback) {
    		return this.$main.call(this, path, undefined, {}, callback);
    	},

    	'string, *, function': function (path, data, callback) {
    		return this.$main.call(this, path, data, {}, callback);
    	},

    	'string, *, object, function': function (path, data, options, callback) {
    		return this.$main.call(this, path, data, options, callback);
    	},

    	'$main': function (path, data, options, callback) {
    		return this.http('HEAD', this.server() + this._rootPath + path, data, options, callback);
    	}
    });

    NodeApiClient.prototype.get = new Overload({
    	'string, function': function (path, callback) {
    		return this.$main.call(this, path, undefined, {}, callback);
    	},

    	'string, *, function': function (path, data, callback) {
    		return this.$main.call(this, path, data, {}, callback);
    	},

    	'string, *, object, function': function (path, data, options, callback) {
    		return this.$main.call(this, path, data, options, callback);
    	},

    	'$main': function (path, data, options, callback) {
    		return this.http('GET', this.server() + this._rootPath + path, data, options, callback);
    	}
    });

    NodeApiClient.prototype.put = new Overload({
    	'string, function': function (path, callback) {
    		return this.$main.call(this, path, undefined, {}, callback);
    	},

    	'string, *, function': function (path, data, callback) {
    		return this.$main.call(this, path, data, {}, callback);
    	},

    	'string, *, object, function': function (path, data, options, callback) {
    		return this.$main.call(this, path, data, options, callback);
    	},

    	'$main': function (path, data, options, callback) {
    		return this.http('PUT', this.server() + this._rootPath + path, data, options, callback);
    	}
    });

    NodeApiClient.prototype.post = new Overload({
    	'string, function': function (path, callback) {
    		return this.$main.call(this, path, undefined, {}, callback);
    	},

    	'string, *, function': function (path, data, callback) {
    		return this.$main.call(this, path, data, {}, callback);
    	},

    	'string, *, object, function': function (path, data, options, callback) {
    		return this.$main.call(this, path, data, options, callback);
    	},

    	'$main': function (path, data, options, callback) {
    		return this.http('POST', this.server() + this._rootPath + path, data, options, callback);
    	}
    });

    NodeApiClient.prototype.patch = new Overload({
    	'string, function': function (path, callback) {
    		return this.$main.call(this, path, undefined, {}, callback);
    	},

    	'string, *, function': function (path, data, callback) {
    		return this.$main.call(this, path, data, {}, callback);
    	},

    	'string, *, object, function': function (path, data, options, callback) {
    		return this.$main.call(this, path, data, options, callback);
    	},

    	'$main': function (path, data, options, callback) {
    		return this.http('PATCH', this.server() + this._rootPath + path, data, options, callback);
    	}
    });

    NodeApiClient.prototype.postPatch = function (path, id, data, options, callback) {
    	var self = this;

    	// Determine if the item exists or not
    	this.head(path + '/' + id, undefined, {}, function (err, headData) {
    		if (err) {
    			if (err === 404) {
    				// Item does not exist, run post
    				return self.http('POST', self.server() + self._rootPath + path, data, options, callback);
    			} else {
    				callback(err, data);
    			}
    		} else {
    			// Item already exists, run patch
    			return self.http('PATCH', self.server() + self._rootPath + path + '/' + id, data, options, callback);
    		}
    	});
    };

    NodeApiClient.prototype.delete = new Overload({
    	'string, function': function (path, callback) {
    		return this.$main.call(this, path, undefined, {}, callback);
    	},

    	'string, *, function': function (path, data, callback) {
    		return this.$main.call(this, path, data, {}, callback);
    	},

    	'string, *, object, function': function (path, data, options, callback) {
    		return this.$main.call(this, path, data, options, callback);
    	},

    	'$main': function (path, data, options, callback) {
    		return this.http('DELETE', this.server() + this._rootPath + path, data, options, callback);
    	}
    });

    /**
     * Gets/ sets a global object that will be sent up with client
     * requests to the API or REST server.
     * @param {String} key The key to send the session object up inside.
     * @param {*} obj The object / value to send up with all requests. If
     * a request has its own data to send up, this session data will be
     * mixed in to the request data under the specified key.
     */
    NodeApiClient.prototype.session = function (key, obj) {
    	if (key !== undefined && obj !== undefined) {
    		this._sessionData = {
    			key: key,
    			obj: obj
    		};
    		return this;
    	}

    	return this._sessionData;
    };

    /**
     * Initiates a client connection to the API server.
     * @param collectionInstance
     * @param path
     * @param query
     * @param options
     * @param callback
     */
    NodeApiClient.prototype.sync = function (collectionInstance, path, query, options, callback) {
    	var self = this,
    		source,
    		finalPath,
    		queryParams,
    		queryString = '',
    		connecting = true;

    	if (this.debug()) {
    		console.log(this.logIdentifier() + ' Connecting to API server ' + this.server() + this._rootPath + path);
    	}

    	finalPath = this.server() + this._rootPath + path + '/_sync';

    	// Check for global auth
    	if (this._sessionData) {
    		queryParams = queryParams || {};

    		if (this._sessionData.key) {
    			// Add the session data to the key specified
    			queryParams[this._sessionData.key] = this._sessionData.obj;
    		} else {
    			// Add the session data to the root query object
    			Shared.mixin(queryParams, this._sessionData.obj);
    		}
    	}

    	if (query) {
    		queryParams = queryParams || {};
    		queryParams.$query = query;
    	}

    	if (options) {
    		queryParams = queryParams || {};
    		if (options.$initialData === undefined) {
    			options.$initialData = true;
    		}

    		queryParams.$options = options;
    	}

    	if (queryParams) {
    		queryString = this.jStringify(queryParams);
    		finalPath += '?' + queryString;
    	}

    	source = new EventSource(finalPath);
    	collectionInstance.__apiConnection = source;

    	source.addEventListener('open', function (e) {
    		if (!options || (options && options.$initialData)) {
    			// The connection is open, grab the initial data
    			self.get(path, queryParams, function (err, data) {
    				if (!err) {
    					collectionInstance.upsert(data);
    				}
    			});
    		}
    	}, false);

    	source.addEventListener('error', function (e) {
    		if (source.readyState === 2) {
    			// The connection is dead, remove the connection
    			collectionInstance.unSync();
    		}

    		if (connecting) {
    			connecting = false;
    			callback(e);
    		}
    	}, false);

    	source.addEventListener('insert', function(e) {
    		var data = self.jParse(e.data);
    		collectionInstance.insert(data.dataSet);
    	}, false);

    	source.addEventListener('update', function(e) {
    		var data = self.jParse(e.data);
    		collectionInstance.update(data.query, data.update);
    	}, false);

    	source.addEventListener('remove', function(e) {
    		var data = self.jParse(e.data);
    		collectionInstance.remove(data.query);
    	}, false);

    	if (callback) {
    		source.addEventListener('connected', function (e) {
    			if (connecting) {
    				connecting = false;
    				callback(false);
    			}
    		}, false);
    	}
    };

    Collection.prototype.sync = new Overload({
    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'function': function (callback) {
    		this.$main.call(this, '/' + this._db.name() + '/collection/' + this.name(), null, null, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {String} collectionName The collection to sync from.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'string, function': function (collectionName, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/collection/' + collectionName, null, null, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {Object} query A query object.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'object, function': function (query, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/collection/' + this.name(), query, null, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {String} objectType The type of object to sync to e.g.
    	 * "collection" or "view".
    	 * @param {String} objectName The name of the object to sync from.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'string, string, function': function (objectType, objectName, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/' + objectType + '/' + objectName, null, null, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {String} collectionName The collection to sync from.
    	 * @param {Object} query A query object.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'string, object, function': function (collectionName, query, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/collection/' + collectionName, query, null, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {String} objectType The type of object to sync to e.g.
    	 * "collection" or "view".
    	 * @param {String} objectName The name of the object to sync from.
    	 * @param {Object} query A query object.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'string, string, object, function': function (objectType, objectName, query, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/' + objectType + '/' + objectName, query, null, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {Object} query A query object.
    	 * @param {Object} options An options object.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'object, object, function': function (query, options, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/collection/' + this.name(), query, options, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {String} collectionName The collection to sync from.
    	 * @param {Object} query A query object.
    	 * @param {Object} options An options object.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'string, object, object, function': function (collectionName, query, options, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/collection/' + collectionName, query, options, callback);
    	},

    	/**
    	 * Sync with this collection on the server-side.
    	 * @param {String} objectType The type of object to sync to e.g.
    	 * "collection" or "view".
    	 * @param {String} objectName The name of the object to sync from.
    	 * @param {Object} query A query object.
    	 * @param {Object} options An options object.
    	 * @param {Function} callback The callback method to call once
    	 * the connection to the server has been established.
    	 */
    	'string, string, object, object, function': function (objectType, objectName, query, options, callback) {
    		this.$main.call(this, '/' + this._db.name() + '/' + objectType + '/' + objectName, query, options, callback);
    	},

    	'$main': function (path, query, options, callback) {
    		var self = this;

    		if (this._db && this._db._core) {
    			// Kill any existing sync connection
    			this.unSync();

    			// Create new sync connection
    			this._db._core.api.sync(this, path, query, options, callback);

    			// Hook on drop to call unsync
    			this.on('drop', function () {
    				self.unSync();
    			});
    		} else {
    			throw(this.logIdentifier() + ' Cannot sync for an anonymous collection! (Collection must be attached to a database)');
    		}
    	}
    });

    /**
     * Disconnects an existing connection to a sync server.
     * @returns {boolean} True if a connection existed, false
     * if no connection existed.
     */
    Collection.prototype.unSync = function () {
    	if (this.__apiConnection) {
    		if (this.__apiConnection.readyState !== 2) {
    			this.__apiConnection.close();
    		}

    		delete this.__apiConnection;

    		return true;
    	}

    	return false;
    };

    Collection.prototype.http = new Overload({
    	'string, function': function (method, callback) {
    		this.$main.call(this, method, '/' + this._db.name() + '/collection/' + this.name(), undefined, undefined, {}, callback);
    	},

    	'$main': function (method, path, queryObj, queryOptions, options, callback) {
    		if (this._db && this._db._core) {
    			return this._db._core.api.http('GET', this._db._core.api.server() + this._rootPath + path, {"$query": queryObj, "$options": queryOptions}, options, callback);
    		} else {
    			throw(this.logIdentifier() + ' Cannot do HTTP for an anonymous collection! (Collection must be attached to a database)');
    		}
    	}
    });

    Collection.prototype.autoHttp = new Overload({
    	'string, function': function (method, callback) {
    		this.$main.call(this, method, '/' + this._db.name() + '/collection/' + this.name(), undefined, undefined, {}, callback);
    	},

    	'string, string, function': function (method, collectionName, callback) {
    		this.$main.call(this, method, '/' + this._db.name() + '/collection/' + collectionName, undefined, undefined, {}, callback);
    	},

    	'string, string, string, function': function (method, objType, objName, callback) {
    		this.$main.call(this, method, '/' + this._db.name() + '/' + objType + '/' + objName, undefined, undefined, {}, callback);
    	},

    	'string, string, string, object, function': function (method, objType, objName, queryObj, callback) {
    		this.$main.call(this, method, '/' + this._db.name() + '/' + objType + '/' + objName, queryObj, undefined, {}, callback);
    	},

    	'string, string, string, object, object, function': function (method, objType, objName, queryObj, queryOptions, callback) {
    		this.$main.call(this, method, '/' + this._db.name() + '/' + objType + '/' + objName, queryObj, queryOptions, {}, callback);
    	},

    	'$main': function (method, path, queryObj, queryOptions, options, callback) {
    		var self = this;

    		if (this._db && this._db._core) {
    			return this._db._core.api.http('GET', this._db._core.api.server() + this._db._core.api._rootPath + path, {"$query": queryObj, "$options": queryOptions}, options, function (err, data) {
    				var i;

    				if (!err && data) {
    					// Check the type of method we used and operate on the collection accordingly
    					switch (method) {
    						// Find insert
    						case 'GET':
    							self.insert(data);
    							break;

    						// Insert
    						case 'POST':
    							if (data.inserted && data.inserted.length) {
    								self.insert(data.inserted);
    							}
    							break;

    						// Update overwrite
    						case 'PUT':
    						case 'PATCH':
    							if (data instanceof Array) {
    								// Update each document
    								for (i = 0; i < data.length; i++) {
    									self.updateById(data[i]._id, {$overwrite: data[i]});
    								}
    							} else {
    								// Update single document
    								self.updateById(data._id, {$overwrite: data});
    							}
    							break;

    						// Remove
    						case 'DELETE':
    							self.remove(data);
    							break;

    						default:
    							// Nothing to do with this method
    							break;
    					}
    				}

    				// Send the data back to the callback
    				callback(err, data);
    			});
    		} else {
    			throw(this.logIdentifier() + ' Cannot do HTTP for an anonymous collection! (Collection must be attached to a database)');
    		}
    	}
    });

    // Override the Core init to instantiate the plugin
    Core.prototype.init = function () {
    	CoreInit.apply(this, arguments);
    	this.api = new NodeApiClient(this);
    };

    Shared.finishModule('NodeApiClient');

    module.exports = NodeApiClient;
    },{"./Shared":40}],31:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared'),
    	Path = _dereq_('./Path');

    /**
     * The operation class, used to store details about an operation being
     * performed by the database.
     * @param {String} name The name of the operation.
     * @constructor
     */
    var Operation = function (name) {
    	this.pathSolver = new Path();
    	this.counter = 0;
    	this.init.apply(this, arguments);
    };

    Operation.prototype.init = function (name) {
    	this._data = {
    		operation: name, // The name of the operation executed such as "find", "update" etc
    		index: {
    			potential: [], // Indexes that could have potentially been used
    			used: false // The index that was picked to use
    		},
    		steps: [], // The steps taken to generate the query results,
    		time: {
    			startMs: 0,
    			stopMs: 0,
    			totalMs: 0,
    			process: {}
    		},
    		flag: {}, // An object with flags that denote certain execution paths
    		log: [] // Any extra data that might be useful such as warnings or helpful hints
    	};
    };

    Shared.addModule('Operation', Operation);
    Shared.mixin(Operation.prototype, 'Mixin.ChainReactor');

    /**
     * Starts the operation timer.
     */
    Operation.prototype.start = function () {
    	this._data.time.startMs = new Date().getTime();
    };

    /**
     * Adds an item to the operation log.
     * @param {String} event The item to log.
     * @returns {*}
     */
    Operation.prototype.log = function (event) {
    	if (event) {
    		var lastLogTime = this._log.length > 0 ? this._data.log[this._data.log.length - 1].time : 0,
    			logObj = {
    				event: event,
    				time: new Date().getTime(),
    				delta: 0
    			};

    		this._data.log.push(logObj);

    		if (lastLogTime) {
    			logObj.delta = logObj.time - lastLogTime;
    		}

    		return this;
    	}

    	return this._data.log;
    };

    /**
     * Called when starting and ending a timed operation, used to time
     * internal calls within an operation's execution.
     * @param {String} section An operation name.
     * @returns {*}
     */
    Operation.prototype.time = function (section) {
    	if (section !== undefined) {
    		var process = this._data.time.process,
    			processObj = process[section] = process[section] || {};

    		if (!processObj.startMs) {
    			// Timer started
    			processObj.startMs = new Date().getTime();
    			processObj.stepObj = {
    				name: section
    			};

    			this._data.steps.push(processObj.stepObj);
    		} else {
    			processObj.stopMs = new Date().getTime();
    			processObj.totalMs = processObj.stopMs - processObj.startMs;
    			processObj.stepObj.totalMs = processObj.totalMs;
    			delete processObj.stepObj;
    		}

    		return this;
    	}

    	return this._data.time;
    };

    /**
     * Used to set key/value flags during operation execution.
     * @param {String} key
     * @param {String} val
     * @returns {*}
     */
    Operation.prototype.flag = function (key, val) {
    	Eif (key !== undefined && val !== undefined) {
    		this._data.flag[key] = val;
    	} else if (key !== undefined) {
    		return this._data.flag[key];
    	} else {
    		return this._data.flag;
    	}
    };

    Operation.prototype.data = function (path, val, noTime) {
    	if (val !== undefined) {
    		// Assign value to object path
    		this.pathSolver.set(this._data, path, val);

    		return this;
    	}

    	return this.pathSolver.get(this._data, path);
    };

    Operation.prototype.pushData = function (path, val, noTime) {
    	// Assign value to object path
    	this.pathSolver.push(this._data, path, val);
    };

    /**
     * Stops the operation timer.
     */
    Operation.prototype.stop = function () {
    	this._data.time.stopMs = new Date().getTime();
    	this._data.time.totalMs = this._data.time.stopMs - this._data.time.startMs;
    };

    Shared.finishModule('Operation');
    module.exports = Operation;
    },{"./Path":34,"./Shared":40}],32:[function(_dereq_,module,exports){
    "use strict";

    /**
     * Allows a method to accept overloaded calls with different parameters controlling
     * which passed overload function is called.
     * @param {String=} name A name to provide this overload to help identify
     * it if any errors occur during the resolving phase of the overload. This
     * is purely for debug purposes and serves no functional purpose.
     * @param {Object} def The overload definition.
     * @returns {Function}
     * @constructor
     */
    var Overload = function (name, def) {
    	if (!def) {
    		def = name;
    		name = undefined;
    	}

    	Eif (def) {
    		var self = this,
    			index,
    			count,
    			tmpDef,
    			defNewKey,
    			sigIndex,
    			signatures;

    		if (!(def instanceof Array)) {
    			tmpDef = {};

    			// Def is an object, make sure all prop names are devoid of spaces
    			for (index in def) {
    				Eif (def.hasOwnProperty(index)) {
    					defNewKey = index.replace(/ /g, '');

    					// Check if the definition array has a * string in it
    					if (defNewKey.indexOf('*') === -1) {
    						// No * found
    						tmpDef[defNewKey] = def[index];
    					} else {
    						// A * was found, generate the different signatures that this
    						// definition could represent
    						signatures = this.generateSignaturePermutations(defNewKey);

    						for (sigIndex = 0; sigIndex < signatures.length; sigIndex++) {
    							if (!tmpDef[signatures[sigIndex]]) {
    								tmpDef[signatures[sigIndex]] = def[index];
    							}
    						}
    					}
    				}
    			}

    			def = tmpDef;
    		}

    		return function () {
    			var arr = [],
    				lookup,
    				type,
    				overloadName;

    			// Check if we are being passed a key/function object or an array of functions
    			if (def instanceof Array) {
    				// We were passed an array of functions
    				count = def.length;
    				for (index = 0; index < count; index++) {
    					if (def[index].length === arguments.length) {
    						return self.callExtend(this, '$main', def, def[index], arguments);
    					}
    				}
    			} else {
    				// Generate lookup key from arguments
    				// Copy arguments to an array
    				for (index = 0; index < arguments.length; index++) {
    					type = typeof arguments[index];

    					// Handle detecting arrays
    					if (type === 'object' && arguments[index] instanceof Array) {
    						type = 'array';
    					}

    					// Handle been presented with a single undefined argument
    					if (arguments.length === 1 && type === 'undefined') {
    						break;
    					}

    					// Add the type to the argument types array
    					arr.push(type);
    				}

    				lookup = arr.join(',');

    				// Check for an exact lookup match
    				if (def[lookup]) {
    					return self.callExtend(this, '$main', def, def[lookup], arguments);
    				} else {
    					for (index = arr.length; index >= 0; index--) {
    						// Get the closest match
    						lookup = arr.slice(0, index).join(',');

    						if (def[lookup + ',...']) {
    							// Matched against arguments + "any other"
    							return self.callExtend(this, '$main', def, def[lookup + ',...'], arguments);
    						}
    					}
    				}
    			}

    			overloadName = name !== undefined ? name : typeof this.name === 'function' ? this.name() : 'Unknown';

    			console.log('Overload Definition:', def);
    			throw('ForerunnerDB.Overload "' + overloadName + '": Overloaded method does not have a matching signature "' + lookup + '" for the passed arguments: ' + this.jStringify(arr));
    		};
    	}

    	return function () {};
    };

    /**
     * Generates an array of all the different definition signatures that can be
     * created from the passed string with a catch-all wildcard *. E.g. it will
     * convert the signature: string,*,string to all potentials:
     * string,string,string
     * string,number,string
     * string,object,string,
     * string,function,string,
     * string,undefined,string
     *
     * @param {String} str Signature string with a wildcard in it.
     * @returns {Array} An array of signature strings that are generated.
     */
    Overload.prototype.generateSignaturePermutations = function (str) {
    	var signatures = [],
    		newSignature,
    		types = ['array', 'string', 'object', 'number', 'function', 'undefined'],
    		index;

    	if (str.indexOf('*') > -1) {
    		// There is at least one "any" type, break out into multiple keys
    		// We could do this at query time with regular expressions but
    		// would be significantly slower
    		for (index = 0; index < types.length; index++) {
    			newSignature = str.replace('*', types[index]);
    			signatures = signatures.concat(this.generateSignaturePermutations(newSignature));
    		}
    	} else {
    		signatures.push(str);
    	}

    	return signatures;
    };

    Overload.prototype.callExtend = function (context, prop, propContext, func, args) {
    	var tmp,
    		ret;

    	if (context && propContext[prop]) {
    		tmp = context[prop];

    		context[prop] = propContext[prop];
    		ret = func.apply(context, args);
    		context[prop] = tmp;

    		return ret;
    	} else {
    		return func.apply(context, args);
    	}
    };

    module.exports = Overload;
    },{}],33:[function(_dereq_,module,exports){
    "use strict";

    // Import external names locally
    var Shared,
    	Db,
    	Collection,
    	DbDocument;

    Shared = _dereq_('./Shared');

    var Overview = function () {
    	this.init.apply(this, arguments);
    };

    Overview.prototype.init = function (name) {
    	var self = this;

    	this._name = name;
    	this._data = new DbDocument('__FDB__dc_data_' + this._name);
    	this._collData = new Collection();
    	this._sources = [];

    	this._sourceDroppedWrap = function () {
    		self._sourceDropped.apply(self, arguments);
    	};
    };

    Shared.addModule('Overview', Overview);
    Shared.mixin(Overview.prototype, 'Mixin.Common');
    Shared.mixin(Overview.prototype, 'Mixin.ChainReactor');
    Shared.mixin(Overview.prototype, 'Mixin.Constants');
    Shared.mixin(Overview.prototype, 'Mixin.Triggers');
    Shared.mixin(Overview.prototype, 'Mixin.Events');
    Shared.mixin(Overview.prototype, 'Mixin.Tags');

    Collection = _dereq_('./Collection');
    DbDocument = _dereq_('./Document');
    Db = Shared.modules.Db;

    /**
     * Gets / sets the current state.
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(Overview.prototype, 'state');

    Shared.synthesize(Overview.prototype, 'db');
    Shared.synthesize(Overview.prototype, 'name');
    Shared.synthesize(Overview.prototype, 'query', function (val) {
    	var ret = this.$super(val);

    	Eif (val !== undefined) {
    		this._refresh();
    	}

    	return ret;
    });
    Shared.synthesize(Overview.prototype, 'queryOptions', function (val) {
    	var ret = this.$super(val);

    	if (val !== undefined) {
    		this._refresh();
    	}

    	return ret;
    });
    Shared.synthesize(Overview.prototype, 'reduce', function (val) {
    	var ret = this.$super(val);

    	Eif (val !== undefined) {
    		this._refresh();
    	}

    	return ret;
    });

    Overview.prototype.from = function (source) {
    	if (source !== undefined) {
    		if (typeof(source) === 'string') {
    			source = this._db.collection(source);
    		}

    		this._setFrom(source);
    		return this;
    	}

    	return this._sources;
    };

    Overview.prototype.find = function () {
    	return this._collData.find.apply(this._collData, arguments);
    };

    /**
     * Executes and returns the response from the current reduce method
     * assigned to the overview.
     * @returns {*}
     */
    Overview.prototype.exec = function () {
    	var reduceFunc = this.reduce();

    	return reduceFunc ? reduceFunc.apply(this) : undefined;
    };

    Overview.prototype.count = function () {
    	return this._collData.count.apply(this._collData, arguments);
    };

    Overview.prototype._setFrom = function (source) {
    	// Remove all source references
    	while (this._sources.length) {
    		this._removeSource(this._sources[0]);
    	}

    	this._addSource(source);

    	return this;
    };

    Overview.prototype._addSource = function (source) {
    	Iif (source && source.className === 'View') {
    		// The source is a view so IO to the internal data collection
    		// instead of the view proper
    		source = source.privateData();
    		if (this.debug()) {
    			console.log(this.logIdentifier() + ' Using internal private data "' + source.instanceIdentifier() + '" for IO graph linking');
    		}
    	}

    	Eif (this._sources.indexOf(source) === -1) {
    		this._sources.push(source);
    		source.chain(this);

    		source.on('drop', this._sourceDroppedWrap);

    		this._refresh();
    	}
    	return this;
    };

    Overview.prototype._removeSource = function (source) {
    	Iif (source && source.className === 'View') {
    		// The source is a view so IO to the internal data collection
    		// instead of the view proper
    		source = source.privateData();
    		if (this.debug()) {
    			console.log(this.logIdentifier() + ' Using internal private data "' + source.instanceIdentifier() + '" for IO graph linking');
    		}
    	}

    	var sourceIndex = this._sources.indexOf(source);

    	Eif (sourceIndex > -1) {
    		this._sources.splice(source, 1);
    		source.unChain(this);

    		source.off('drop', this._sourceDroppedWrap);

    		this._refresh();
    	}

    	return this;
    };

    Overview.prototype._sourceDropped = function (source) {
    	Eif (source) {
    		// Source was dropped, remove from overview
    		this._removeSource(source);
    	}
    };

    Overview.prototype._refresh = function () {
    	if (!this.isDropped()) {
    		if (this._sources && this._sources[0]) {
    			this._collData.primaryKey(this._sources[0].primaryKey());
    			var tempArr = [],
    				i;

    			for (i = 0; i < this._sources.length; i++) {
    				tempArr = tempArr.concat(this._sources[i].find(this._query, this._queryOptions));
    			}

    			this._collData.setData(tempArr);
    		}

    		// Now execute the reduce method
    		if (this._reduce) {
    			var reducedData = this._reduce.apply(this);

    			// Update the document with the newly returned data
    			this._data.setData(reducedData);
    		}
    	}
    };

    Overview.prototype._chainHandler = function (chainPacket) {
    	switch (chainPacket.type) {
    		case 'setData':
    		case 'insert':
    		case 'update':
    		case 'remove':
    			this._refresh();
    			break;

    		default:
    			break;
    	}
    };

    /**
     * Gets the module's internal data collection.
     * @returns {Collection}
     */
    Overview.prototype.data = function () {
    	return this._data;
    };

    Overview.prototype.drop = function (callback) {
    	Eif (!this.isDropped()) {
    		this._state = 'dropped';

    		delete this._data;
    		delete this._collData;

    		// Remove all source references
    		while (this._sources.length) {
    			this._removeSource(this._sources[0]);
    		}

    		delete this._sources;

    		Eif (this._db && this._name) {
    			delete this._db._overview[this._name];
    		}

    		this.emit('drop', this);

    		Iif (callback) { callback(false, true); }

    		delete this._listeners;
    	}

    	return true;
    };

    Db.prototype.overview = function (name) {
    	var self = this;

    	Eif (name) {
    		// Handle being passed an instance
    		Iif (name instanceof Overview) {
    			return name;
    		}

    		Iif (this._overview && this._overview[name]) {
    			return this._overview[name];
    		}

    		this._overview = this._overview || {};
    		this._overview[name] = new Overview(name).db(this);

    		self.emit('create', self._overview[name], 'overview', name);

    		return this._overview[name];
    	} else {
    		// Return an object of collection data
    		return this._overview || {};
    	}
    };

    /**
     * Returns an array of overviews the DB currently has.
     * @returns {Array} An array of objects containing details of each overview
     * the database is currently managing.
     */
    Db.prototype.overviews = function () {
    	var arr = [],
    		item,
    		i;

    	for (i in this._overview) {
    		if (this._overview.hasOwnProperty(i)) {
    			item = this._overview[i];

    			arr.push({
    				name: i,
    				count: item.count(),
    				linked: item.isLinked !== undefined ? item.isLinked() : false
    			});
    		}
    	}

    	return arr;
    };

    Shared.finishModule('Overview');
    module.exports = Overview;
    },{"./Collection":7,"./Document":11,"./Shared":40}],34:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared');

    /**
     * Path object used to resolve object paths and retrieve data from
     * objects by using paths.
     * @param {String=} path The path to assign.
     * @constructor
     */
    var Path = function (path) {
    	this.init.apply(this, arguments);
    };

    Path.prototype.init = function (path) {
    	if (path) {
    		this.path(path);
    	}
    };

    Shared.addModule('Path', Path);
    Shared.mixin(Path.prototype, 'Mixin.Common');
    Shared.mixin(Path.prototype, 'Mixin.ChainReactor');

    /**
     * Gets / sets the given path for the Path instance.
     * @param {String=} path The path to assign.
     */
    Path.prototype.path = function (path) {
    	Eif (path !== undefined) {
    		this._path = this.clean(path);
    		this._pathParts = this._path.split('.');
    		return this;
    	}

    	return this._path;
    };

    /**
     * Tests if the passed object has the paths that are specified and that
     * a value exists in those paths.
     * @param {Object} testKeys The object describing the paths to test for.
     * @param {Object} testObj The object to test paths against.
     * @returns {Boolean} True if the object paths exist.
     */
    Path.prototype.hasObjectPaths = function (testKeys, testObj) {
    	var result = true,
    		i;

    	for (i in testKeys) {
    		if (testKeys.hasOwnProperty(i)) {
    			if (testObj[i] === undefined) {
    				return false;
    			}

    			if (typeof testKeys[i] === 'object') {
    				// Recurse object
    				result = this.hasObjectPaths(testKeys[i], testObj[i]);

    				// Should we exit early?
    				if (!result) {
    					return false;
    				}
    			}
    		}
    	}

    	return result;
    };

    /**
     * Counts the total number of key endpoints in the passed object.
     * @param {Object} testObj The object to count key endpoints for.
     * @returns {Number} The number of endpoints.
     */
    Path.prototype.countKeys = function (testObj) {
    	var totalKeys = 0,
    		i;

    	for (i in testObj) {
    		if (testObj.hasOwnProperty(i)) {
    			if (testObj[i] !== undefined) {
    				if (typeof testObj[i] !== 'object') {
    					totalKeys++;
    				} else {
    					totalKeys += this.countKeys(testObj[i]);
    				}
    			}
    		}
    	}

    	return totalKeys;
    };

    /**
     * Tests if the passed object has the paths that are specified and that
     * a value exists in those paths and if so returns the number matched.
     * @param {Object} testKeys The object describing the paths to test for.
     * @param {Object} testObj The object to test paths against.
     * @returns {Object} Stats on the matched keys
     */
    Path.prototype.countObjectPaths = function (testKeys, testObj) {
    	var matchData,
    		matchedKeys = {},
    		matchedKeyCount = 0,
    		totalKeyCount = 0,
    		i;

    	for (i in testObj) {
    		if (testObj.hasOwnProperty(i)) {
    			if (typeof testObj[i] === 'object') {
    				// The test / query object key is an object, recurse
    				matchData = this.countObjectPaths(testKeys[i], testObj[i]);

    				matchedKeys[i] = matchData.matchedKeys;
    				totalKeyCount += matchData.totalKeyCount;
    				matchedKeyCount += matchData.matchedKeyCount;
    			} else {
    				// The test / query object has a property that is not an object so add it as a key
    				totalKeyCount++;

    				// Check if the test keys also have this key and it is also not an object
    				if (testKeys && testKeys[i] && typeof testKeys[i] !== 'object') {
    					matchedKeys[i] = true;
    					matchedKeyCount++;
    				} else {
    					matchedKeys[i] = false;
    				}
    			}
    		}
    	}

    	return {
    		matchedKeys: matchedKeys,
    		matchedKeyCount: matchedKeyCount,
    		totalKeyCount: totalKeyCount
    	};
    };

    /**
     * Takes a non-recursive object and converts the object hierarchy into
     * a path string.
     * @param {Object} obj The object to parse.
     * @param {Boolean=} withValue If true will include a 'value' key in the returned
     * object that represents the value the object path points to.
     * @returns {Object}
     */
    Path.prototype.parse = function (obj, withValue) {
    	var paths = [],
    		path = '',
    		resultData,
    		i, k;

    	for (i in obj) {
    		Eif (obj.hasOwnProperty(i)) {
    			// Set the path to the key
    			path = i;

    			if (typeof(obj[i]) === 'object') {
    				if (withValue) {
    					resultData = this.parse(obj[i], withValue);

    					for (k = 0; k < resultData.length; k++) {
    						paths.push({
    							path: path + '.' + resultData[k].path,
    							value: resultData[k].value
    						});
    					}
    				} else {
    					resultData = this.parse(obj[i]);

    					for (k = 0; k < resultData.length; k++) {
    						paths.push({
    							path: path + '.' + resultData[k].path
    						});
    					}
    				}
    			} else {
    				if (withValue) {
    					paths.push({
    						path: path,
    						value: obj[i]
    					});
    				} else {
    					paths.push({
    						path: path
    					});
    				}
    			}
    		}
    	}

    	return paths;
    };

    /**
     * Takes a non-recursive object and converts the object hierarchy into
     * an array of path strings that allow you to target all possible paths
     * in an object.
     *
     * The options object accepts an "ignore" field with a regular expression
     * as the value. If any key matches the expression it is not included in
     * the results.
     *
     * The options object accepts a boolean "verbose" field. If set to true
     * the results will include all paths leading up to endpoints as well as
     * they endpoints themselves.
     *
     * @returns {Array}
     */
    Path.prototype.parseArr = function (obj, options) {
    	options = options || {};
    	return this._parseArr(obj, '', [], options);
    };

    Path.prototype._parseArr = function (obj, path, paths, options) {
    	var i,
    		newPath = '';

    	path = path || '';
    	paths = paths || [];

    	for (i in obj) {
    		Eif (obj.hasOwnProperty(i)) {
    			if (!options.ignore || (options.ignore && !options.ignore.test(i))) {
    				if (path) {
    					newPath = path + '.' + i;
    				} else {
    					newPath = i;
    				}

    				if (typeof(obj[i]) === 'object') {
    					if (options.verbose) {
    						paths.push(newPath);
    					}

    					this._parseArr(obj[i], newPath, paths, options);
    				} else {
    					paths.push(newPath);
    				}
    			}
    		}
    	}

    	return paths;
    };

    /**
     * Sets a value on an object for the specified path.
     * @param {Object} obj The object to update.
     * @param {String} path The path to update.
     * @param {*} val The value to set the object path to.
     * @returns {*}
     */
    Path.prototype.set = function (obj, path, val) {
    	if (obj !== undefined && path !== undefined) {
    		var pathParts,
    				part;

    		path = this.clean(path);
    		pathParts = path.split('.');

    		part = pathParts.shift();

    		if (pathParts.length) {
    			// Generate the path part in the object if it does not already exist
    			obj[part] = obj[part] || {};

    			// Recurse
    			this.set(obj[part], pathParts.join('.'), val);
    		} else {
    			// Set the value
    			obj[part] = val;
    		}
    	}

    	return obj;
    };

    /**
     * Gets a single value from the passed object and given path.
     * @param {Object} obj The object to inspect.
     * @param {String} path The path to retrieve data from.
     * @returns {*}
     */
    Path.prototype.get = function (obj, path) {
    	return this.value(obj, path)[0];
    };

    /**
     * Gets the value(s) that the object contains for the currently assigned path string.
     * @param {Object} obj The object to evaluate the path against.
     * @param {String=} path A path to use instead of the existing one passed in path().
     * @param {Object=} options An optional options object.
     * @returns {Array} An array of values for the given path.
     */
    Path.prototype.value = function (obj, path, options) {
    	var pathParts,
    		arr,
    		arrCount,
    		objPart,
    		objPartParent,
    		valuesArr,
    		returnArr,
    		i, k;

    	// Detect early exit
    	if (path && path.indexOf('.') === -1) {
    		return [obj[path]];
    	}

    	Eif (obj !== undefined && typeof obj === 'object') {
    		if (!options || options && !options.skipArrCheck) {
    			// Check if we were passed an array of objects and if so,
    			// iterate over the array and return the value from each
    			// array item
    			if (obj instanceof Array) {
    				returnArr = [];

    				for (i = 0; i < obj.length; i++) {
    					returnArr.push(this.get(obj[i], path));
    				}

    				return returnArr;
    			}
    		}

    		valuesArr = [];

    		if (path !== undefined) {
    			path = this.clean(path);
    			pathParts = path.split('.');
    		}

    		arr = pathParts || this._pathParts;
    		arrCount = arr.length;
    		objPart = obj;

    		for (i = 0; i < arrCount; i++) {
    			objPart = objPart[arr[i]];

    			if (objPartParent instanceof Array) {
    				// Search inside the array for the next key
    				for (k = 0; k < objPartParent.length; k++) {
    					valuesArr = valuesArr.concat(this.value(objPartParent, k + '.' + arr[i], {skipArrCheck: true}));
    				}

    				return valuesArr;
    			} else {
    				if (!objPart || typeof(objPart) !== 'object') {
    					break;
    				}
    			}

    			objPartParent = objPart;
    		}

    		return [objPart];
    	} else {
    		return [];
    	}
    };

    /**
     * Push a value to an array on an object for the specified path.
     * @param {Object} obj The object to update.
     * @param {String} path The path to the array to push to.
     * @param {*} val The value to push to the array at the object path.
     * @returns {*}
     */
    Path.prototype.push = function (obj, path, val) {
    	if (obj !== undefined && path !== undefined) {
    		var pathParts,
    			part;

    		path = this.clean(path);
    		pathParts = path.split('.');

    		part = pathParts.shift();

    		if (pathParts.length) {
    			// Generate the path part in the object if it does not already exist
    			obj[part] = obj[part] || {};

    			// Recurse
    			this.set(obj[part], pathParts.join('.'), val);
    		} else {
    			// Set the value
    			obj[part] = obj[part] || [];

    			if (obj[part] instanceof Array) {
    				obj[part].push(val);
    			} else {
    				throw('ForerunnerDB.Path: Cannot push to a path whose endpoint is not an array!');
    			}
    		}
    	}

    	return obj;
    };

    /**
     * Gets the value(s) that the object contains for the currently assigned path string
     * with their associated keys.
     * @param {Object} obj The object to evaluate the path against.
     * @param {String=} path A path to use instead of the existing one passed in path().
     * @returns {Array} An array of values for the given path with the associated key.
     */
    Path.prototype.keyValue = function (obj, path) {
    	var pathParts,
    		arr,
    		arrCount,
    		objPart,
    		objPartParent,
    		objPartHash,
    		i;

    	Eif (path !== undefined) {
    		path = this.clean(path);
    		pathParts = path.split('.');
    	}

    	arr = pathParts || this._pathParts;
    	arrCount = arr.length;
    	objPart = obj;

    	for (i = 0; i < arrCount; i++) {
    		objPart = objPart[arr[i]];

    		if (!objPart || typeof(objPart) !== 'object') {
    			objPartHash = arr[i] + ':' + objPart;
    			break;
    		}

    		objPartParent = objPart;
    	}

    	return objPartHash;
    };

    /**
     * Sets a value on an object for the specified path.
     * @param {Object} obj The object to update.
     * @param {String} path The path to update.
     * @param {*} val The value to set the object path to.
     * @returns {*}
     */
    Path.prototype.set = function (obj, path, val) {
    	Eif (obj !== undefined && path !== undefined) {
    		var pathParts,
    			part;

    		path = this.clean(path);
    		pathParts = path.split('.');

    		part = pathParts.shift();

    		if (pathParts.length) {
    			// Generate the path part in the object if it does not already exist
    			obj[part] = obj[part] || {};

    			// Recurse
    			this.set(obj[part], pathParts.join('.'), val);
    		} else {
    			// Set the value
    			obj[part] = val;
    		}
    	}

    	return obj;
    };

    /**
     * Removes leading period (.) from string and returns it.
     * @param {String} str The string to clean.
     * @returns {*}
     */
    Path.prototype.clean = function (str) {
    	if (str.substr(0, 1) === '.') {
    		str = str.substr(1, str.length -1);
    	}

    	return str;
    };

    Shared.finishModule('Path');
    module.exports = Path;
    },{"./Shared":40}],35:[function(_dereq_,module,exports){
    "use strict";

    // Import external names locally
    var Shared = _dereq_('./Shared'),
    	async = _dereq_('async'),
    	localforage = _dereq_('localforage'),
    	FdbCompress = _dereq_('./PersistCompress'),// jshint ignore:line
    	FdbCrypto = _dereq_('./PersistCrypto'),// jshint ignore:line
    	Db,
    	Collection,
    	CollectionDrop,
    	CollectionGroup,
    	CollectionInit,
    	DbInit,
    	DbDrop,
    	Persist,
    	Overload;//,
    	//DataVersion = '2.0';

    /**
     * The persistent storage class handles loading and saving data to browser
     * storage.
     * @constructor
     */
    Persist = function () {
    	this.init.apply(this, arguments);
    };

    /**
     * The local forage library.
     */
    Persist.prototype.localforage = localforage;

    /**
     * The init method that can be overridden or extended.
     * @param {Db} db The ForerunnerDB database instance.
     */
    Persist.prototype.init = function (db) {
    	var self = this;

    	this._encodeSteps = [
    		function () { return self._encode.apply(self, arguments); }
    	];
    	this._decodeSteps = [
    		function () { return self._decode.apply(self, arguments); }
    	];

    	// Check environment
    	Eif (db.isClient()) {
    		Eif (window.Storage !== undefined) {
    			this.mode('localforage');

    			localforage.config({
    				driver: [
    					localforage.INDEXEDDB,
    					localforage.WEBSQL,
    					localforage.LOCALSTORAGE
    				],
    				name: String(db.core().name()),
    				storeName: 'FDB'
    			});
    		}
    	}
    };

    Shared.addModule('Persist', Persist);
    Shared.mixin(Persist.prototype, 'Mixin.ChainReactor');
    Shared.mixin(Persist.prototype, 'Mixin.Common');

    Db = Shared.modules.Db;
    Collection = _dereq_('./Collection');
    CollectionDrop = Collection.prototype.drop;
    CollectionGroup = _dereq_('./CollectionGroup');
    CollectionInit = Collection.prototype.init;
    DbInit = Db.prototype.init;
    DbDrop = Db.prototype.drop;
    Overload = Shared.overload;

    /**
     * Gets / sets the auto flag which determines if the persistence module
     * will automatically load data for collections the first time they are
     * accessed and save data whenever it changes. This is disabled by
     * default.
     * @param {Boolean} val Set to true to enable, false to disable
     * @returns {*}
     */
    Shared.synthesize(Persist.prototype, 'auto', function (val) {
    	var self = this;

    	if (val !== undefined) {
    		if (val) {
    			// Hook db events
    			this._db.on('create', function () { self._autoLoad.apply(self, arguments); });
    			this._db.on('change', function () { self._autoSave.apply(self, arguments); });

    			if (this._db.debug()) {
    				console.log(this._db.logIdentifier() + ' Automatic load/save enabled');
    			}
    		} else {
    			// Un-hook db events
    			this._db.off('create', this._autoLoad);
    			this._db.off('change', this._autoSave);

    			if (this._db.debug()) {
    				console.log(this._db.logIdentifier() + ' Automatic load/save disbled');
    			}
    		}
    	}

    	return this.$super.call(this, val);
    });

    Persist.prototype._autoLoad = function (obj, objType, name) {
    	var self = this;

    	if (typeof obj.load === 'function') {
    		if (self._db.debug()) {
    			console.log(self._db.logIdentifier() + ' Auto-loading data for ' + objType + ':', name);
    		}

    		obj.load(function (err, data) {
    			if (err && self._db.debug()) {
    				console.log(self._db.logIdentifier() + ' Automatic load failed:', err);
    			}

    			self.emit('load', err, data);
    		});
    	} else {
    		if (self._db.debug()) {
    			console.log(self._db.logIdentifier() + ' Auto-load for ' + objType + ':', name, 'no load method, skipping');
    		}
    	}
    };

    Persist.prototype._autoSave = function (obj, objType, name) {
    	var self = this;

    	if (typeof obj.save === 'function') {
    		if (self._db.debug()) {
    			console.log(self._db.logIdentifier() + ' Auto-saving data for ' + objType + ':', name);
    		}

    		obj.save(function (err, data) {
    			if (err && self._db.debug()) {
    				console.log(self._db.logIdentifier() + ' Automatic save failed:', err);
    			}

    			self.emit('save', err, data);
    		});
    	}
    };

    /**
     * Gets / sets the persistent storage mode (the library used
     * to persist data to the browser - defaults to localForage).
     * @param {String} type The library to use for storage. Defaults
     * to localForage.
     * @returns {*}
     */
    Persist.prototype.mode = function (type) {
    	if (type !== undefined) {
    		this._mode = type;
    		return this;
    	}

    	return this._mode;
    };

    /**
     * Gets / sets the driver used when persisting data.
     * @param {String} val Specify the driver type (LOCALSTORAGE,
     * WEBSQL or INDEXEDDB)
     * @returns {*}
     */
    Persist.prototype.driver = function (val) {
    	Iif (val !== undefined) {
    		switch (val.toUpperCase()) {
    			case 'LOCALSTORAGE':
    				localforage.setDriver(localforage.LOCALSTORAGE);
    				break;

    			case 'WEBSQL':
    				localforage.setDriver(localforage.WEBSQL);
    				break;

    			case 'INDEXEDDB':
    				localforage.setDriver(localforage.INDEXEDDB);
    				break;

    			default:
    				throw('ForerunnerDB.Persist: The persistence driver you have specified is not found. Please use either IndexedDB, WebSQL or LocalStorage!');
    		}

    		return this;
    	}

    	return localforage.driver();
    };

    /**
     * Starts a decode waterfall process.
     * @param {*} val The data to be decoded.
     * @param {Function} finished The callback to pass final data to.
     */
    Persist.prototype.decode = function (val, finished) {
    	async.waterfall([function (callback) {
    		Eif (callback) { callback(false, val, {}); }
    	}].concat(this._decodeSteps), finished);
    };

    /**
     * Starts an encode waterfall process.
     * @param {*} val The data to be encoded.
     * @param {Function} finished The callback to pass final data to.
     */
    Persist.prototype.encode = function (val, finished) {
    	async.waterfall([function (callback) {
    		Eif (callback) { callback(false, val, {}); }
    	}].concat(this._encodeSteps), finished);
    };

    Shared.synthesize(Persist.prototype, 'encodeSteps');
    Shared.synthesize(Persist.prototype, 'decodeSteps');

    /**
     * Adds an encode/decode step to the persistent storage system so
     * that you can add custom functionality.
     * @param {Function} encode The encode method called with the data from the
     * previous encode step. When your method is complete it MUST call the
     * callback method. If you provide anything other than false to the err
     * parameter the encoder will fail and throw an error.
     * @param {Function} decode The decode method called with the data from the
     * previous decode step. When your method is complete it MUST call the
     * callback method. If you provide anything other than false to the err
     * parameter the decoder will fail and throw an error.
     * @param {Number=} index Optional index to add the encoder step to. This
     * allows you to place a step before or after other existing steps. If not
     * provided your step is placed last in the list of steps. For instance if
     * you are providing an encryption step it makes sense to place this last
     * since all previous steps will then have their data encrypted by your
     * final step.
     */
    Persist.prototype.addStep = new Overload({
    	'object': function (obj) {
    		this.$main.call(this, function objEncode () { obj.encode.apply(obj, arguments); }, function objDecode () { obj.decode.apply(obj, arguments); }, 0);
    	},

    	'function, function': function (encode, decode) {
    		this.$main.call(this, encode, decode, 0);
    	},

    	'function, function, number': function (encode, decode, index) {
    		this.$main.call(this, encode, decode, index);
    	},

    	$main: function (encode, decode, index) {
    		Eif (index === 0 || index === undefined) {
    			this._encodeSteps.push(encode);
    			this._decodeSteps.unshift(decode);
    		} else {
    			// Place encoder step at index then work out correct
    			// index to place decoder step
    			this._encodeSteps.splice(index, 0, encode);
    			this._decodeSteps.splice(this._decodeSteps.length - index, 0, decode);
    		}
    	}
    });

    Persist.prototype.unwrap = function (dataStr) {
    	var parts = dataStr.split('::fdb::'),
    		data;

    	switch (parts[0]) {
    		case 'json':
    			data = this.jParse(parts[1]);
    			break;

    		case 'raw':
    			data = parts[1];
    			break;

    		default:
    			break;
    	}
    };

    /**
     * Takes encoded data and decodes it for use as JS native objects and arrays.
     * @param {String} val The currently encoded string data.
     * @param {Object} meta Meta data object that can be used to pass back useful
     * supplementary data.
     * @param {Function} finished The callback method to call when decoding is
     * completed.
     * @private
     */
    Persist.prototype._decode = function (val, meta, finished) {
    	var parts,
    		data;

    	if (val) {
    		parts = val.split('::fdb::');

    		switch (parts[0]) {
    			case 'json':
    				data = this.jParse(parts[1]);
    				break;

    			case 'raw':
    				data = parts[1];
    				break;

    			default:
    				break;
    		}

    		Eif (data) {
    			meta.foundData = true;
    			meta.rowCount = data.length || 0;
    		} else {
    			meta.foundData = false;
    			meta.rowCount = 0;
    		}

    		Eif (finished) {
    			finished(false, data, meta);
    		}
    	} else {
    		meta.foundData = false;
    		meta.rowCount = 0;

    		Eif (finished) {
    			finished(false, val, meta);
    		}
    	}
    };

    /**
     * Takes native JS data and encodes it for for storage as a string.
     * @param {Object} val The current un-encoded data.
     * @param {Object} meta Meta data object that can be used to pass back useful
     * supplementary data.
     * @param {Function} finished The callback method to call when encoding is
     * completed.
     * @private
     */
    Persist.prototype._encode = function (val, meta, finished) {
    	var data = val;

    	Eif (typeof val === 'object') {
    		val = 'json::fdb::' + this.jStringify(val);
    	} else {
    		val = 'raw::fdb::' + val;
    	}

    	Eif (data) {
    		meta.foundData = true;
    		meta.rowCount = data.length || 0;
    	} else {
    		meta.foundData = false;
    		meta.rowCount = 0;
    	}

    	Eif (finished) {
    		finished(false, val, meta);
    	}
    };

    /**
     * Encodes passed data and then stores it in the browser's persistent
     * storage layer.
     * @param {String} key The key to store the data under in the persistent
     * storage.
     * @param {Object} data The data to store under the key.
     * @param {Function=} callback The method to call when the save process
     * has completed.
     */
    Persist.prototype.save = function (key, data, callback) {
    	switch (this.mode()) {
    		case 'localforage':
    			this.encode(data, function (err, data, tableStats) {
    				localforage.setItem(key, data).then(function (data) {
    					Eif (callback) { callback(false, data, tableStats); }
    				}, function (err) {
    					if (callback) { callback(err); }
    				});
    			});
    			break;

    		default:
    			if (callback) { callback('No data handler.'); }
    			break;
    	}
    };

    /**
     * Loads and decodes data from the passed key.
     * @param {String} key The key to retrieve data from in the persistent
     * storage.
     * @param {Function=} callback The method to call when the load process
     * has completed.
     */
    Persist.prototype.load = function (key, callback) {
    	var self = this;

    	switch (this.mode()) {
    		case 'localforage':
    			localforage.getItem(key).then(function (val) {
    				self.decode(val, callback);
    			}, function (err) {
    				if (callback) { callback(err); }
    			});
    			break;

    		default:
    			if (callback) { callback('No data handler or unrecognised data type.');	}
    			break;
    	}
    };

    /**
     * Deletes data in persistent storage stored under the passed key.
     * @param {String} key The key to drop data for in the storage.
     * @param {Function=} callback The method to call when the data is dropped.
     */
    Persist.prototype.drop = function (key, callback) {
    	switch (this.mode()) {
    		case 'localforage':
    			localforage.removeItem(key).then(function () {
    				if (callback) { callback(false); }
    			}, function (err) {
    				if (callback) { callback(err); }
    			});
    			break;

    		default:
    			if (callback) { callback('No data handler or unrecognised data type.'); }
    			break;
    	}

    };

    // Extend the Collection prototype with persist methods
    Collection.prototype.drop = new Overload({
    	/**
    	 * Drop collection and persistent storage.
    	 */
    	'': function () {
    		if (!this.isDropped()) {
    			this.drop(true);
    		}
    	},

    	/**
    	 * Drop collection and persistent storage with callback.
    	 * @param {Function} callback Callback method.
    	 */
    	'function': function (callback) {
    		Eif (!this.isDropped()) {
    			this.drop(true, callback);
    		}
    	},

    	/**
    	 * Drop collection and optionally drop persistent storage.
    	 * @param {Boolean} removePersistent True to drop persistent storage, false to keep it.
    	 */
    	'boolean': function (removePersistent) {
    		Eif (!this.isDropped()) {
    			// Remove persistent storage
    			if (removePersistent) {
    				Eif (this._name) {
    					Eif (this._db) {
    						// Drop the collection data from storage
    						this._db.persist.drop(this._db._name + '-' + this._name);
    						this._db.persist.drop(this._db._name + '-' + this._name + '-metaData');
    					}
    				} else {
    					throw('ForerunnerDB.Persist: Cannot drop a collection\'s persistent storage when no name assigned to collection!');
    				}
    			}

    			// Call the original method
    			CollectionDrop.call(this);
    		}
    	},

    	/**
    	 * Drop collections and optionally drop persistent storage with callback.
    	 * @param {Boolean} removePersistent True to drop persistent storage, false to keep it.
    	 * @param {Function} callback Callback method.
    	 */
    	'boolean, function': function (removePersistent, callback) {
    		var self = this;

    		Eif (!this.isDropped()) {
    			// Remove persistent storage
    			Eif (removePersistent) {
    				Eif (this._name) {
    					Eif (this._db) {
    						// Drop the collection data from storage
    						this._db.persist.drop(this._db._name + '-' + this._name, function () {
    							self._db.persist.drop(self._db._name + '-' + self._name + '-metaData', callback);
    						});

    						return CollectionDrop.call(this);
    					} else {
    						if (callback) { callback('Cannot drop a collection\'s persistent storage when the collection is not attached to a database!'); }
    					}
    				} else {
    					if (callback) { callback('Cannot drop a collection\'s persistent storage when no name assigned to collection!'); }
    				}
    			} else {
    				// Call the original method
    				return CollectionDrop.call(this, callback);
    			}
    		}
    	}
    });

    /**
     * Saves an entire collection's data to persistent storage.
     * @param {Function=} callback The method to call when the save function
     * has completed.
     */
    Collection.prototype.save = function (callback) {
    	var self = this,
    		processSave;

    	Eif (self._name) {
    		Eif (self._db) {
    			processSave = function () {
    				// Save the collection data
    				self._db.persist.save(self._db._name + '-' + self._name, self._data, function (err, data, tableStats) {
    					Eif (!err) {
    						self._db.persist.save(self._db._name + '-' + self._name + '-metaData', self.metaData(), function (err, data, metaStats) {
    							Eif (callback) { callback(err, data, tableStats, metaStats); }
    						});
    					} else {
    						if (callback) { callback(err); }
    					}
    				});
    			};

    			// Check for processing queues
    			Iif (self.isProcessingQueue()) {
    				// Hook queue complete to process save
    				self.on('queuesComplete', function () {
    					processSave();
    				});
    			} else {
    				// Process save immediately
    				processSave();
    			}
    		} else {
    			if (callback) { callback('Cannot save a collection that is not attached to a database!'); }
    		}
    	} else {
    		if (callback) { callback('Cannot save a collection with no assigned name!'); }
    	}
    };

    /**
     * Loads an entire collection's data from persistent storage.
     * @param {Function=} callback The method to call when the load function
     * has completed.
     */
    Collection.prototype.load = function (callback) {
    	var self = this;

    	Eif (self._name) {
    		Eif (self._db) {
    			// Load the collection data
    			self._db.persist.load(self._db._name + '-' + self._name, function (err, data, tableStats) {
    				Eif (!err) {
    					if (data) {
    						// Remove all previous data
    						self.remove({});
    						self.insert(data);
    						//self.setData(data);
    					}

    					// Now load the collection's metadata
    					self._db.persist.load(self._db._name + '-' + self._name + '-metaData', function (err, data, metaStats) {
    						Eif (!err) {
    							if (data) {
    								self.metaData(data);
    							}
    						}

    						Eif (callback) { callback(err, tableStats, metaStats); }
    					});
    				} else {
    					if (callback) { callback(err); }
    				}
    			});
    		} else {
    			if (callback) { callback('Cannot load a collection that is not attached to a database!'); }
    		}
    	} else {
    		if (callback) { callback('Cannot load a collection with no assigned name!'); }
    	}
    };

    /**
     * Gets the data that represents this collection for easy storage using
     * a third-party method / plugin instead of using the standard persistent
     * storage system.
     * @param {Function} callback The method to call with the data response.
     */
    Collection.prototype.saveCustom = function (callback) {
    	var self = this,
    		myData = {},
    		processSave;

    	if (self._name) {
    		if (self._db) {
    			processSave = function () {
    				self.encode(self._data, function (err, data, tableStats) {
    					if (!err) {
    						myData.data = {
    							name: self._db._name + '-' + self._name,
    							store: data,
    							tableStats: tableStats
    						};

    						self.encode(self._data, function (err, data, tableStats) {
    							if (!err) {
    								myData.metaData = {
    									name: self._db._name + '-' + self._name + '-metaData',
    									store: data,
    									tableStats: tableStats
    								};

    								callback(false, myData);
    							} else {
    								callback(err);
    							}
    						});
    					} else {
    						callback(err);
    					}
    				});
    			};

    			// Check for processing queues
    			if (self.isProcessingQueue()) {
    				// Hook queue complete to process save
    				self.on('queuesComplete', function () {
    					processSave();
    				});
    			} else {
    				// Process save immediately
    				processSave();
    			}
    		} else {
    			if (callback) { callback('Cannot save a collection that is not attached to a database!'); }
    		}
    	} else {
    		if (callback) { callback('Cannot save a collection with no assigned name!'); }
    	}
    };

    /**
     * Loads custom data loaded by a third-party plugin into the collection.
     * @param {Object} myData Data object previously saved by using saveCustom()
     * @param {Function} callback A callback method to receive notification when
     * data has loaded.
     */
    Collection.prototype.loadCustom = function (myData, callback) {
    	var self = this;

    	if (self._name) {
    		if (self._db) {
    			if (myData.data && myData.data.store) {
    				if (myData.metaData && myData.metaData.store) {
    					self.decode(myData.data.store, function (err, data, tableStats) {
    						if (!err) {
    							if (data) {
    								// Remove all previous data
    								self.remove({});
    								self.insert(data);

    								self.decode(myData.metaData.store, function (err, data, metaStats) {
    									if (!err) {
    										if (data) {
    											self.metaData(data);

    											if (callback) { callback(err, tableStats, metaStats); }
    										}
    									} else {
    										callback(err);
    									}
    								});
    							}
    						} else {
    							callback(err);
    						}
    					});
    				} else {
    					callback('No "metaData" key found in passed object!');
    				}
    			} else {
    				callback('No "data" key found in passed object!');
    			}
    		} else {
    			if (callback) { callback('Cannot load a collection that is not attached to a database!'); }
    		}
    	} else {
    		if (callback) { callback('Cannot load a collection with no assigned name!'); }
    	}
    };

    // Override the DB init to instantiate the plugin
    Db.prototype.init = function () {
    	DbInit.apply(this, arguments);
    	this.persist = new Persist(this);
    };

    Db.prototype.load = new Overload({
    	/**
    	 * Loads an entire database's data from persistent storage.
    	 * @param {Function=} callback The method to call when the load function
    	 * has completed.
    	 */
    	'function': function (callback) {
    		this.$main.call(this, {}, callback);
    	},

    	'object, function': function (myData, callback) {
    		this.$main.call(this, myData, callback);
    	},

    	'$main': function (myData, callback) {
    		// Loop the collections in the database
    		var obj = this._collection,
    			keys = obj.keys(),
    			keyCount = keys.length,
    			loadCallback,
    			index;

    		loadCallback = function (err) {
    			if (!err) {
    				keyCount--;

    				if (keyCount === 0) {
    					if (callback) {
    						callback(false);
    					}
    				}
    			} else {
    				if (callback) {
    					callback(err);
    				}
    			}
    		};

    		for (index in obj) {
    			if (obj.hasOwnProperty(index)) {
    				// Call the collection load method
    				if (!myData) {
    					obj[index].load(loadCallback);
    				} else {
    					obj[index].loadCustom(myData, loadCallback);
    				}
    			}
    		}
    	}
    });

    Db.prototype.save = new Overload({
    	/**
    	 * Saves an entire database's data to persistent storage.
    	 * @param {Function=} callback The method to call when the save function
    	 * has completed.
    	 */
    	'function': function (callback) {
    		this.$main.call(this, {}, callback);
    	},

    	'object, function': function (options, callback) {
    		this.$main.call(this, options, callback);
    	},

    	'$main': function (options, callback) {
    		// Loop the collections in the database
    		var obj = this._collection,
    			keys = obj.keys(),
    			keyCount = keys.length,
    			saveCallback,
    			index;

    		saveCallback = function (err) {
    			if (!err) {
    				keyCount--;

    				if (keyCount === 0) {
    					if (callback) { callback(false); }
    				}
    			} else {
    				if (callback) { callback(err); }
    			}
    		};

    		for (index in obj) {
    			if (obj.hasOwnProperty(index)) {
    				// Call the collection save method
    				if (!options.custom) {
    					obj[index].save(saveCallback);
    				} else {
    					obj[index].saveCustom(saveCallback);
    				}
    			}
    		}
    	}
    });

    Shared.finishModule('Persist');
    module.exports = Persist;
    },{"./Collection":7,"./CollectionGroup":8,"./PersistCompress":36,"./PersistCrypto":37,"./Shared":40,"async":43,"localforage":79}],36:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared'),
    	pako = _dereq_('pako');

    var Plugin = function () {
    	this.init.apply(this, arguments);
    };

    Plugin.prototype.init = function (options) {

    };

    Shared.mixin(Plugin.prototype, 'Mixin.Common');

    Plugin.prototype.encode = function (val, meta, finished) {
    	var wrapper = {
    			data: val,
    			type: 'fdbCompress',
    			enabled: false
    		},
    		before,
    		after,
    		compressedVal;

    	// Compress the data
    	before = val.length;
    	compressedVal = pako.deflate(val, {to: 'string'});
    	after = compressedVal.length;

    	// If the compressed version is smaller than the original, use it!
    	Iif (after < before) {
    		wrapper.data = compressedVal;
    		wrapper.enabled = true;
    	}

    	meta.compression = {
    		enabled: wrapper.enabled,
    		compressedBytes: after,
    		uncompressedBytes: before,
    		effect: Math.round((100 / before) * after) + '%'
    	};

    	finished(false, this.jStringify(wrapper), meta);
    };

    Plugin.prototype.decode = function (wrapper, meta, finished) {
    	var compressionEnabled = false,
    		data;

    	Eif (wrapper) {
    		wrapper = this.jParse(wrapper);

    		// Check if we need to decompress the string
    		Iif (wrapper.enabled) {
    			data = pako.inflate(wrapper.data, {to: 'string'});
    			compressionEnabled = true;
    		} else {
    			data = wrapper.data;
    			compressionEnabled = false;
    		}

    		meta.compression = {
    			enabled: compressionEnabled
    		};

    		Eif (finished) {
    			finished(false, data, meta);
    		}
    	} else {
    		if (finished) {
    			finished(false, data, meta);
    		}
    	}
    };

    // Register this plugin with ForerunnerDB
    Shared.plugins.FdbCompress = Plugin;

    module.exports = Plugin;
    },{"./Shared":40,"pako":80}],37:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared'),
    	CryptoJS = _dereq_('crypto-js');

    var Plugin = function () {
    	this.init.apply(this, arguments);
    };

    Plugin.prototype.init = function (options) {
    	// Ensure at least a password is passed in options
    	Iif (!options || !options.pass) {
    		throw('Cannot initialise persistent storage encryption without a passphrase provided in the passed options object as the "pass" field.');
    	}

    	this._algo = options.algo || 'AES';
    	this._pass = options.pass;
    };

    Shared.mixin(Plugin.prototype, 'Mixin.Common');

    /**
     * Gets / sets the current pass-phrase being used to encrypt / decrypt
     * data with the plugin.
     */
    Shared.synthesize(Plugin.prototype, 'pass');

    Plugin.prototype.stringify = function (cipherParams) {
    	// create json object with ciphertext
    	var jsonObj = {
    		ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)
    	};

    	// optionally add iv and salt
    	Eif (cipherParams.iv) {
    		jsonObj.iv = cipherParams.iv.toString();
    	}
    	Eif (cipherParams.salt) {
    		jsonObj.s = cipherParams.salt.toString();
    	}

    	// stringify json object
    	return this.jStringify(jsonObj);
    };

    Plugin.prototype.parse = function (jsonStr) {
    	// parse json string
    	var jsonObj = this.jParse(jsonStr);

    	// extract ciphertext from json object, and create cipher params object
    	var cipherParams = CryptoJS.lib.CipherParams.create({
    		ciphertext: CryptoJS.enc.Base64.parse(jsonObj.ct)
    	});

    	// optionally extract iv and salt
    	Eif (jsonObj.iv) {
    		cipherParams.iv = CryptoJS.enc.Hex.parse(jsonObj.iv);
    	}
    	Eif (jsonObj.s) {
    		cipherParams.salt = CryptoJS.enc.Hex.parse(jsonObj.s);
    	}

    	return cipherParams;
    };

    Plugin.prototype.encode = function (val, meta, finished) {
    	var self = this,
    		wrapper = {
    			type: 'fdbCrypto'
    		},
    		encryptedVal;

    	// Encrypt the data
    	encryptedVal = CryptoJS[this._algo].encrypt(val, this._pass, {
    		format: {
    			stringify: function () { return self.stringify.apply(self, arguments); },
    			parse: function () { return self.parse.apply(self, arguments); }
    		}
    	});

    	wrapper.data = encryptedVal.toString();
    	wrapper.enabled = true;

    	meta.encryption = {
    		enabled: wrapper.enabled
    	};

    	Eif (finished) {
    		finished(false, this.jStringify(wrapper), meta);
    	}
    };

    Plugin.prototype.decode = function (wrapper, meta, finished) {
    	var self = this,
    		data;

    	Eif (wrapper) {
    		wrapper = this.jParse(wrapper);

    		data = CryptoJS[this._algo].decrypt(wrapper.data, this._pass, {
    			format: {
    				stringify: function () { return self.stringify.apply(self, arguments); },
    				parse: function () { return self.parse.apply(self, arguments); }
    			}
    		}).toString(CryptoJS.enc.Utf8);

    		Eif (finished) {
    			finished(false, data, meta);
    		}
    	} else {
    		if (finished) {
    			finished(false, wrapper, meta);
    		}
    	}
    };

    // Register this plugin with ForerunnerDB
    Shared.plugins.FdbCrypto = Plugin;

    module.exports = Plugin;
    },{"./Shared":40,"crypto-js":52}],38:[function(_dereq_,module,exports){
    "use strict";

    var Shared = _dereq_('./Shared');

    /**
     * Provides chain reactor node linking so that a chain reaction can propagate
     * down a node tree. Effectively creates a chain link between the reactorIn and
     * reactorOut objects where a chain reaction from the reactorIn is passed through
     * the reactorProcess before being passed to the reactorOut object. Reactor
     * packets are only passed through to the reactorOut if the reactor IO method
     * chainSend is used.
     * @param {*} reactorIn An object that has the Mixin.ChainReactor methods mixed
     * in to it. Chain reactions that occur inside this object will be passed through
     * to the reactorOut object.
     * @param {*} reactorOut An object that has the Mixin.ChainReactor methods mixed
     * in to it. Chain reactions that occur in the reactorIn object will be passed
     * through to this object.
     * @param {Function} reactorProcess The processing method to use when chain
     * reactions occur.
     * @constructor
     */
    var ReactorIO = function (reactorIn, reactorOut, reactorProcess) {
    	Eif (reactorIn && reactorOut && reactorProcess) {
    		this._reactorIn = reactorIn;
    		this._reactorOut = reactorOut;
    		this._chainHandler = reactorProcess;

    		Iif (!reactorIn.chain) {
    			throw('ForerunnerDB.ReactorIO: ReactorIO requires passed in and out objects to implement the ChainReactor mixin!');
    		}

    		// Register the reactorIO with the input
    		reactorIn.chain(this);

    		// Register the output with the reactorIO
    		this.chain(reactorOut);
    	} else {
    		throw('ForerunnerDB.ReactorIO: ReactorIO requires in, out and process arguments to instantiate!');
    	}
    };

    Shared.addModule('ReactorIO', ReactorIO);

    /**
     * Drop a reactor IO object, breaking the reactor link between the in and out
     * reactor nodes.
     * @returns {boolean}
     */
    ReactorIO.prototype.drop = function () {
    	Eif (!this.isDropped()) {
    		this._state = 'dropped';

    		// Remove links
    		Eif (this._reactorIn) {
    			this._reactorIn.unChain(this);
    		}

    		Eif (this._reactorOut) {
    			this.unChain(this._reactorOut);
    		}

    		delete this._reactorIn;
    		delete this._reactorOut;
    		delete this._chainHandler;

    		this.emit('drop', this);

    		delete this._listeners;
    	}

    	return true;
    };

    /**
     * Gets / sets the current state.
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(ReactorIO.prototype, 'state');

    Shared.mixin(ReactorIO.prototype, 'Mixin.Common');
    Shared.mixin(ReactorIO.prototype, 'Mixin.ChainReactor');
    Shared.mixin(ReactorIO.prototype, 'Mixin.Events');

    Shared.finishModule('ReactorIO');
    module.exports = ReactorIO;
    },{"./Shared":40}],39:[function(_dereq_,module,exports){
    "use strict";

    /**
     * Provides functionality to encode and decode JavaScript objects to strings
     * and back again. This differs from JSON.stringify and JSON.parse in that
     * special objects such as dates can be encoded to strings and back again
     * so that the reconstituted version of the string still contains a JavaScript
     * date object.
     * @constructor
     */
    var Serialiser = function () {
    	this.init.apply(this, arguments);
    };

    Serialiser.prototype.init = function () {
    	var self = this;

    	this._encoder = [];
    	this._decoder = [];

    	// Handler for Date() objects
    	this.registerHandler('$date', function (objInstance) {
    		if (objInstance instanceof Date) {
    			// Augment this date object with a new toJSON method
    			objInstance.toJSON = function () {
    				return "$date:" + this.toISOString();
    			};

    			// Tell the converter we have matched this object
    			return true;
    		}

    		// Tell converter to keep looking, we didn't match this object
    		return false;
    	}, function (data) {
    		if (typeof data === 'string' && data.indexOf('$date:') === 0) {
    			return self.convert(new Date(data.substr(6)));
    		}

    		return undefined;
    	});

    	// Handler for RegExp() objects
    	this.registerHandler('$regexp', function (objInstance) {
    		Eif (objInstance instanceof RegExp) {
    			objInstance.toJSON = function () {
    				return "$regexp:" + this.source.length + ":" + this.source + ":" + (this.global ? 'g' : '') + (this.ignoreCase ? 'i' : '');
    				/*return {
    					source: this.source,
    					params: '' + (this.global ? 'g' : '') + (this.ignoreCase ? 'i' : '')
    				};*/
    			};

    			// Tell the converter we have matched this object
    			return true;
    		}

    		// Tell converter to keep looking, we didn't match this object
    		return false;
    	}, function (data) {
    		if (typeof data === 'string' && data.indexOf('$regexp:') === 0) {
    			var dataStr = data.substr(8),//±
    				lengthEnd = dataStr.indexOf(':'),
    				sourceLength = Number(dataStr.substr(0, lengthEnd)),
    				source = dataStr.substr(lengthEnd + 1, sourceLength),
    				params = dataStr.substr(lengthEnd + sourceLength + 2);

    			return self.convert(new RegExp(source, params));
    		}

    		return undefined;
    	});
    };

    Serialiser.prototype.registerHandler = function (handles, encoder, decoder) {
    	Eif (handles !== undefined) {
    		// Register encoder
    		this._encoder.push(encoder);

    		// Register decoder
    		this._decoder.push(decoder);
    	}
    };

    Serialiser.prototype.convert = function (data) {
    	// Run through converters and check for match
    	var arr = this._encoder,
    		i;

    	for (i = 0; i < arr.length; i++) {
    		if (arr[i](data)) {
    			// The converter we called matched the object and converted it
    			// so let's return it now.
    			return data;
    		}
    	}

    	// No converter matched the object, return the unaltered one
    	return data;
    };

    Serialiser.prototype.reviver = function () {
    	var arr = this._decoder;

    	return function (key, value) {
    		// Check if we have a decoder method for this key
    		var decodedData,
    			i;

    		for (i = 0; i < arr.length; i++) {
    			decodedData = arr[i](value);

    			if (decodedData !== undefined) {
    				// The decoder we called matched the object and decoded it
    				// so let's return it now.
    				return decodedData;
    			}
    		}

    		// No decoder, return basic value
    		return value;
    	};
    };

    module.exports = Serialiser;
    },{}],40:[function(_dereq_,module,exports){
    "use strict";

    var Overload = _dereq_('./Overload');

    /**
     * A shared object that can be used to store arbitrary data between class
     * instances, and access helper methods.
     * @mixin
     */
    var Shared = {
    	version: '1.3.731',
    	modules: {},
    	plugins: {},
    	index: {},

    	_synth: {},

    	/**
    	 * Adds a module to ForerunnerDB.
    	 * @memberof Shared
    	 * @param {String} name The name of the module.
    	 * @param {Function} module The module class.
    	 */
    	addModule: function (name, module) {
    		// Store the module in the module registry
    		this.modules[name] = module;

    		// Tell the universe we are loading this module
    		this.emit('moduleLoad', [name, module]);
    	},

    	/**
    	 * Called by the module once all processing has been completed. Used to determine
    	 * if the module is ready for use by other modules.
    	 * @memberof Shared
    	 * @param {String} name The name of the module.
    	 */
    	finishModule: function (name) {
    		Eif (this.modules[name]) {
    			// Set the finished loading flag to true
    			this.modules[name]._fdbFinished = true;

    			// Assign the module name to itself so it knows what it
    			// is called
    			if (this.modules[name].prototype) {
    				this.modules[name].prototype.className = name;
    			} else {
    				this.modules[name].className = name;
    			}

    			this.emit('moduleFinished', [name, this.modules[name]]);
    		} else {
    			throw('ForerunnerDB.Shared: finishModule called on a module that has not been registered with addModule(): ' + name);
    		}
    	},

    	/**
    	 * Will call your callback method when the specified module has loaded. If the module
    	 * is already loaded the callback is called immediately.
    	 * @memberof Shared
    	 * @param {String} name The name of the module.
    	 * @param {Function} callback The callback method to call when the module is loaded.
    	 */
    	moduleFinished: function (name, callback) {
    		Eif (this.modules[name] && this.modules[name]._fdbFinished) {
    			Eif (callback) { callback(name, this.modules[name]); }
    		} else {
    			this.on('moduleFinished', callback);
    		}
    	},

    	/**
    	 * Determines if a module has been added to ForerunnerDB or not.
    	 * @memberof Shared
    	 * @param {String} name The name of the module.
    	 * @returns {Boolean} True if the module exists or false if not.
    	 */
    	moduleExists: function (name) {
    		return Boolean(this.modules[name]);
    	},

    	mixin: new Overload({
    		/**
    		 * Adds the properties and methods defined in the mixin to the passed
    		 * object.
    		 * @memberof Shared
    		 * @name mixin
    		 * @param {Object} obj The target object to add mixin key/values to.
    		 * @param {String} mixinName The name of the mixin to add to the object.
    		 */
    		'object, string': function (obj, mixinName) {
    			var mixinObj;

    			Eif (typeof mixinName === 'string') {
    				mixinObj = this.mixins[mixinName];

    				Iif (!mixinObj) {
    					throw('ForerunnerDB.Shared: Cannot find mixin named: ' + mixinName);
    				}
    			}

    			return this.$main.call(this, obj, mixinObj);
    		},

    		/**
    		 * Adds the properties and methods defined in the mixin to the passed
    		 * object.
    		 * @memberof Shared
    		 * @name mixin
    		 * @param {Object} obj The target object to add mixin key/values to.
    		 * @param {Object} mixinObj The object containing the keys to mix into
    		 * the target object.
    		 */
    		'object, *': function (obj, mixinObj) {
    			return this.$main.call(this, obj, mixinObj);
    		},

    		'$main': function (obj, mixinObj) {
    			Eif (mixinObj && typeof mixinObj === 'object') {
    				for (var i in mixinObj) {
    					Eif (mixinObj.hasOwnProperty(i)) {
    						obj[i] = mixinObj[i];
    					}
    				}
    			}

    			return obj;
    		}
    	}),

    	/**
    	 * Generates a generic getter/setter method for the passed method name.
    	 * @memberof Shared
    	 * @param {Object} obj The object to add the getter/setter to.
    	 * @param {String} name The name of the getter/setter to generate.
    	 * @param {Function=} extend A method to call before executing the getter/setter.
    	 * The existing getter/setter can be accessed from the extend method via the
    	 * $super e.g. this.$super();
    	 */
    	synthesize: function (obj, name, extend) {
    		this._synth[name] = this._synth[name] || function (val) {
    			if (val !== undefined) {
    				this['_' + name] = val;
    				return this;
    			}

    			return this['_' + name];
    		};

    		if (extend) {
    			var self = this;

    			obj[name] = function () {
    				var tmp = this.$super,
    					ret;

    				this.$super = self._synth[name];
    				ret = extend.apply(this, arguments);
    				this.$super = tmp;

    				return ret;
    			};
    		} else {
    			obj[name] = this._synth[name];
    		}
    	},

    	/**
    	 * Allows a method to be overloaded.
    	 * @memberof Shared
    	 * @param arr
    	 * @returns {Function}
    	 * @constructor
    	 */
    	overload: Overload,

    	/**
    	 * Define the mixins that other modules can use as required.
    	 * @memberof Shared
    	 */
    	mixins: {
    		'Mixin.Common': _dereq_('./Mixin.Common'),
    		'Mixin.Events': _dereq_('./Mixin.Events'),
    		'Mixin.ChainReactor': _dereq_('./Mixin.ChainReactor'),
    		'Mixin.CRUD': _dereq_('./Mixin.CRUD'),
    		'Mixin.Constants': _dereq_('./Mixin.Constants'),
    		'Mixin.Triggers': _dereq_('./Mixin.Triggers'),
    		'Mixin.Sorting': _dereq_('./Mixin.Sorting'),
    		'Mixin.Matching': _dereq_('./Mixin.Matching'),
    		'Mixin.Updating': _dereq_('./Mixin.Updating'),
    		'Mixin.Tags': _dereq_('./Mixin.Tags')
    	}
    };

    // Add event handling to shared
    Shared.mixin(Shared, 'Mixin.Events');

    module.exports = Shared;
    },{"./Mixin.CRUD":20,"./Mixin.ChainReactor":21,"./Mixin.Common":22,"./Mixin.Constants":23,"./Mixin.Events":24,"./Mixin.Matching":25,"./Mixin.Sorting":26,"./Mixin.Tags":27,"./Mixin.Triggers":28,"./Mixin.Updating":29,"./Overload":32}],41:[function(_dereq_,module,exports){
    /* jshint strict:false */
    Iif (!Array.prototype.filter) {
    	Array.prototype.filter = function(fun/*, thisArg*/) {

    		if (this === void 0 || this === null) {
    			throw new TypeError();
    		}

    		var t = Object(this);
    		var len = t.length >>> 0; // jshint ignore:line
    		if (typeof fun !== 'function') {
    			throw new TypeError();
    		}

    		var res = [];
    		var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    		for (var i = 0; i < len; i++) {
    			if (i in t) {
    				var val = t[i];

    				// NOTE: Technically this should Object.defineProperty at
    				//       the next index, as push can be affected by
    				//       properties on Object.prototype and Array.prototype.
    				//       But that method's new, and collisions should be
    				//       rare, so use the more-compatible alternative.
    				if (fun.call(thisArg, val, i, t)) {
    					res.push(val);
    				}
    			}
    		}

    		return res;
    	};
    }

    Iif (typeof Object.create !== 'function') {
    	Object.create = (function() {
    		var Temp = function() {};
    		return function (prototype) {
    			if (arguments.length > 1) {
    				throw Error('Second argument not supported');
    			}
    			if (typeof prototype !== 'object') {
    				throw TypeError('Argument must be an object');
    			}
    			Temp.prototype = prototype;
    			var result = new Temp();
    			Temp.prototype = null;
    			return result;
    		};
    	})();
    }

    // Production steps of ECMA-262, Edition 5, 15.4.4.14
    // Reference: http://es5.github.io/#x15.4.4.14e
    Iif (!Array.prototype.indexOf) {
    	Array.prototype.indexOf = function(searchElement, fromIndex) {
    		var k;

    		// 1. Let O be the result of calling ToObject passing
    		//    the this value as the argument.
    		if (this === null) {
    			throw new TypeError('"this" is null or not defined');
    		}

    		var O = Object(this);

    		// 2. Let lenValue be the result of calling the Get
    		//    internal method of O with the argument "length".
    		// 3. Let len be ToUint32(lenValue).
    		var len = O.length >>> 0; // jshint ignore:line

    		// 4. If len is 0, return -1.
    		if (len === 0) {
    			return -1;
    		}

    		// 5. If argument fromIndex was passed let n be
    		//    ToInteger(fromIndex); else let n be 0.
    		var n = +fromIndex || 0;

    		if (Math.abs(n) === Infinity) {
    			n = 0;
    		}

    		// 6. If n >= len, return -1.
    		if (n >= len) {
    			return -1;
    		}

    		// 7. If n >= 0, then Let k be n.
    		// 8. Else, n<0, Let k be len - abs(n).
    		//    If k is less than 0, then let k be 0.
    		k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

    		// 9. Repeat, while k < len
    		while (k < len) {
    			// a. Let Pk be ToString(k).
    			//   This is implicit for LHS operands of the in operator
    			// b. Let kPresent be the result of calling the
    			//    HasProperty internal method of O with argument Pk.
    			//   This step can be combined with c
    			// c. If kPresent is true, then
    			//    i.  Let elementK be the result of calling the Get
    			//        internal method of O with the argument ToString(k).
    			//   ii.  Let same be the result of applying the
    			//        Strict Equality Comparison Algorithm to
    			//        searchElement and elementK.
    			//  iii.  If same is true, return k.
    			if (k in O && O[k] === searchElement) {
    				return k;
    			}
    			k++;
    		}
    		return -1;
    	};
    }

    module.exports = {};
    },{}],42:[function(_dereq_,module,exports){
    "use strict";

    // Import external names locally
    var Shared,
    	Db,
    	Collection,
    	CollectionGroup,
    	CollectionInit,
    	DbInit,
    	ReactorIO,
    	ActiveBucket,
    	Overload = _dereq_('./Overload'),
    	Path,
    	sharedPathSolver;

    Shared = _dereq_('./Shared');

    /**
     * Creates a new view instance.
     * @param {String} name The name of the view.
     * @param {Object=} query The view's query.
     * @param {Object=} options An options object.
     * @constructor
     */
    var View = function (name, query, options) {
    	this.init.apply(this, arguments);
    };

    Shared.addModule('View', View);
    Shared.mixin(View.prototype, 'Mixin.Common');
    Shared.mixin(View.prototype, 'Mixin.Matching');
    Shared.mixin(View.prototype, 'Mixin.ChainReactor');
    Shared.mixin(View.prototype, 'Mixin.Constants');
    Shared.mixin(View.prototype, 'Mixin.Triggers');
    Shared.mixin(View.prototype, 'Mixin.Tags');

    Collection = _dereq_('./Collection');
    CollectionGroup = _dereq_('./CollectionGroup');
    ActiveBucket = _dereq_('./ActiveBucket');
    ReactorIO = _dereq_('./ReactorIO');
    CollectionInit = Collection.prototype.init;
    Db = Shared.modules.Db;
    DbInit = Db.prototype.init;
    Path = Shared.modules.Path;
    sharedPathSolver = new Path();

    View.prototype.init = function (name, query, options) {
    	var self = this;

    	this.sharedPathSolver = sharedPathSolver;
    	this._name = name;
    	this._listeners = {};
    	this._querySettings = {};
    	this._debug = {};

    	this.query(query, options, false);

    	this._collectionDroppedWrap = function () {
    		self._collectionDropped.apply(self, arguments);
    	};

    	this._data = new Collection(this.name() + '_internal');
    };

    /**
     * This reactor IO node is given data changes from source data and
     * then acts as a firewall process between the source and view data.
     * Data needs to meet the requirements this IO node imposes before
     * the data is passed down the reactor chain (to the view). This
     * allows us to intercept data changes from the data source and act
     * on them such as applying transforms, checking the data matches
     * the view's query, applying joins to the data etc before sending it
     * down the reactor chain via the this.chainSend() calls.
     *
     * Update packets are especially complex to handle because an update
     * on the underlying source data could translate into an insert,
     * update or remove call on the view. Take a scenario where the view's
     * query limits the data see from the source. If the source data is
     * updated and the data now falls inside the view's query limitations
     * the data is technically now an insert on the view, not an update.
     * The same is true in reverse where the update becomes a remove. If
     * the updated data already exists in the view and will still exist
     * after the update operation then the update can remain an update.
     * @param {Object} chainPacket The chain reactor packet representing the
     * data operation that has just been processed on the source data.
     * @param {View} self The reference to the view we are operating for.
     * @private
     */
    View.prototype._handleChainIO = function (chainPacket, self) {
    	var type = chainPacket.type,
    		hasActiveJoin,
    		hasActiveQuery,
    		hasTransformIn,
    		sharedData;

    	// NOTE: "self" in this context is the view instance.

    	// NOTE: "this" in this context is the ReactorIO node sitting in
    	// between the source (sender) and the destination (listener) and
    	// in this case the source is the view's "from" data source and the
    	// destination is the view's _data collection. This means
    	// that "this.chainSend()" is asking the ReactorIO node to send the
    	// packet on to the destination listener.

    	// EARLY EXIT: Check that the packet is not a CRUD operation
    	Iif (type !== 'setData' && type !== 'insert' && type !== 'update' && type !== 'remove') {
    		// This packet is NOT a CRUD operation packet so exit early!

    		// Returning false informs the chain reactor to continue propagation
    		// of the chain packet down the graph tree
    		return false;
    	}

    	// We only need to check packets under three conditions

    	// 1) We have a limiting query on the view "active query",
    	// 2) We have a query options with a $join clause on the view "active join"
    	// 3) We have a transformIn operation registered on the view.

    	// If none of these conditions exist we can just allow the chain
    	// packet to proceed as normal
    	hasActiveJoin = Boolean(self._querySettings.options && self._querySettings.options.$join);
    	hasActiveQuery = Boolean(self._querySettings.query);
    	hasTransformIn = self._data._transformIn !== undefined;

    	// EARLY EXIT: Check for any complex operation flags and if none
    	// exist, send the packet on and exit early
    	if (!hasActiveJoin && !hasActiveQuery && !hasTransformIn) {
    		// We don't have any complex operation flags so exit early!

    		// Returning false informs the chain reactor to continue propagation
    		// of the chain packet down the graph tree
    		return false;
    	}

    	// We have either an active query, active join or a transformIn
    	// function registered on the view

    	// We create a shared data object here so that the disparate method
    	// calls can share data with each other via this object whilst
    	// still remaining separate methods to keep code relatively clean.
    	sharedData = {
    		dataArr: [],
    		removeArr: []
    	};

    	// Check the packet type to get the data arrays to work on
    	if (chainPacket.type === 'insert') {
    		// Check if the insert data is an array
    		Eif (chainPacket.data.dataSet instanceof Array) {
    			// Use the insert data array
    			sharedData.dataArr = chainPacket.data.dataSet;
    		} else {
    			// Generate an array from the single insert object
    			sharedData.dataArr = [chainPacket.data.dataSet];
    		}
    	} else if (chainPacket.type === 'update') {
    		// Use the dataSet array
    		sharedData.dataArr = chainPacket.data.dataSet;
    	} else Eif (chainPacket.type === 'remove') {
    		Eif (chainPacket.data.dataSet instanceof Array) {
    			// Use the remove data array
    			sharedData.removeArr = chainPacket.data.dataSet;
    		} else {
    			// Generate an array from the single remove object
    			sharedData.removeArr = [chainPacket.data.dataSet];
    		}
    	}

    	// Safety check
    	Iif (!(sharedData.dataArr instanceof Array)) {
    		// This shouldn't happen, let's log it
    		console.warn('WARNING: dataArr being processed by chain reactor in View class is inconsistent!');
    		sharedData.dataArr = [];
    	}

    	Iif (!(sharedData.removeArr instanceof Array)) {
    		// This shouldn't happen, let's log it
    		console.warn('WARNING: removeArr being processed by chain reactor in View class is inconsistent!');
    		sharedData.removeArr = [];
    	}

    	// We need to operate in this order:

    	// 1) Check if there is an active join - active joins are operated
    	// against the SOURCE data. The joined data can potentially be
    	// utilised by any active query or transformIn so we do this step first.

    	// 2) Check if there is an active query - this is a query that is run
    	// against the SOURCE data after any active joins have been resolved
    	// on the source data. This allows an active query to operate on data
    	// that would only exist after an active join has been executed.
    	// If the source data does not fall inside the limiting factors of the
    	// active query then we add it to a removal array. If it does fall
    	// inside the limiting factors when we add it to an upsert array. This
    	// is because data that falls inside the query could end up being
    	// either new data or updated data after a transformIn operation.

    	// 3) Check if there is a transformIn function. If a transformIn function
    	// exist we run it against the data after doing any active join and
    	// active query.
    	if (hasActiveJoin) {
    		Iif (this.debug()) {
    			console.time(this.logIdentifier() + ' :: _handleChainIO_ActiveJoin');
    		}
    		self._handleChainIO_ActiveJoin(chainPacket, sharedData);
    		Iif (this.debug()) {
    			console.timeEnd(this.logIdentifier() + ' :: _handleChainIO_ActiveJoin');
    		}
    	}

    	if (hasActiveQuery) {
    		Iif (this.debug()) {
    			console.time(this.logIdentifier() + ' :: _handleChainIO_ActiveQuery');
    		}
    		self._handleChainIO_ActiveQuery(chainPacket, sharedData);
    		Iif (this.debug()) {
    			console.timeEnd(this.logIdentifier() + ' :: _handleChainIO_ActiveQuery');
    		}
    	}

    	if (hasTransformIn) {
    		Iif (this.debug()) {
    			console.time(this.logIdentifier() + ' :: _handleChainIO_TransformIn');
    		}
    		self._handleChainIO_TransformIn(chainPacket, sharedData);
    		Iif (this.debug()) {
    			console.timeEnd(this.logIdentifier() + ' :: _handleChainIO_TransformIn');
    		}
    	}

    	// Check if we still have data to operate on and exit
    	// if there is none left
    	Iif (!sharedData.dataArr.length && !sharedData.removeArr.length) {
    		// There is no more data to operate on, exit without
    		// sending any data down the chain reactor (return true
    		// will tell reactor to exit without continuing)!
    		return true;
    	}

    	// Grab the public data collection's primary key
    	sharedData.pk = self._data.primaryKey();

    	// We still have data left, let's work out how to handle it
    	// first let's loop through the removals as these are easy
    	if (sharedData.removeArr.length) {
    		Iif (this.debug()) {
    			console.time(this.logIdentifier() + ' :: _handleChainIO_RemovePackets');
    		}
    		self._handleChainIO_RemovePackets(this, chainPacket, sharedData);
    		Iif (this.debug()) {
    			console.timeEnd(this.logIdentifier() + ' :: _handleChainIO_RemovePackets');
    		}
    	}

    	if (sharedData.dataArr.length) {
    		Iif (this.debug()) {
    			console.time(this.logIdentifier() + ' :: _handleChainIO_UpsertPackets');
    		}
    		self._handleChainIO_UpsertPackets(this, chainPacket, sharedData);
    		Iif (this.debug()) {
    			console.timeEnd(this.logIdentifier() + ' :: _handleChainIO_UpsertPackets');
    		}
    	}

    	// Now return true to tell the chain reactor not to propagate
    	// the data itself as we have done all that work here
    	return true;
    };

    View.prototype._handleChainIO_ActiveJoin = function (chainPacket, sharedData) {
    	var dataArr = sharedData.dataArr,
    		removeArr;

    	// Since we have an active join, all we need to do is operate
    	// the join clause on each item in the packet's data array.
    	removeArr = this.applyJoin(dataArr, this._querySettings.options.$join, {}, {});

    	// Now that we've run our join keep in mind that joins can exclude data
    	// if there is no matching joined data and the require: true clause in
    	// the join options is enabled. This means we have to store a removal
    	// array that tells us which items from the original data we sent to
    	// join did not match the join data and were set with a require flag.

    	// Now that we have our array of items to remove, let's run through the
    	// original data and remove them from there.
    	this.spliceArrayByIndexList(dataArr, removeArr);

    	// Make sure we add any items we removed to the shared removeArr
    	sharedData.removeArr = sharedData.removeArr.concat(removeArr);
    };

    View.prototype._handleChainIO_ActiveQuery = function (chainPacket, sharedData) {
    	var self = this,
    		dataArr = sharedData.dataArr,
    		i;

    	// Now we need to run the data against the active query to
    	// see if the data should be in the final data list or not,
    	// so we use the _match method.

    	// Loop backwards so we can safely splice from the array
    	// while we are looping
    	for (i = dataArr.length - 1; i >= 0; i--) {
    		if (!self._match(dataArr[i], self._querySettings.query, self._querySettings.options, 'and', {})) {
    			// The data didn't match the active query, add it
    			// to the shared removeArr
    			sharedData.removeArr.push(dataArr[i]);

    			// Now remove it from the shared dataArr
    			dataArr.splice(i, 1);
    		}
    	}
    };

    View.prototype._handleChainIO_TransformIn = function (chainPacket, sharedData) {
    	var self = this,
    		dataArr = sharedData.dataArr,
    		removeArr = sharedData.removeArr,
    		dataIn = self._data._transformIn,
    		i;

    	// At this stage we take the remaining items still left in the data
    	// array and run our transformIn method on each one, modifying it
    	// from what it was to what it should be on the view. We also have
    	// to run this on items we want to remove too because transforms can
    	// affect primary keys and therefore stop us from identifying the
    	// correct items to run removal operations on.

    	// It is important that these are transformed BEFORE they are passed
    	// to the CRUD methods because we use the CU data to check the position
    	// of the item in the array and that can only happen if it is already
    	// pre-transformed. The removal stuff also needs pre-transformed
    	// because ids can be modified by a transform.
    	for (i = 0; i < dataArr.length; i++) {
    		// Assign the new value
    		dataArr[i] = dataIn(dataArr[i]);
    	}

    	for (i = 0; i < removeArr.length; i++) {
    		// Assign the new value
    		removeArr[i] = dataIn(removeArr[i]);
    	}
    };

    View.prototype._handleChainIO_RemovePackets = function (ioObj, chainPacket, sharedData) {
    	var $or = [],
    		pk = sharedData.pk,
    		removeArr = sharedData.removeArr,
    		packet = {
    			dataSet: removeArr,
    			query: {
    				$or: $or
    			}
    		},
    		orObj,
    		i;

    	for (i = 0; i < removeArr.length; i++) {
    		orObj = {};
    		orObj[pk] = removeArr[i][pk];

    		$or.push(orObj);
    	}

    	ioObj.chainSend('remove', packet);
    };

    View.prototype._handleChainIO_UpsertPackets = function (ioObj, chainPacket, sharedData) {
    	var data = this._data,
    		primaryIndex = data._primaryIndex,
    		primaryCrc = data._primaryCrc,
    		pk = sharedData.pk,
    		dataArr = sharedData.dataArr,
    		arrItem,
    		insertArr = [],
    		updateArr = [],
    		query,
    		i;

    	// Let's work out what type of operation this data should
    	// generate between an insert or an update.
    	for (i = 0; i < dataArr.length; i++) {
    		arrItem = dataArr[i];

    		// Check if the data already exists in the data
    		if (primaryIndex.get(arrItem[pk])) {
    			// Matching item exists, check if the data is the same
    			Eif (primaryCrc.get(arrItem[pk]) !== this.hash(arrItem[pk])) {
    				// The document exists in the data collection but data differs, update required
    				updateArr.push(arrItem);
    			}
    		} else {
    			// The document is missing from this collection, insert required
    			insertArr.push(arrItem);
    		}
    	}

    	if (insertArr.length) {
    		ioObj.chainSend('insert', {
    			dataSet: insertArr
    		});
    	}

    	if (updateArr.length) {
    		for (i = 0; i < updateArr.length; i++) {
    			arrItem = updateArr[i];

    			query = {};
    			query[pk] = arrItem[pk];

    			ioObj.chainSend('update', {
    				query: query,
    				update: arrItem,
    				dataSet: [arrItem]
    			});
    		}
    	}
    };

    /**
     * Executes an insert against the view's underlying data-source.
     * @see Collection::insert()
     */
    View.prototype.insert = function () {
    	this._from.insert.apply(this._from, arguments);
    };

    /**
     * Executes an update against the view's underlying data-source.
     * @see Collection::update()
     */
    View.prototype.update = function () {
    	this._from.update.apply(this._from, arguments);
    };

    /**
     * Executes an updateById against the view's underlying data-source.
     * @see Collection::updateById()
     */
    View.prototype.updateById = function () {
    	this._from.updateById.apply(this._from, arguments);
    };

    /**
     * Executes a remove against the view's underlying data-source.
     * @see Collection::remove()
     */
    View.prototype.remove = function () {
    	this._from.remove.apply(this._from, arguments);
    };

    /**
     * Queries the view data.
     * @see Collection::find()
     * @returns {Array} The result of the find query.
     */
    View.prototype.find = function (query, options) {
    	return this._data.find(query, options);
    };

    /**
     * Queries the view data for a single document.
     * @see Collection::findOne()
     * @returns {Object} The result of the find query.
     */
    View.prototype.findOne = function (query, options) {
    	return this._data.findOne(query, options);
    };

    /**
     * Queries the view data by specific id.
     * @see Collection::findById()
     * @returns {Array} The result of the find query.
     */
    View.prototype.findById = function (id, options) {
    	return this._data.findById(id, options);
    };

    /**
     * Queries the view data in a sub-array.
     * @see Collection::findSub()
     * @returns {Array} The result of the find query.
     */
    View.prototype.findSub = function (match, path, subDocQuery, subDocOptions) {
    	return this._data.findSub(match, path, subDocQuery, subDocOptions);
    };

    /**
     * Queries the view data in a sub-array and returns first match.
     * @see Collection::findSubOne()
     * @returns {Object} The result of the find query.
     */
    View.prototype.findSubOne = function (match, path, subDocQuery, subDocOptions) {
    	return this._data.findSubOne(match, path, subDocQuery, subDocOptions);
    };

    /**
     * Gets the module's internal data collection.
     * @returns {Collection}
     */
    View.prototype.data = function () {
    	return this._data;
    };

    /**
     * Sets the source from which the view will assemble its data.
     * @param {Collection|View} source The source to use to assemble view data.
     * @param {Function=} callback A callback method.
     * @returns {*} If no argument is passed, returns the current value of from,
     * otherwise returns itself for chaining.
     */
    View.prototype.from = function (source, callback) {
    	var self = this;

    	if (source !== undefined) {
    		// Check if we have an existing from
    		if (this._from) {
    			// Remove the listener to the drop event
    			this._from.off('drop', this._collectionDroppedWrap);

    			// Remove the current reference to the _from since we
    			// are about to replace it with a new one
    			delete this._from;
    		}

    		// Check if we have an existing reactor io that links the
    		// previous _from source to the view's internal data
    		if (this._io) {
    			// Drop the io and remove it
    			this._io.drop();
    			delete this._io;
    		}

    		// Check if we were passed a source name rather than a
    		// reference to a source object
    		if (typeof(source) === 'string') {
    			// We were passed a name, assume it is a collection and
    			// get the reference to the collection of that name
    			source = this._db.collection(source);
    		}

    		// Check if we were passed a reference to a view rather than
    		// a collection. Views need to be handled slightly differently
    		// since their data is stored in an internal data collection
    		// rather than actually being a direct data source themselves.
    		Iif (source.className === 'View') {
    			// The source is a view so IO to the internal data collection
    			// instead of the view proper
    			source = source._data;

    			if (this.debug()) {
    				console.log(this.logIdentifier() + ' Using internal data "' + source.instanceIdentifier() + '" for IO graph linking');
    			}
    		}

    		// Assign the new data source as the view's _from
    		this._from = source;

    		// Hook the new data source's drop event so we can unhook
    		// it as a data source if it gets dropped. This is important
    		// so that we don't run into problems using a dropped source
    		// for active data.
    		this._from.on('drop', this._collectionDroppedWrap);

    		// Create a new reactor IO graph node that intercepts chain packets from the
    		// view's _from source and determines how they should be interpreted by
    		// this view. See the _handleChainIO() method which does all the chain packet
    		// processing for the view.
    		this._io = new ReactorIO(this._from, this, function (chainPacket) { return self._handleChainIO.call(this, chainPacket, self); });

    		// Set the view's internal data primary key to the same as the
    		// current active _from data source
    		this._data.primaryKey(source.primaryKey());

    		// Do the initial data lookup and populate the view's internal data
    		// since at this point we don't actually have any data in the view
    		// yet.
    		var collData = source.find(this._querySettings.query, this._querySettings.options);
    		this._data.setData(collData, {}, callback);

    		// If we have an active query and that query has an $orderBy clause,
    		// update our active bucket which allows us to keep track of where
    		// data should be placed in our internal data array. This is about
    		// ordering of data and making sure that we maintain an ordered array
    		// so that if we have data-binding we can place an item in the data-
    		// bound view at the correct location. Active buckets use quick-sort
    		// algorithms to quickly determine the position of an item inside an
    		// existing array based on a sort protocol.
    		if (this._querySettings.options && this._querySettings.options.$orderBy) {
    			this.rebuildActiveBucket(this._querySettings.options.$orderBy);
    		} else {
    			this.rebuildActiveBucket();
    		}

    		return this;
    	}

    	return this._from;
    };

    /**
     * The chain reaction handler method for the view.
     * @param {Object} chainPacket The chain reaction packet to handle.
     * @private
     */
    View.prototype._chainHandler = function (chainPacket) {
    	var //self = this,
    		arr,
    		count,
    		index,
    		insertIndex,
    		updates,
    		primaryKey,
    		item,
    		currentIndex;

    	Eif (this.debug()) {
    		console.log(this.logIdentifier() + ' Received chain reactor data: ' + chainPacket.type);
    	}

    	switch (chainPacket.type) {
    		case 'setData':
    			if (this.debug()) {
    				console.log(this.logIdentifier() + ' Setting data in underlying (internal) view collection "' + this._data.name() + '"');
    			}

    			// Get the new data from our underlying data source sorted as we want
    			var collData = this._from.find(this._querySettings.query, this._querySettings.options);
    			this._data.setData(collData);

    			// Rebuild active bucket as well
    			this.rebuildActiveBucket(this._querySettings.options);
    			break;

    		case 'insert':
    			Eif (this.debug()) {
    				console.log(this.logIdentifier() + ' Inserting some data into underlying (internal) view collection "' + this._data.name() + '"');
    			}

    			// Decouple the data to ensure we are working with our own copy
    			chainPacket.data.dataSet = this.decouple(chainPacket.data.dataSet);

    			// Make sure we are working with an array
    			Iif (!(chainPacket.data.dataSet instanceof Array)) {
    				chainPacket.data.dataSet = [chainPacket.data.dataSet];
    			}

    			if (this._querySettings.options && this._querySettings.options.$orderBy) {
    				// Loop the insert data and find each item's index
    				arr = chainPacket.data.dataSet;
    				count = arr.length;

    				for (index = 0; index < count; index++) {
    					insertIndex = this._activeBucket.insert(arr[index]);
    					this._data._insertHandle(arr[index], insertIndex);
    				}
    			} else {
    				// Set the insert index to the passed index, or if none, the end of the view data array
    				insertIndex = this._data._data.length;
    				this._data._insertHandle(chainPacket.data.dataSet, insertIndex);
    			}
    			break;

    		case 'update':
    			Eif (this.debug()) {
    				console.log(this.logIdentifier() + ' Updating some data in underlying (internal) view collection "' + this._data.name() + '"');
    			}

    			primaryKey = this._data.primaryKey();

    			// Do the update
    			updates = this._data._handleUpdate(
    				chainPacket.data.query,
    				chainPacket.data.update,
    				chainPacket.data.options
    			);

    			if (this._querySettings.options && this._querySettings.options.$orderBy) {
    				// TODO: This would be a good place to improve performance by somehow
    				// TODO: inspecting the change that occurred when update was performed
    				// TODO: above and determining if it affected the order clause keys
    				// TODO: and if not, skipping the active bucket updates here

    				// Loop the updated items and work out their new sort locations
    				count = updates.length;
    				for (index = 0; index < count; index++) {
    					item = updates[index];

    					// Remove the item from the active bucket (via it's id)
    					this._activeBucket.remove(item);

    					// Get the current location of the item
    					currentIndex = this._data._data.indexOf(item);

    					// Add the item back in to the active bucket
    					insertIndex = this._activeBucket.insert(item);

    					Eif (currentIndex !== insertIndex) {
    						// Move the updated item to the new index
    						this._data._updateSpliceMove(this._data._data, currentIndex, insertIndex);
    					}
    				}
    			}
    			break;

    		case 'remove':
    			Eif (this.debug()) {
    				console.log(this.logIdentifier() + ' Removing some data from underlying (internal) view collection "' + this._data.name() + '"');
    			}

    			this._data.remove(chainPacket.data.query, chainPacket.options);

    			if (this._querySettings.options && this._querySettings.options.$orderBy) {
    				// Loop the dataSet and remove the objects from the ActiveBucket
    				arr = chainPacket.data.dataSet;
    				count = arr.length;

    				for (index = 0; index < count; index++) {
    					this._activeBucket.remove(arr[index]);
    				}
    			}
    			break;

    		default:
    			break;
    	}
    };

    /**
     * Handles when an underlying collection the view is using as a data
     * source is dropped.
     * @param {Collection} collection The collection that has been dropped.
     * @private
     */
    View.prototype._collectionDropped = function (collection) {
    	Eif (collection) {
    		// Collection was dropped, remove from view
    		delete this._from;
    	}
    };

    /**
     * Creates an index on the view.
     * @see Collection::ensureIndex()
     * @returns {*}
     */
    View.prototype.ensureIndex = function () {
    	return this._data.ensureIndex.apply(this._data, arguments);
    };

    /**

     /**
     * Listens for an event.
     * @see Mixin.Events::on()
     */
    View.prototype.on = function () {
    	return this._data.on.apply(this._data, arguments);
    };

    /**
     * Cancels an event listener.
     * @see Mixin.Events::off()
     */
    View.prototype.off = function () {
    	return this._data.off.apply(this._data, arguments);
    };

    /**
     * Emits an event.
     * @see Mixin.Events::emit()
     */
    View.prototype.emit = function () {
    	return this._data.emit.apply(this._data, arguments);
    };

    /**
     * Emits an event.
     * @see Mixin.Events::deferEmit()
     */
    View.prototype.deferEmit = function () {
    	return this._data.deferEmit.apply(this._data, arguments);
    };

    /**
     * Find the distinct values for a specified field across a single collection and
     * returns the results in an array.
     * @param {String} key The field path to return distinct values for e.g. "person.name".
     * @param {Object=} query The query to use to filter the documents used to return values from.
     * @param {Object=} options The query options to use when running the query.
     * @returns {Array}
     */
    View.prototype.distinct = function (key, query, options) {
    	return this._data.distinct(key, query, options);
    };

    /**
     * Gets the primary key for this view from the assigned collection.
     * @see Collection::primaryKey()
     * @returns {String}
     */
    View.prototype.primaryKey = function () {
    	return this._data.primaryKey();
    };

    /**
     * Drops a view and all it's stored data from the database.
     * @returns {boolean} True on success, false on failure.
     */
    View.prototype.drop = function (callback) {
    	Eif (!this.isDropped()) {
    		if (this._from) {
    			this._from.off('drop', this._collectionDroppedWrap);
    			this._from._removeView(this);
    		}

    		Eif (this.debug() || (this._db && this._db.debug())) {
    			console.log(this.logIdentifier() + ' Dropping');
    		}

    		this._state = 'dropped';

    		// Clear io and chains
    		if (this._io) {
    			this._io.drop();
    		}

    		// Drop the view's internal collection
    		Eif (this._data) {
    			this._data.drop();
    		}

    		Eif (this._db && this._name) {
    			delete this._db._view[this._name];
    		}

    		this.emit('drop', this);

    		if (callback) { callback(false, true); }

    		delete this._chain;
    		delete this._from;
    		delete this._data;
    		delete this._io;
    		delete this._listeners;
    		delete this._querySettings;
    		delete this._db;

    		return true;
    	}

    	return false;
    };

    /**
     * Gets / sets the query object and query options that the view uses
     * to build it's data set. This call modifies both the query and
     * query options at the same time.
     * @param {Object=} query The query to set.
     * @param {Boolean=} options The query options object.
     * @param {Boolean=} refresh Whether to refresh the view data after
     * this operation. Defaults to true.
     * @returns {*}
     * @deprecated Use query(<query>, <options>, <refresh>) instead. Query
     * now supports being presented with multiple different variations of
     * arguments.
     */
    View.prototype.queryData = function (query, options, refresh) {
    	Eif (query !== undefined) {
    		this._querySettings.query = query;

    		Iif (query.$findSub && !query.$findSub.$from) {
    			query.$findSub.$from = this._data.name();
    		}

    		Iif (query.$findSubOne && !query.$findSubOne.$from) {
    			query.$findSubOne.$from = this._data.name();
    		}
    	}

    	Eif (options !== undefined) {
    		this._querySettings.options = options;
    	}

    	Eif (query !== undefined || options !== undefined) {
    		Eif (refresh === undefined || refresh === true) {
    			this.refresh();
    		}
    	}

    	Eif (query !== undefined) {
    		this.emit('queryChange', query);
    	}

    	Eif (options !== undefined) {
    		this.emit('queryOptionsChange', options);
    	}

    	Eif (query !== undefined || options !== undefined) {
    		return this;
    	}

    	return this._querySettings;
    };

    /**
     * Add data to the existing query.
     * @param {Object} obj The data whose keys will be added to the existing
     * query object.
     * @param {Boolean} overwrite Whether or not to overwrite data that already
     * exists in the query object. Defaults to true.
     * @param {Boolean=} refresh Whether or not to refresh the view data set
     * once the operation is complete. Defaults to true.
     */
    View.prototype.queryAdd = function (obj, overwrite, refresh) {
    	this._querySettings.query = this._querySettings.query || {};

    	var query = this._querySettings.query,
    		i;

    	if (obj !== undefined) {
    		// Loop object properties and add to existing query
    		for (i in obj) {
    			if (obj.hasOwnProperty(i)) {
    				if (query[i] === undefined || (query[i] !== undefined && overwrite !== false)) {
    					query[i] = obj[i];
    				}
    			}
    		}
    	}

    	if (refresh === undefined || refresh === true) {
    		this.refresh();
    	}

    	if (query !== undefined) {
    		this.emit('queryChange', query);
    	}
    };

    /**
     * Remove data from the existing query.
     * @param {Object} obj The data whose keys will be removed from the existing
     * query object.
     * @param {Boolean=} refresh Whether or not to refresh the view data set
     * once the operation is complete. Defaults to true.
     */
    View.prototype.queryRemove = function (obj, refresh) {
    	var query = this._querySettings.query,
    		i;

    	if (query) {
    		if (obj !== undefined) {
    			// Loop object properties and add to existing query
    			for (i in obj) {
    				if (obj.hasOwnProperty(i)) {
    					delete query[i];
    				}
    			}
    		}

    		if (refresh === undefined || refresh === true) {
    			this.refresh();
    		}

    		if (query !== undefined) {
    			this.emit('queryChange', query);
    		}
    	}
    };

    /**
     * Gets / sets the query being used to generate the view data. It
     * does not change or modify the view's query options.
     * @param {Object=} query The query to set.
     * @param {Boolean=} refresh Whether to refresh the view data after
     * this operation. Defaults to true.
     * @returns {*}
     */
    View.prototype.query = new Overload({
    	'': function () {
    		return this._querySettings.query;
    	},

    	'object': function (query) {
    		return this.$main.call(this, query, undefined, true);
    	},

    	'*, boolean': function (query, refresh) {
    		return this.$main.call(this, query, undefined, refresh);
    	},

    	'object, object': function (query, options) {
    		return this.$main.call(this, query, options, true);
    	},

    	'*, *, boolean': function (query, options, refresh) {
    		return this.$main.call(this, query, options, refresh);
    	},

    	'$main': function (query, options, refresh) {
    		if (query !== undefined) {
    			this._querySettings.query = query;

    			Iif (query.$findSub && !query.$findSub.$from) {
    				query.$findSub.$from = this._data.name();
    			}

    			Iif (query.$findSubOne && !query.$findSubOne.$from) {
    				query.$findSubOne.$from = this._data.name();
    			}
    		}

    		if (options !== undefined) {
    			this._querySettings.options = options;
    		}

    		if (query !== undefined || options !== undefined) {
    			Eif (refresh === undefined || refresh === true) {
    				this.refresh();
    			}
    		}

    		if (query !== undefined) {
    			this.emit('queryChange', query);
    		}

    		if (options !== undefined) {
    			this.emit('queryOptionsChange', options);
    		}

    		if (query !== undefined || options !== undefined) {
    			return this;
    		}

    		return this._querySettings;
    	}
    });

    /**
     * Gets / sets the orderBy clause in the query options for the view.
     * @param {Object=} val The order object.
     * @returns {*}
     */
    View.prototype.orderBy = function (val) {
    	Eif (val !== undefined) {
    		var queryOptions = this.queryOptions() || {};
    		queryOptions.$orderBy = val;

    		this.queryOptions(queryOptions);
    		return this;
    	}

    	return (this.queryOptions() || {}).$orderBy;
    };

    /**
     * Gets / sets the page clause in the query options for the view.
     * @param {Number=} val The page number to change to (zero index).
     * @returns {*}
     */
    View.prototype.page = function (val) {
    	if (val !== undefined) {
    		var queryOptions = this.queryOptions() || {};

    		// Only execute a query options update if page has changed
    		if (val !== queryOptions.$page) {
    			queryOptions.$page = val;
    			this.queryOptions(queryOptions);
    		}

    		return this;
    	}

    	return (this.queryOptions() || {}).$page;
    };

    /**
     * Jump to the first page in the data set.
     * @returns {*}
     */
    View.prototype.pageFirst = function () {
    	return this.page(0);
    };

    /**
     * Jump to the last page in the data set.
     * @returns {*}
     */
    View.prototype.pageLast = function () {
    	var pages = this.cursor().pages,
    		lastPage = pages !== undefined ? pages : 0;

    	return this.page(lastPage - 1);
    };

    /**
     * Move forward or backwards in the data set pages by passing a positive
     * or negative integer of the number of pages to move.
     * @param {Number} val The number of pages to move.
     * @returns {*}
     */
    View.prototype.pageScan = function (val) {
    	if (val !== undefined) {
    		var pages = this.cursor().pages,
    			queryOptions = this.queryOptions() || {},
    			currentPage = queryOptions.$page !== undefined ? queryOptions.$page : 0;

    		currentPage += val;

    		if (currentPage < 0) {
    			currentPage = 0;
    		}

    		if (currentPage >= pages) {
    			currentPage = pages - 1;
    		}

    		return this.page(currentPage);
    	}
    };

    /**
     * Gets / sets the query options used when applying sorting etc to the
     * view data set.
     * @param {Object=} options An options object.
     * @param {Boolean=} refresh Whether to refresh the view data after
     * this operation. Defaults to true.
     * @returns {*}
     */
    View.prototype.queryOptions = function (options, refresh) {
    	if (options !== undefined) {
    		this._querySettings.options = options;
    		Eif (options.$decouple === undefined) { options.$decouple = true; }

    		Eif (refresh === undefined || refresh === true) {
    			this.refresh();
    		} else {
    			// TODO: This could be wasteful if the previous options $orderBy was identical, do a hash and check first!
    			this.rebuildActiveBucket(options.$orderBy);
    		}

    		Eif (options !== undefined) {
    			this.emit('queryOptionsChange', options);
    		}

    		return this;
    	}

    	return this._querySettings.options;
    };

    /**
     * Clears the existing active bucket and builds a new one based
     * on the passed orderBy object (if one is passed).
     * @param {Object=} orderBy The orderBy object describing how to
     * order any data.
     */
    View.prototype.rebuildActiveBucket = function (orderBy) {
    	if (orderBy) {
    		var arr = this._data._data,
    			arrCount = arr.length;

    		// Build a new active bucket
    		this._activeBucket = new ActiveBucket(orderBy);
    		this._activeBucket.primaryKey(this._data.primaryKey());

    		// Loop the current view data and add each item
    		for (var i = 0; i < arrCount; i++) {
    			this._activeBucket.insert(arr[i]);
    		}
    	} else {
    		// Remove any existing active bucket
    		delete this._activeBucket;
    	}
    };

    /**
     * Refreshes the view data such as ordering etc.
     */
    View.prototype.refresh = function () {
    	var self = this,
    		refreshResults,
    		joinArr,
    		i, k;

    	if (this._from) {
    		// Clear the private data collection which will propagate to the public data
    		// collection automatically via the chain reactor node between them
    		this._data.remove();

    		// Grab all the data from the underlying data source
    		refreshResults = this._from.find(this._querySettings.query, this._querySettings.options);
    		this.cursor(refreshResults.$cursor);

    		// Insert the underlying data into the private data collection
    		this._data.insert(refreshResults);

    		// Store the current cursor data
    		this._data._data.$cursor = refreshResults.$cursor;
    		this._data._data.$cursor = refreshResults.$cursor;
    	}

    	if (this._querySettings && this._querySettings.options && this._querySettings.options.$join && this._querySettings.options.$join.length) {
    		// Define the change handler method
    		self.__joinChange = self.__joinChange || function () {
    			self._joinChange();
    		};

    		// Check for existing join collections
    		if (this._joinCollections && this._joinCollections.length) {
    			// Loop the join collections and remove change listeners
    			// Loop the collections and hook change events
    			for (i = 0; i < this._joinCollections.length; i++) {
    				this._db.collection(this._joinCollections[i]).off('immediateChange', self.__joinChange);
    			}
    		}

    		// Now start hooking any new / existing joins
    		joinArr = this._querySettings.options.$join;
    		this._joinCollections = [];

    		// Loop the joined collections and hook change events
    		for (i = 0; i < joinArr.length; i++) {
    			for (k in joinArr[i]) {
    				Eif (joinArr[i].hasOwnProperty(k)) {
    					this._joinCollections.push(k);
    				}
    			}
    		}

    		Eif (this._joinCollections.length) {
    			// Loop the collections and hook change events
    			for (i = 0; i < this._joinCollections.length; i++) {
    				this._db.collection(this._joinCollections[i]).on('immediateChange', self.__joinChange);
    			}
    		}
    	}

    	if (this._querySettings.options && this._querySettings.options.$orderBy) {
    		this.rebuildActiveBucket(this._querySettings.options.$orderBy);
    	} else {
    		this.rebuildActiveBucket();
    	}

    	return this;
    };

    /**
     * Handles when a change has occurred on a collection that is joined
     * by query to this view.
     * @param objName
     * @param objType
     * @private
     */
    View.prototype._joinChange = function (objName, objType) {
    	this.emit('joinChange');

    	// TODO: This is a really dirty solution because it will require a complete
    	// TODO: rebuild of the view data. We need to implement an IO handler to
    	// TODO: selectively update the data of the view based on the joined
    	// TODO: collection data operation.
    	// FIXME: This isnt working, major performance killer, invest in some IO from chain reactor to make this a targeted call
    	this.refresh();
    };

    /**
     * Returns the number of documents currently in the view.
     * @returns {Number}
     */
    View.prototype.count = function () {
    	return this._data.count.apply(this._data, arguments);
    };

    // Call underlying
    View.prototype.subset = function () {
    	return this._data.subset.apply(this._data, arguments);
    };

    /**
     * Takes the passed data and uses it to set transform methods and globally
     * enable or disable the transform system for the view.
     * @param {Object} obj The new transform system settings "enabled", "dataIn"
     * and "dataOut":
     * {
     * 	"enabled": true,
     * 	"dataIn": function (data) { return data; },
     * 	"dataOut": function (data) { return data; }
     * }
     * @returns {*}
     */
    View.prototype.transform = function (obj) {
    	var currentSettings,
    		newSettings;

    	currentSettings = this._data.transform();
    	this._data.transform(obj);
    	newSettings = this._data.transform();

    	// Check if transforms are enabled, a dataIn method is set and these
    	// settings did not match the previous transform settings
    	Eif (newSettings.enabled && newSettings.dataIn && (currentSettings.enabled !== newSettings.enabled || currentSettings.dataIn !== newSettings.dataIn)) {
    		// The data in the view is now stale, refresh it
    		this.refresh();
    	}

    	return newSettings;
    };

    /**
     * Executes a method against each document that matches query and returns an
     * array of documents that may have been modified by the method.
     * @param {Object} query The query object.
     * @param {Function} func The method that each document is passed to. If this method
     * returns false for a particular document it is excluded from the results.
     * @param {Object=} options Optional options object.
     * @returns {Array}
     */
    View.prototype.filter = function (query, func, options) {
    	return this._data.filter(query, func, options);
    };

    /**
     * Returns the non-transformed data the view holds as a collection
     * reference.
     * @return {Collection} The non-transformed collection reference.
     */
    View.prototype.data = function () {
    	return this._data;
    };

    /**
     * @see Collection.indexOf
     * @returns {*}
     */
    View.prototype.indexOf = function () {
    	return this._data.indexOf.apply(this._data, arguments);
    };

    /**
     * Gets / sets the db instance this class instance belongs to.
     * @param {Db=} db The db instance.
     * @memberof View
     * @returns {*}
     */
    Shared.synthesize(View.prototype, 'db', function (db) {
    	Eif (db) {
    		this._data.db(db);

    		// Apply the same debug settings
    		this.debug(db.debug());
    		this._data.debug(db.debug());
    	}

    	return this.$super.apply(this, arguments);
    });

    /**
     * Gets / sets the current state.
     * @param {String=} val The name of the state to set.
     * @returns {*}
     */
    Shared.synthesize(View.prototype, 'state');

    /**
     * Gets / sets the current name.
     * @param {String=} val The new name to set.
     * @returns {*}
     */
    Shared.synthesize(View.prototype, 'name');

    /**
     * Gets / sets the current cursor.
     * @param {String=} val The new cursor to set.
     * @returns {*}
     */
    Shared.synthesize(View.prototype, 'cursor', function (val) {
    	Iif (val === undefined) {
    		return this._cursor || {};
    	}

    	this.$super.apply(this, arguments);
    });

    // Extend collection with view init
    Collection.prototype.init = function () {
    	this._view = [];
    	CollectionInit.apply(this, arguments);
    };

    /**
     * Creates a view and assigns the collection as its data source.
     * @param {String} name The name of the new view.
     * @param {Object} query The query to apply to the new view.
     * @param {Object} options The options object to apply to the view.
     * @returns {*}
     */
    Collection.prototype.view = function (name, query, options) {
    	if (this._db && this._db._view ) {
    		if (!this._db._view[name]) {
    			var view = new View(name, query, options)
    				.db(this._db)
    				.from(this);

    			this._view = this._view || [];
    			this._view.push(view);

    			return view;
    		} else {
    			throw(this.logIdentifier() + ' Cannot create a view using this collection because a view with this name already exists: ' + name);
    		}
    	}
    };

    /**
     * Adds a view to the internal view lookup.
     * @param {View} view The view to add.
     * @returns {Collection}
     * @private
     */
    Collection.prototype._addView = CollectionGroup.prototype._addView = function (view) {
    	if (view !== undefined) {
    		this._view.push(view);
    	}

    	return this;
    };

    /**
     * Removes a view from the internal view lookup.
     * @param {View} view The view to remove.
     * @returns {Collection}
     * @private
     */
    Collection.prototype._removeView = CollectionGroup.prototype._removeView = function (view) {
    	Eif (view !== undefined) {
    		var index = this._view.indexOf(view);
    		Iif (index > -1) {
    			this._view.splice(index, 1);
    		}
    	}

    	return this;
    };

    // Extend DB with views init
    Db.prototype.init = function () {
    	this._view = {};
    	DbInit.apply(this, arguments);
    };

    /**
     * Gets a view by it's name.
     * @param {String} name The name of the view to retrieve.
     * @returns {*}
     */
    Db.prototype.view = function (name) {
    	var self = this;

    	// Handle being passed an instance
    	Iif (name instanceof View) {
    		return name;
    	}

    	if (this._view[name]) {
    		return this._view[name];
    	}

    	Eif (this.debug() || (this._db && this._db.debug())) {
    		console.log(this.logIdentifier() + ' Creating view ' + name);
    	}

    	this._view[name] = new View(name).db(this);

    	self.emit('create', self._view[name], 'view', name);

    	return this._view[name];
    };

    /**
     * Determine if a view with the passed name already exists.
     * @param {String} name The name of the view to check for.
     * @returns {boolean}
     */
    Db.prototype.viewExists = function (name) {
    	return Boolean(this._view[name]);
    };

    /**
     * Returns an array of views the DB currently has.
     * @returns {Array} An array of objects containing details of each view
     * the database is currently managing.
     */
    Db.prototype.views = function () {
    	var arr = [],
    		view,
    		i;

    	for (i in this._view) {
    		if (this._view.hasOwnProperty(i)) {
    			view = this._view[i];

    			arr.push({
    				name: i,
    				count: view.count(),
    				linked: view.isLinked !== undefined ? view.isLinked() : false
    			});
    		}
    	}

    	return arr;
    };

    Shared.finishModule('View');
    module.exports = View;
    },{"./ActiveBucket":3,"./Collection":7,"./CollectionGroup":8,"./Overload":32,"./ReactorIO":38,"./Shared":40}],43:[function(_dereq_,module,exports){
    (function (process,global){
    /*!
     * async
     * https://github.com/caolan/async
     *
     * Copyright 2010-2014 Caolan McMahon
     * Released under the MIT license
     */
    (function () {

        var async = {};
        function noop() {}
        function identity(v) {
            return v;
        }
        function toBool(v) {
            return !!v;
        }
        function notId(v) {
            return !v;
        }

        // global on the server, window in the browser
        var previous_async;

        // Establish the root object, `window` (`self`) in the browser, `global`
        // on the server, or `this` in some virtual machines. We use `self`
        // instead of `window` for `WebWorker` support.
        var root = typeof self === 'object' && self.self === self && self ||
                typeof global === 'object' && global.global === global && global ||
                this;

        Eif (root != null) {
            previous_async = root.async;
        }

        async.noConflict = function () {
            root.async = previous_async;
            return async;
        };

        function only_once(fn) {
            return function() {
                if (fn === null) throw new Error("Callback was already called.");
                fn.apply(this, arguments);
                fn = null;
            };
        }

        function _once(fn) {
            return function() {
                Iif (fn === null) return;
                fn.apply(this, arguments);
                fn = null;
            };
        }

        //// cross-browser compatiblity functions ////

        var _toString = Object.prototype.toString;

        var _isArray = Array.isArray || function (obj) {
            return _toString.call(obj) === '[object Array]';
        };

        // Ported from underscore.js isObject
        var _isObject = function(obj) {
            var type = typeof obj;
            return type === 'function' || type === 'object' && !!obj;
        };

        function _isArrayLike(arr) {
            return _isArray(arr) || (
                // has a positive integer length property
                typeof arr.length === "number" &&
                arr.length >= 0 &&
                arr.length % 1 === 0
            );
        }

        function _arrayEach(arr, iterator) {
            var index = -1,
                length = arr.length;

            while (++index < length) {
                iterator(arr[index], index, arr);
            }
        }

        function _map(arr, iterator) {
            var index = -1,
                length = arr.length,
                result = Array(length);

            while (++index < length) {
                result[index] = iterator(arr[index], index, arr);
            }
            return result;
        }

        function _range(count) {
            return _map(Array(count), function (v, i) { return i; });
        }

        function _reduce(arr, iterator, memo) {
            _arrayEach(arr, function (x, i, a) {
                memo = iterator(memo, x, i, a);
            });
            return memo;
        }

        function _forEachOf(object, iterator) {
            _arrayEach(_keys(object), function (key) {
                iterator(object[key], key);
            });
        }

        function _indexOf(arr, item) {
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] === item) return i;
            }
            return -1;
        }

        var _keys = Object.keys || function (obj) {
            var keys = [];
            for (var k in obj) {
                if (obj.hasOwnProperty(k)) {
                    keys.push(k);
                }
            }
            return keys;
        };

        function _keyIterator(coll) {
            var i = -1;
            var len;
            var keys;
            if (_isArrayLike(coll)) {
                len = coll.length;
                return function next() {
                    i++;
                    return i < len ? i : null;
                };
            } else {
                keys = _keys(coll);
                len = keys.length;
                return function next() {
                    i++;
                    return i < len ? keys[i] : null;
                };
            }
        }

        // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)
        // This accumulates the arguments passed into an array, after a given index.
        // From underscore.js (https://github.com/jashkenas/underscore/pull/2140).
        function _restParam(func, startIndex) {
            startIndex = startIndex == null ? func.length - 1 : +startIndex;
            return function() {
                var length = Math.max(arguments.length - startIndex, 0);
                var rest = Array(length);
                for (var index = 0; index < length; index++) {
                    rest[index] = arguments[index + startIndex];
                }
                switch (startIndex) {
                    case 0: return func.call(this, rest);
                    case 1: return func.call(this, arguments[0], rest);
                }
                // Currently unused but handle cases outside of the switch statement:
                // var args = Array(startIndex + 1);
                // for (index = 0; index < startIndex; index++) {
                //     args[index] = arguments[index];
                // }
                // args[startIndex] = rest;
                // return func.apply(this, args);
            };
        }

        function _withoutIndex(iterator) {
            return function (value, index, callback) {
                return iterator(value, callback);
            };
        }

        //// exported async module functions ////

        //// nextTick implementation with browser-compatible fallback ////

        // capture the global reference to guard against fakeTimer mocks
        var _setImmediate = typeof setImmediate === 'function' && setImmediate;

        var _delay = _setImmediate ? function(fn) {
            // not a direct alias for IE10 compatibility
            _setImmediate(fn);
        } : function(fn) {
            setTimeout(fn, 0);
        };

        Eif (typeof process === 'object' && typeof process.nextTick === 'function') {
            async.nextTick = process.nextTick;
        } else {
            async.nextTick = _delay;
        }
        async.setImmediate = _setImmediate ? _delay : async.nextTick;

        async.forEach =
        async.each = function (arr, iterator, callback) {
            return async.eachOf(arr, _withoutIndex(iterator), callback);
        };

        async.forEachSeries =
        async.eachSeries = function (arr, iterator, callback) {
            return async.eachOfSeries(arr, _withoutIndex(iterator), callback);
        };

        async.forEachLimit =
        async.eachLimit = function (arr, limit, iterator, callback) {
            return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback);
        };

        async.forEachOf =
        async.eachOf = function (object, iterator, callback) {
            callback = _once(callback || noop);
            object = object || [];

            var iter = _keyIterator(object);
            var key, completed = 0;

            while ((key = iter()) != null) {
                completed += 1;
                iterator(object[key], key, only_once(done));
            }

            if (completed === 0) callback(null);

            function done(err) {
                completed--;
                if (err) {
                    callback(err);
                }
                // Check key is null in case iterator isn't exhausted
                // and done resolved synchronously.
                else if (key === null && completed <= 0) {
                    callback(null);
                }
            }
        };

        async.forEachOfSeries =
        async.eachOfSeries = function (obj, iterator, callback) {
            callback = _once(callback || noop);
            obj = obj || [];
            var nextKey = _keyIterator(obj);
            var key = nextKey();
            function iterate() {
                var sync = true;
                if (key === null) {
                    return callback(null);
                }
                iterator(obj[key], key, only_once(function (err) {
                    if (err) {
                        callback(err);
                    }
                    else {
                        key = nextKey();
                        if (key === null) {
                            return callback(null);
                        } else {
                            if (sync) {
                                async.setImmediate(iterate);
                            } else {
                                iterate();
                            }
                        }
                    }
                }));
                sync = false;
            }
            iterate();
        };

        async.forEachOfLimit =
        async.eachOfLimit = function (obj, limit, iterator, callback) {
            _eachOfLimit(limit)(obj, iterator, callback);
        };

        function _eachOfLimit(limit) {

            return function (obj, iterator, callback) {
                callback = _once(callback || noop);
                obj = obj || [];
                var nextKey = _keyIterator(obj);
                if (limit <= 0) {
                    return callback(null);
                }
                var done = false;
                var running = 0;
                var errored = false;

                (function replenish () {
                    if (done && running <= 0) {
                        return callback(null);
                    }

                    while (running < limit && !errored) {
                        var key = nextKey();
                        if (key === null) {
                            done = true;
                            if (running <= 0) {
                                callback(null);
                            }
                            return;
                        }
                        running += 1;
                        iterator(obj[key], key, only_once(function (err) {
                            running -= 1;
                            if (err) {
                                callback(err);
                                errored = true;
                            }
                            else {
                                replenish();
                            }
                        }));
                    }
                })();
            };
        }

        function doParallel(fn) {
            return function (obj, iterator, callback) {
                return fn(async.eachOf, obj, iterator, callback);
            };
        }
        function doParallelLimit(fn) {
            return function (obj, limit, iterator, callback) {
                return fn(_eachOfLimit(limit), obj, iterator, callback);
            };
        }
        function doSeries(fn) {
            return function (obj, iterator, callback) {
                return fn(async.eachOfSeries, obj, iterator, callback);
            };
        }

        function _asyncMap(eachfn, arr, iterator, callback) {
            callback = _once(callback || noop);
            arr = arr || [];
            var results = _isArrayLike(arr) ? [] : {};
            eachfn(arr, function (value, index, callback) {
                iterator(value, function (err, v) {
                    results[index] = v;
                    callback(err);
                });
            }, function (err) {
                callback(err, results);
            });
        }

        async.map = doParallel(_asyncMap);
        async.mapSeries = doSeries(_asyncMap);
        async.mapLimit = doParallelLimit(_asyncMap);

        // reduce only has a series version, as doing reduce in parallel won't
        // work in many situations.
        async.inject =
        async.foldl =
        async.reduce = function (arr, memo, iterator, callback) {
            async.eachOfSeries(arr, function (x, i, callback) {
                iterator(memo, x, function (err, v) {
                    memo = v;
                    callback(err);
                });
            }, function (err) {
                callback(err, memo);
            });
        };

        async.foldr =
        async.reduceRight = function (arr, memo, iterator, callback) {
            var reversed = _map(arr, identity).reverse();
            async.reduce(reversed, memo, iterator, callback);
        };

        async.transform = function (arr, memo, iterator, callback) {
            if (arguments.length === 3) {
                callback = iterator;
                iterator = memo;
                memo = _isArray(arr) ? [] : {};
            }

            async.eachOf(arr, function(v, k, cb) {
                iterator(memo, v, k, cb);
            }, function(err) {
                callback(err, memo);
            });
        };

        function _filter(eachfn, arr, iterator, callback) {
            var results = [];
            eachfn(arr, function (x, index, callback) {
                iterator(x, function (v) {
                    if (v) {
                        results.push({index: index, value: x});
                    }
                    callback();
                });
            }, function () {
                callback(_map(results.sort(function (a, b) {
                    return a.index - b.index;
                }), function (x) {
                    return x.value;
                }));
            });
        }

        async.select =
        async.filter = doParallel(_filter);

        async.selectLimit =
        async.filterLimit = doParallelLimit(_filter);

        async.selectSeries =
        async.filterSeries = doSeries(_filter);

        function _reject(eachfn, arr, iterator, callback) {
            _filter(eachfn, arr, function(value, cb) {
                iterator(value, function(v) {
                    cb(!v);
                });
            }, callback);
        }
        async.reject = doParallel(_reject);
        async.rejectLimit = doParallelLimit(_reject);
        async.rejectSeries = doSeries(_reject);

        function _createTester(eachfn, check, getResult) {
            return function(arr, limit, iterator, cb) {
                function done() {
                    if (cb) cb(getResult(false, void 0));
                }
                function iteratee(x, _, callback) {
                    if (!cb) return callback();
                    iterator(x, function (v) {
                        if (cb && check(v)) {
                            cb(getResult(true, x));
                            cb = iterator = false;
                        }
                        callback();
                    });
                }
                if (arguments.length > 3) {
                    eachfn(arr, limit, iteratee, done);
                } else {
                    cb = iterator;
                    iterator = limit;
                    eachfn(arr, iteratee, done);
                }
            };
        }

        async.any =
        async.some = _createTester(async.eachOf, toBool, identity);

        async.someLimit = _createTester(async.eachOfLimit, toBool, identity);

        async.all =
        async.every = _createTester(async.eachOf, notId, notId);

        async.everyLimit = _createTester(async.eachOfLimit, notId, notId);

        function _findGetResult(v, x) {
            return x;
        }
        async.detect = _createTester(async.eachOf, identity, _findGetResult);
        async.detectSeries = _createTester(async.eachOfSeries, identity, _findGetResult);
        async.detectLimit = _createTester(async.eachOfLimit, identity, _findGetResult);

        async.sortBy = function (arr, iterator, callback) {
            async.map(arr, function (x, callback) {
                iterator(x, function (err, criteria) {
                    if (err) {
                        callback(err);
                    }
                    else {
                        callback(null, {value: x, criteria: criteria});
                    }
                });
            }, function (err, results) {
                if (err) {
                    return callback(err);
                }
                else {
                    callback(null, _map(results.sort(comparator), function (x) {
                        return x.value;
                    }));
                }

            });

            function comparator(left, right) {
                var a = left.criteria, b = right.criteria;
                return a < b ? -1 : a > b ? 1 : 0;
            }
        };

        async.auto = function (tasks, concurrency, callback) {
            if (!callback) {
                // concurrency is optional, shift the args.
                callback = concurrency;
                concurrency = null;
            }
            callback = _once(callback || noop);
            var keys = _keys(tasks);
            var remainingTasks = keys.length;
            if (!remainingTasks) {
                return callback(null);
            }
            if (!concurrency) {
                concurrency = remainingTasks;
            }

            var results = {};
            var runningTasks = 0;

            var listeners = [];
            function addListener(fn) {
                listeners.unshift(fn);
            }
            function removeListener(fn) {
                var idx = _indexOf(listeners, fn);
                if (idx >= 0) listeners.splice(idx, 1);
            }
            function taskComplete() {
                remainingTasks--;
                _arrayEach(listeners.slice(0), function (fn) {
                    fn();
                });
            }

            addListener(function () {
                if (!remainingTasks) {
                    callback(null, results);
                }
            });

            _arrayEach(keys, function (k) {
                var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
                var taskCallback = _restParam(function(err, args) {
                    runningTasks--;
                    if (args.length <= 1) {
                        args = args[0];
                    }
                    if (err) {
                        var safeResults = {};
                        _forEachOf(results, function(val, rkey) {
                            safeResults[rkey] = val;
                        });
                        safeResults[k] = args;
                        callback(err, safeResults);
                    }
                    else {
                        results[k] = args;
                        async.setImmediate(taskComplete);
                    }
                });
                var requires = task.slice(0, task.length - 1);
                // prevent dead-locks
                var len = requires.length;
                var dep;
                while (len--) {
                    if (!(dep = tasks[requires[len]])) {
                        throw new Error('Has inexistant dependency');
                    }
                    if (_isArray(dep) && _indexOf(dep, k) >= 0) {
                        throw new Error('Has cyclic dependencies');
                    }
                }
                function ready() {
                    return runningTasks < concurrency && _reduce(requires, function (a, x) {
                        return (a && results.hasOwnProperty(x));
                    }, true) && !results.hasOwnProperty(k);
                }
                if (ready()) {
                    runningTasks++;
                    task[task.length - 1](taskCallback, results);
                }
                else {
                    addListener(listener);
                }
                function listener() {
                    if (ready()) {
                        runningTasks++;
                        removeListener(listener);
                        task[task.length - 1](taskCallback, results);
                    }
                }
            });
        };

        async.retry = function(times, task, callback) {
            var DEFAULT_TIMES = 5;
            var DEFAULT_INTERVAL = 0;

            var attempts = [];

            var opts = {
                times: DEFAULT_TIMES,
                interval: DEFAULT_INTERVAL
            };

            function parseTimes(acc, t){
                if(typeof t === 'number'){
                    acc.times = parseInt(t, 10) || DEFAULT_TIMES;
                } else if(typeof t === 'object'){
                    acc.times = parseInt(t.times, 10) || DEFAULT_TIMES;
                    acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL;
                } else {
                    throw new Error('Unsupported argument type for \'times\': ' + typeof t);
                }
            }

            var length = arguments.length;
            if (length < 1 || length > 3) {
                throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)');
            } else if (length <= 2 && typeof times === 'function') {
                callback = task;
                task = times;
            }
            if (typeof times !== 'function') {
                parseTimes(opts, times);
            }
            opts.callback = callback;
            opts.task = task;

            function wrappedTask(wrappedCallback, wrappedResults) {
                function retryAttempt(task, finalAttempt) {
                    return function(seriesCallback) {
                        task(function(err, result){
                            seriesCallback(!err || finalAttempt, {err: err, result: result});
                        }, wrappedResults);
                    };
                }

                function retryInterval(interval){
                    return function(seriesCallback){
                        setTimeout(function(){
                            seriesCallback(null);
                        }, interval);
                    };
                }

                while (opts.times) {

                    var finalAttempt = !(opts.times-=1);
                    attempts.push(retryAttempt(opts.task, finalAttempt));
                    if(!finalAttempt && opts.interval > 0){
                        attempts.push(retryInterval(opts.interval));
                    }
                }

                async.series(attempts, function(done, data){
                    data = data[data.length - 1];
                    (wrappedCallback || opts.callback)(data.err, data.result);
                });
            }

            // If a callback is passed, run this as a controll flow
            return opts.callback ? wrappedTask() : wrappedTask;
        };

        async.waterfall = function (tasks, callback) {
            callback = _once(callback || noop);
            Iif (!_isArray(tasks)) {
                var err = new Error('First argument to waterfall must be an array of functions');
                return callback(err);
            }
            Iif (!tasks.length) {
                return callback();
            }
            function wrapIterator(iterator) {
                return _restParam(function (err, args) {
                    Iif (err) {
                        callback.apply(null, [err].concat(args));
                    }
                    else {
                        var next = iterator.next();
                        if (next) {
                            args.push(wrapIterator(next));
                        }
                        else {
                            args.push(callback);
                        }
                        ensureAsync(iterator).apply(null, args);
                    }
                });
            }
            wrapIterator(async.iterator(tasks))();
        };

        function _parallel(eachfn, tasks, callback) {
            callback = callback || noop;
            var results = _isArrayLike(tasks) ? [] : {};

            eachfn(tasks, function (task, key, callback) {
                task(_restParam(function (err, args) {
                    if (args.length <= 1) {
                        args = args[0];
                    }
                    results[key] = args;
                    callback(err);
                }));
            }, function (err) {
                callback(err, results);
            });
        }

        async.parallel = function (tasks, callback) {
            _parallel(async.eachOf, tasks, callback);
        };

        async.parallelLimit = function(tasks, limit, callback) {
            _parallel(_eachOfLimit(limit), tasks, callback);
        };

        async.series = function(tasks, callback) {
            _parallel(async.eachOfSeries, tasks, callback);
        };

        async.iterator = function (tasks) {
            function makeCallback(index) {
                function fn() {
                    Eif (tasks.length) {
                        tasks[index].apply(null, arguments);
                    }
                    return fn.next();
                }
                fn.next = function () {
                    return (index < tasks.length - 1) ? makeCallback(index + 1): null;
                };
                return fn;
            }
            return makeCallback(0);
        };

        async.apply = _restParam(function (fn, args) {
            return _restParam(function (callArgs) {
                return fn.apply(
                    null, args.concat(callArgs)
                );
            });
        });

        function _concat(eachfn, arr, fn, callback) {
            var result = [];
            eachfn(arr, function (x, index, cb) {
                fn(x, function (err, y) {
                    result = result.concat(y || []);
                    cb(err);
                });
            }, function (err) {
                callback(err, result);
            });
        }
        async.concat = doParallel(_concat);
        async.concatSeries = doSeries(_concat);

        async.whilst = function (test, iterator, callback) {
            callback = callback || noop;
            if (test()) {
                var next = _restParam(function(err, args) {
                    if (err) {
                        callback(err);
                    } else if (test.apply(this, args)) {
                        iterator(next);
                    } else {
                        callback(null);
                    }
                });
                iterator(next);
            } else {
                callback(null);
            }
        };

        async.doWhilst = function (iterator, test, callback) {
            var calls = 0;
            return async.whilst(function() {
                return ++calls <= 1 || test.apply(this, arguments);
            }, iterator, callback);
        };

        async.until = function (test, iterator, callback) {
            return async.whilst(function() {
                return !test.apply(this, arguments);
            }, iterator, callback);
        };

        async.doUntil = function (iterator, test, callback) {
            return async.doWhilst(iterator, function() {
                return !test.apply(this, arguments);
            }, callback);
        };

        async.during = function (test, iterator, callback) {
            callback = callback || noop;

            var next = _restParam(function(err, args) {
                if (err) {
                    callback(err);
                } else {
                    args.push(check);
                    test.apply(this, args);
                }
            });

            var check = function(err, truth) {
                if (err) {
                    callback(err);
                } else if (truth) {
                    iterator(next);
                } else {
                    callback(null);
                }
            };

            test(check);
        };

        async.doDuring = function (iterator, test, callback) {
            var calls = 0;
            async.during(function(next) {
                if (calls++ < 1) {
                    next(null, true);
                } else {
                    test.apply(this, arguments);
                }
            }, iterator, callback);
        };

        function _queue(worker, concurrency, payload) {
            if (concurrency == null) {
                concurrency = 1;
            }
            else if(concurrency === 0) {
                throw new Error('Concurrency must not be zero');
            }
            function _insert(q, data, pos, callback) {
                if (callback != null && typeof callback !== "function") {
                    throw new Error("task callback must be a function");
                }
                q.started = true;
                if (!_isArray(data)) {
                    data = [data];
                }
                if(data.length === 0 && q.idle()) {
                    // call drain immediately if there are no tasks
                    return async.setImmediate(function() {
                        q.drain();
                    });
                }
                _arrayEach(data, function(task) {
                    var item = {
                        data: task,
                        callback: callback || noop
                    };

                    if (pos) {
                        q.tasks.unshift(item);
                    } else {
                        q.tasks.push(item);
                    }

                    if (q.tasks.length === q.concurrency) {
                        q.saturated();
                    }
                });
                async.setImmediate(q.process);
            }
            function _next(q, tasks) {
                return function(){
                    workers -= 1;

                    var removed = false;
                    var args = arguments;
                    _arrayEach(tasks, function (task) {
                        _arrayEach(workersList, function (worker, index) {
                            if (worker === task && !removed) {
                                workersList.splice(index, 1);
                                removed = true;
                            }
                        });

                        task.callback.apply(task, args);
                    });
                    if (q.tasks.length + workers === 0) {
                        q.drain();
                    }
                    q.process();
                };
            }

            var workers = 0;
            var workersList = [];
            var q = {
                tasks: [],
                concurrency: concurrency,
                payload: payload,
                saturated: noop,
                empty: noop,
                drain: noop,
                started: false,
                paused: false,
                push: function (data, callback) {
                    _insert(q, data, false, callback);
                },
                kill: function () {
                    q.drain = noop;
                    q.tasks = [];
                },
                unshift: function (data, callback) {
                    _insert(q, data, true, callback);
                },
                process: function () {
                    if (!q.paused && workers < q.concurrency && q.tasks.length) {
                        while(workers < q.concurrency && q.tasks.length){
                            var tasks = q.payload ?
                                q.tasks.splice(0, q.payload) :
                                q.tasks.splice(0, q.tasks.length);

                            var data = _map(tasks, function (task) {
                                return task.data;
                            });

                            if (q.tasks.length === 0) {
                                q.empty();
                            }
                            workers += 1;
                            workersList.push(tasks[0]);
                            var cb = only_once(_next(q, tasks));
                            worker(data, cb);
                        }
                    }
                },
                length: function () {
                    return q.tasks.length;
                },
                running: function () {
                    return workers;
                },
                workersList: function () {
                    return workersList;
                },
                idle: function() {
                    return q.tasks.length + workers === 0;
                },
                pause: function () {
                    q.paused = true;
                },
                resume: function () {
                    if (q.paused === false) { return; }
                    q.paused = false;
                    var resumeCount = Math.min(q.concurrency, q.tasks.length);
                    // Need to call q.process once per concurrent
                    // worker to preserve full concurrency after pause
                    for (var w = 1; w <= resumeCount; w++) {
                        async.setImmediate(q.process);
                    }
                }
            };
            return q;
        }

        async.queue = function (worker, concurrency) {
            var q = _queue(function (items, cb) {
                worker(items[0], cb);
            }, concurrency, 1);

            return q;
        };

        async.priorityQueue = function (worker, concurrency) {

            function _compareTasks(a, b){
                return a.priority - b.priority;
            }

            function _binarySearch(sequence, item, compare) {
                var beg = -1,
                    end = sequence.length - 1;
                while (beg < end) {
                    var mid = beg + ((end - beg + 1) >>> 1);
                    if (compare(item, sequence[mid]) >= 0) {
                        beg = mid;
                    } else {
                        end = mid - 1;
                    }
                }
                return beg;
            }

            function _insert(q, data, priority, callback) {
                if (callback != null && typeof callback !== "function") {
                    throw new Error("task callback must be a function");
                }
                q.started = true;
                if (!_isArray(data)) {
                    data = [data];
                }
                if(data.length === 0) {
                    // call drain immediately if there are no tasks
                    return async.setImmediate(function() {
                        q.drain();
                    });
                }
                _arrayEach(data, function(task) {
                    var item = {
                        data: task,
                        priority: priority,
                        callback: typeof callback === 'function' ? callback : noop
                    };

                    q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);

                    if (q.tasks.length === q.concurrency) {
                        q.saturated();
                    }
                    async.setImmediate(q.process);
                });
            }

            // Start with a normal queue
            var q = async.queue(worker, concurrency);

            // Override push to accept second parameter representing priority
            q.push = function (data, priority, callback) {
                _insert(q, data, priority, callback);
            };

            // Remove unshift function
            delete q.unshift;

            return q;
        };

        async.cargo = function (worker, payload) {
            return _queue(worker, 1, payload);
        };

        function _console_fn(name) {
            return _restParam(function (fn, args) {
                fn.apply(null, args.concat([_restParam(function (err, args) {
                    if (typeof console === 'object') {
                        if (err) {
                            if (console.error) {
                                console.error(err);
                            }
                        }
                        else if (console[name]) {
                            _arrayEach(args, function (x) {
                                console[name](x);
                            });
                        }
                    }
                })]));
            });
        }
        async.log = _console_fn('log');
        async.dir = _console_fn('dir');
        /*async.info = _console_fn('info');
        async.warn = _console_fn('warn');
        async.error = _console_fn('error');*/

        async.memoize = function (fn, hasher) {
            var memo = {};
            var queues = {};
            hasher = hasher || identity;
            var memoized = _restParam(function memoized(args) {
                var callback = args.pop();
                var key = hasher.apply(null, args);
                if (key in memo) {
                    async.setImmediate(function () {
                        callback.apply(null, memo[key]);
                    });
                }
                else if (key in queues) {
                    queues[key].push(callback);
                }
                else {
                    queues[key] = [callback];
                    fn.apply(null, args.concat([_restParam(function (args) {
                        memo[key] = args;
                        var q = queues[key];
                        delete queues[key];
                        for (var i = 0, l = q.length; i < l; i++) {
                            q[i].apply(null, args);
                        }
                    })]));
                }
            });
            memoized.memo = memo;
            memoized.unmemoized = fn;
            return memoized;
        };

        async.unmemoize = function (fn) {
            return function () {
                return (fn.unmemoized || fn).apply(null, arguments);
            };
        };

        function _times(mapper) {
            return function (count, iterator, callback) {
                mapper(_range(count), iterator, callback);
            };
        }

        async.times = _times(async.map);
        async.timesSeries = _times(async.mapSeries);
        async.timesLimit = function (count, limit, iterator, callback) {
            return async.mapLimit(_range(count), limit, iterator, callback);
        };

        async.seq = function (/* functions... */) {
            var fns = arguments;
            return _restParam(function (args) {
                var that = this;

                var callback = args[args.length - 1];
                if (typeof callback == 'function') {
                    args.pop();
                } else {
                    callback = noop;
                }

                async.reduce(fns, args, function (newargs, fn, cb) {
                    fn.apply(that, newargs.concat([_restParam(function (err, nextargs) {
                        cb(err, nextargs);
                    })]));
                },
                function (err, results) {
                    callback.apply(that, [err].concat(results));
                });
            });
        };

        async.compose = function (/* functions... */) {
            return async.seq.apply(null, Array.prototype.reverse.call(arguments));
        };

        function _applyEach(eachfn) {
            return _restParam(function(fns, args) {
                var go = _restParam(function(args) {
                    var that = this;
                    var callback = args.pop();
                    return eachfn(fns, function (fn, _, cb) {
                        fn.apply(that, args.concat([cb]));
                    },
                    callback);
                });
                if (args.length) {
                    return go.apply(this, args);
                }
                else {
                    return go;
                }
            });
        }

        async.applyEach = _applyEach(async.eachOf);
        async.applyEachSeries = _applyEach(async.eachOfSeries);

        async.forever = function (fn, callback) {
            var done = only_once(callback || noop);
            var task = ensureAsync(fn);
            function next(err) {
                if (err) {
                    return done(err);
                }
                task(next);
            }
            next();
        };

        function ensureAsync(fn) {
            return _restParam(function (args) {
                var callback = args.pop();
                args.push(function () {
                    var innerArgs = arguments;
                    Eif (sync) {
                        async.setImmediate(function () {
                            callback.apply(null, innerArgs);
                        });
                    } else {
                        callback.apply(null, innerArgs);
                    }
                });
                var sync = true;
                fn.apply(this, args);
                sync = false;
            });
        }

        async.ensureAsync = ensureAsync;

        async.constant = _restParam(function(values) {
            var args = [null].concat(values);
            return function (callback) {
                return callback.apply(this, args);
            };
        });

        async.wrapSync =
        async.asyncify = function asyncify(func) {
            return _restParam(function (args) {
                var callback = args.pop();
                var result;
                try {
                    result = func.apply(this, args);
                } catch (e) {
                    return callback(e);
                }
                // if result is Promise object
                if (_isObject(result) && typeof result.then === "function") {
                    result.then(function(value) {
                        callback(null, value);
                    })["catch"](function(err) {
                        callback(err.message ? err : new Error(err));
                    });
                } else {
                    callback(null, result);
                }
            });
        };

        // Node.js
        Eif (typeof module === 'object' && module.exports) {
            module.exports = async;
        }
        // AMD / RequireJS
        else if (typeof define === 'function' && define.amd) {
            define([], function () {
                return async;
            });
        }
        // included directly via <script> tag
        else {
            root.async = async;
        }

    }());

    }).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"_process":78}],44:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./enc-base64"), _dereq_("./md5"), _dereq_("./evpkdf"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var BlockCipher = C_lib.BlockCipher;
    	    var C_algo = C.algo;

    	    // Lookup tables
    	    var SBOX = [];
    	    var INV_SBOX = [];
    	    var SUB_MIX_0 = [];
    	    var SUB_MIX_1 = [];
    	    var SUB_MIX_2 = [];
    	    var SUB_MIX_3 = [];
    	    var INV_SUB_MIX_0 = [];
    	    var INV_SUB_MIX_1 = [];
    	    var INV_SUB_MIX_2 = [];
    	    var INV_SUB_MIX_3 = [];

    	    // Compute lookup tables
    	    (function () {
    	        // Compute double table
    	        var d = [];
    	        for (var i = 0; i < 256; i++) {
    	            if (i < 128) {
    	                d[i] = i << 1;
    	            } else {
    	                d[i] = (i << 1) ^ 0x11b;
    	            }
    	        }

    	        // Walk GF(2^8)
    	        var x = 0;
    	        var xi = 0;
    	        for (var i = 0; i < 256; i++) {
    	            // Compute sbox
    	            var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4);
    	            sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63;
    	            SBOX[x] = sx;
    	            INV_SBOX[sx] = x;

    	            // Compute multiplication
    	            var x2 = d[x];
    	            var x4 = d[x2];
    	            var x8 = d[x4];

    	            // Compute sub bytes, mix columns tables
    	            var t = (d[sx] * 0x101) ^ (sx * 0x1010100);
    	            SUB_MIX_0[x] = (t << 24) | (t >>> 8);
    	            SUB_MIX_1[x] = (t << 16) | (t >>> 16);
    	            SUB_MIX_2[x] = (t << 8)  | (t >>> 24);
    	            SUB_MIX_3[x] = t;

    	            // Compute inv sub bytes, inv mix columns tables
    	            var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100);
    	            INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8);
    	            INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16);
    	            INV_SUB_MIX_2[sx] = (t << 8)  | (t >>> 24);
    	            INV_SUB_MIX_3[sx] = t;

    	            // Compute next counter
    	            if (!x) {
    	                x = xi = 1;
    	            } else {
    	                x = x2 ^ d[d[d[x8 ^ x2]]];
    	                xi ^= d[d[xi]];
    	            }
    	        }
    	    }());

    	    // Precomputed Rcon lookup
    	    var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];

    	    /**
    	     * AES block cipher algorithm.
    	     */
    	    var AES = C_algo.AES = BlockCipher.extend({
    	        _doReset: function () {
    	            // Shortcuts
    	            var key = this._key;
    	            var keyWords = key.words;
    	            var keySize = key.sigBytes / 4;

    	            // Compute number of rounds
    	            var nRounds = this._nRounds = keySize + 6

    	            // Compute number of key schedule rows
    	            var ksRows = (nRounds + 1) * 4;

    	            // Compute key schedule
    	            var keySchedule = this._keySchedule = [];
    	            for (var ksRow = 0; ksRow < ksRows; ksRow++) {
    	                if (ksRow < keySize) {
    	                    keySchedule[ksRow] = keyWords[ksRow];
    	                } else {
    	                    var t = keySchedule[ksRow - 1];

    	                    if (!(ksRow % keySize)) {
    	                        // Rot word
    	                        t = (t << 8) | (t >>> 24);

    	                        // Sub word
    	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];

    	                        // Mix Rcon
    	                        t ^= RCON[(ksRow / keySize) | 0] << 24;
    	                    } else if (keySize > 6 && ksRow % keySize == 4) {
    	                        // Sub word
    	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
    	                    }

    	                    keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t;
    	                }
    	            }

    	            // Compute inv key schedule
    	            var invKeySchedule = this._invKeySchedule = [];
    	            for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) {
    	                var ksRow = ksRows - invKsRow;

    	                if (invKsRow % 4) {
    	                    var t = keySchedule[ksRow];
    	                } else {
    	                    var t = keySchedule[ksRow - 4];
    	                }

    	                if (invKsRow < 4 || ksRow <= 4) {
    	                    invKeySchedule[invKsRow] = t;
    	                } else {
    	                    invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^
    	                                               INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]];
    	                }
    	            }
    	        },

    	        encryptBlock: function (M, offset) {
    	            this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX);
    	        },

    	        decryptBlock: function (M, offset) {
    	            // Swap 2nd and 4th rows
    	            var t = M[offset + 1];
    	            M[offset + 1] = M[offset + 3];
    	            M[offset + 3] = t;

    	            this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX);

    	            // Inv swap 2nd and 4th rows
    	            var t = M[offset + 1];
    	            M[offset + 1] = M[offset + 3];
    	            M[offset + 3] = t;
    	        },

    	        _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) {
    	            // Shortcut
    	            var nRounds = this._nRounds;

    	            // Get input, add round key
    	            var s0 = M[offset]     ^ keySchedule[0];
    	            var s1 = M[offset + 1] ^ keySchedule[1];
    	            var s2 = M[offset + 2] ^ keySchedule[2];
    	            var s3 = M[offset + 3] ^ keySchedule[3];

    	            // Key schedule row counter
    	            var ksRow = 4;

    	            // Rounds
    	            for (var round = 1; round < nRounds; round++) {
    	                // Shift rows, sub bytes, mix columns, add round key
    	                var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++];
    	                var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++];
    	                var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++];
    	                var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++];

    	                // Update state
    	                s0 = t0;
    	                s1 = t1;
    	                s2 = t2;
    	                s3 = t3;
    	            }

    	            // Shift rows, sub bytes, add round key
    	            var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++];
    	            var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++];
    	            var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++];
    	            var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++];

    	            // Set output
    	            M[offset]     = t0;
    	            M[offset + 1] = t1;
    	            M[offset + 2] = t2;
    	            M[offset + 3] = t3;
    	        },

    	        keySize: 256/32
    	    });

    	    /**
    	     * Shortcut functions to the cipher's object interface.
    	     *
    	     * @example
    	     *
    	     *     var ciphertext = CryptoJS.AES.encrypt(message, key, cfg);
    	     *     var plaintext  = CryptoJS.AES.decrypt(ciphertext, key, cfg);
    	     */
    	    C.AES = BlockCipher._createHelper(AES);
    	}());

    	return CryptoJS.AES;

    }));
    },{"./cipher-core":45,"./core":46,"./enc-base64":47,"./evpkdf":49,"./md5":54}],45:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * Cipher core components.
    	 */
    	CryptoJS.lib.Cipher || (function (undefined) {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var Base = C_lib.Base;
    	    var WordArray = C_lib.WordArray;
    	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm;
    	    var C_enc = C.enc;
    	    var Utf8 = C_enc.Utf8;
    	    var Base64 = C_enc.Base64;
    	    var C_algo = C.algo;
    	    var EvpKDF = C_algo.EvpKDF;

    	    /**
    	     * Abstract base cipher template.
    	     *
    	     * @property {number} keySize This cipher's key size. Default: 4 (128 bits)
    	     * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)
    	     * @property {number} _ENC_XFORM_MODE A constant representing encryption mode.
    	     * @property {number} _DEC_XFORM_MODE A constant representing decryption mode.
    	     */
    	    var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {WordArray} iv The IV to use for this operation.
    	         */
    	        cfg: Base.extend(),

    	        /**
    	         * Creates this cipher in encryption mode.
    	         *
    	         * @param {WordArray} key The key.
    	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
    	         *
    	         * @return {Cipher} A cipher instance.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });
    	         */
    	        createEncryptor: function (key, cfg) {
    	            return this.create(this._ENC_XFORM_MODE, key, cfg);
    	        },

    	        /**
    	         * Creates this cipher in decryption mode.
    	         *
    	         * @param {WordArray} key The key.
    	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
    	         *
    	         * @return {Cipher} A cipher instance.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });
    	         */
    	        createDecryptor: function (key, cfg) {
    	            return this.create(this._DEC_XFORM_MODE, key, cfg);
    	        },

    	        /**
    	         * Initializes a newly created cipher.
    	         *
    	         * @param {number} xformMode Either the encryption or decryption transormation mode constant.
    	         * @param {WordArray} key The key.
    	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
    	         *
    	         * @example
    	         *
    	         *     var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });
    	         */
    	        init: function (xformMode, key, cfg) {
    	            // Apply config defaults
    	            this.cfg = this.cfg.extend(cfg);

    	            // Store transform mode and key
    	            this._xformMode = xformMode;
    	            this._key = key;

    	            // Set initial values
    	            this.reset();
    	        },

    	        /**
    	         * Resets this cipher to its initial state.
    	         *
    	         * @example
    	         *
    	         *     cipher.reset();
    	         */
    	        reset: function () {
    	            // Reset data buffer
    	            BufferedBlockAlgorithm.reset.call(this);

    	            // Perform concrete-cipher logic
    	            this._doReset();
    	        },

    	        /**
    	         * Adds data to be encrypted or decrypted.
    	         *
    	         * @param {WordArray|string} dataUpdate The data to encrypt or decrypt.
    	         *
    	         * @return {WordArray} The data after processing.
    	         *
    	         * @example
    	         *
    	         *     var encrypted = cipher.process('data');
    	         *     var encrypted = cipher.process(wordArray);
    	         */
    	        process: function (dataUpdate) {
    	            // Append
    	            this._append(dataUpdate);

    	            // Process available blocks
    	            return this._process();
    	        },

    	        /**
    	         * Finalizes the encryption or decryption process.
    	         * Note that the finalize operation is effectively a destructive, read-once operation.
    	         *
    	         * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.
    	         *
    	         * @return {WordArray} The data after final processing.
    	         *
    	         * @example
    	         *
    	         *     var encrypted = cipher.finalize();
    	         *     var encrypted = cipher.finalize('data');
    	         *     var encrypted = cipher.finalize(wordArray);
    	         */
    	        finalize: function (dataUpdate) {
    	            // Final data update
    	            Eif (dataUpdate) {
    	                this._append(dataUpdate);
    	            }

    	            // Perform concrete-cipher logic
    	            var finalProcessedData = this._doFinalize();

    	            return finalProcessedData;
    	        },

    	        keySize: 128/32,

    	        ivSize: 128/32,

    	        _ENC_XFORM_MODE: 1,

    	        _DEC_XFORM_MODE: 2,

    	        /**
    	         * Creates shortcut functions to a cipher's object interface.
    	         *
    	         * @param {Cipher} cipher The cipher to create a helper for.
    	         *
    	         * @return {Object} An object with encrypt and decrypt shortcut functions.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);
    	         */
    	        _createHelper: (function () {
    	            function selectCipherStrategy(key) {
    	                Eif (typeof key == 'string') {
    	                    return PasswordBasedCipher;
    	                } else {
    	                    return SerializableCipher;
    	                }
    	            }

    	            return function (cipher) {
    	                return {
    	                    encrypt: function (message, key, cfg) {
    	                        return selectCipherStrategy(key).encrypt(cipher, message, key, cfg);
    	                    },

    	                    decrypt: function (ciphertext, key, cfg) {
    	                        return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg);
    	                    }
    	                };
    	            };
    	        }())
    	    });

    	    /**
    	     * Abstract base stream cipher template.
    	     *
    	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits)
    	     */
    	    var StreamCipher = C_lib.StreamCipher = Cipher.extend({
    	        _doFinalize: function () {
    	            // Process partial blocks
    	            var finalProcessedBlocks = this._process(!!'flush');

    	            return finalProcessedBlocks;
    	        },

    	        blockSize: 1
    	    });

    	    /**
    	     * Mode namespace.
    	     */
    	    var C_mode = C.mode = {};

    	    /**
    	     * Abstract base block cipher mode template.
    	     */
    	    var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({
    	        /**
    	         * Creates this mode for encryption.
    	         *
    	         * @param {Cipher} cipher A block cipher instance.
    	         * @param {Array} iv The IV words.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
    	         */
    	        createEncryptor: function (cipher, iv) {
    	            return this.Encryptor.create(cipher, iv);
    	        },

    	        /**
    	         * Creates this mode for decryption.
    	         *
    	         * @param {Cipher} cipher A block cipher instance.
    	         * @param {Array} iv The IV words.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);
    	         */
    	        createDecryptor: function (cipher, iv) {
    	            return this.Decryptor.create(cipher, iv);
    	        },

    	        /**
    	         * Initializes a newly created mode.
    	         *
    	         * @param {Cipher} cipher A block cipher instance.
    	         * @param {Array} iv The IV words.
    	         *
    	         * @example
    	         *
    	         *     var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);
    	         */
    	        init: function (cipher, iv) {
    	            this._cipher = cipher;
    	            this._iv = iv;
    	        }
    	    });

    	    /**
    	     * Cipher Block Chaining mode.
    	     */
    	    var CBC = C_mode.CBC = (function () {
    	        /**
    	         * Abstract base CBC mode.
    	         */
    	        var CBC = BlockCipherMode.extend();

    	        /**
    	         * CBC encryptor.
    	         */
    	        CBC.Encryptor = CBC.extend({
    	            /**
    	             * Processes the data block at offset.
    	             *
    	             * @param {Array} words The data words to operate on.
    	             * @param {number} offset The offset where the block starts.
    	             *
    	             * @example
    	             *
    	             *     mode.processBlock(data.words, offset);
    	             */
    	            processBlock: function (words, offset) {
    	                // Shortcuts
    	                var cipher = this._cipher;
    	                var blockSize = cipher.blockSize;

    	                // XOR and encrypt
    	                xorBlock.call(this, words, offset, blockSize);
    	                cipher.encryptBlock(words, offset);

    	                // Remember this block to use with next block
    	                this._prevBlock = words.slice(offset, offset + blockSize);
    	            }
    	        });

    	        /**
    	         * CBC decryptor.
    	         */
    	        CBC.Decryptor = CBC.extend({
    	            /**
    	             * Processes the data block at offset.
    	             *
    	             * @param {Array} words The data words to operate on.
    	             * @param {number} offset The offset where the block starts.
    	             *
    	             * @example
    	             *
    	             *     mode.processBlock(data.words, offset);
    	             */
    	            processBlock: function (words, offset) {
    	                // Shortcuts
    	                var cipher = this._cipher;
    	                var blockSize = cipher.blockSize;

    	                // Remember this block to use with next block
    	                var thisBlock = words.slice(offset, offset + blockSize);

    	                // Decrypt and XOR
    	                cipher.decryptBlock(words, offset);
    	                xorBlock.call(this, words, offset, blockSize);

    	                // This block becomes the previous block
    	                this._prevBlock = thisBlock;
    	            }
    	        });

    	        function xorBlock(words, offset, blockSize) {
    	            // Shortcut
    	            var iv = this._iv;

    	            // Choose mixing block
    	            if (iv) {
    	                var block = iv;

    	                // Remove IV for subsequent blocks
    	                this._iv = undefined;
    	            } else {
    	                var block = this._prevBlock;
    	            }

    	            // XOR blocks
    	            for (var i = 0; i < blockSize; i++) {
    	                words[offset + i] ^= block[i];
    	            }
    	        }

    	        return CBC;
    	    }());

    	    /**
    	     * Padding namespace.
    	     */
    	    var C_pad = C.pad = {};

    	    /**
    	     * PKCS #5/7 padding strategy.
    	     */
    	    var Pkcs7 = C_pad.Pkcs7 = {
    	        /**
    	         * Pads data using the algorithm defined in PKCS #5/7.
    	         *
    	         * @param {WordArray} data The data to pad.
    	         * @param {number} blockSize The multiple that the data should be padded to.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     CryptoJS.pad.Pkcs7.pad(wordArray, 4);
    	         */
    	        pad: function (data, blockSize) {
    	            // Shortcut
    	            var blockSizeBytes = blockSize * 4;

    	            // Count padding bytes
    	            var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;

    	            // Create padding word
    	            var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes;

    	            // Create padding
    	            var paddingWords = [];
    	            for (var i = 0; i < nPaddingBytes; i += 4) {
    	                paddingWords.push(paddingWord);
    	            }
    	            var padding = WordArray.create(paddingWords, nPaddingBytes);

    	            // Add padding
    	            data.concat(padding);
    	        },

    	        /**
    	         * Unpads data that had been padded using the algorithm defined in PKCS #5/7.
    	         *
    	         * @param {WordArray} data The data to unpad.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     CryptoJS.pad.Pkcs7.unpad(wordArray);
    	         */
    	        unpad: function (data) {
    	            // Get number of padding bytes from last byte
    	            var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;

    	            // Remove padding
    	            data.sigBytes -= nPaddingBytes;
    	        }
    	    };

    	    /**
    	     * Abstract base block cipher template.
    	     *
    	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits)
    	     */
    	    var BlockCipher = C_lib.BlockCipher = Cipher.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {Mode} mode The block mode to use. Default: CBC
    	         * @property {Padding} padding The padding strategy to use. Default: Pkcs7
    	         */
    	        cfg: Cipher.cfg.extend({
    	            mode: CBC,
    	            padding: Pkcs7
    	        }),

    	        reset: function () {
    	            // Reset cipher
    	            Cipher.reset.call(this);

    	            // Shortcuts
    	            var cfg = this.cfg;
    	            var iv = cfg.iv;
    	            var mode = cfg.mode;

    	            // Reset block mode
    	            if (this._xformMode == this._ENC_XFORM_MODE) {
    	                var modeCreator = mode.createEncryptor;
    	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
    	                var modeCreator = mode.createDecryptor;

    	                // Keep at least one block in the buffer for unpadding
    	                this._minBufferSize = 1;
    	            }
    	            this._mode = modeCreator.call(mode, this, iv && iv.words);
    	        },

    	        _doProcessBlock: function (words, offset) {
    	            this._mode.processBlock(words, offset);
    	        },

    	        _doFinalize: function () {
    	            // Shortcut
    	            var padding = this.cfg.padding;

    	            // Finalize
    	            if (this._xformMode == this._ENC_XFORM_MODE) {
    	                // Pad data
    	                padding.pad(this._data, this.blockSize);

    	                // Process final blocks
    	                var finalProcessedBlocks = this._process(!!'flush');
    	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
    	                // Process final blocks
    	                var finalProcessedBlocks = this._process(!!'flush');

    	                // Unpad data
    	                padding.unpad(finalProcessedBlocks);
    	            }

    	            return finalProcessedBlocks;
    	        },

    	        blockSize: 128/32
    	    });

    	    /**
    	     * A collection of cipher parameters.
    	     *
    	     * @property {WordArray} ciphertext The raw ciphertext.
    	     * @property {WordArray} key The key to this ciphertext.
    	     * @property {WordArray} iv The IV used in the ciphering operation.
    	     * @property {WordArray} salt The salt used with a key derivation function.
    	     * @property {Cipher} algorithm The cipher algorithm.
    	     * @property {Mode} mode The block mode used in the ciphering operation.
    	     * @property {Padding} padding The padding scheme used in the ciphering operation.
    	     * @property {number} blockSize The block size of the cipher.
    	     * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string.
    	     */
    	    var CipherParams = C_lib.CipherParams = Base.extend({
    	        /**
    	         * Initializes a newly created cipher params object.
    	         *
    	         * @param {Object} cipherParams An object with any of the possible cipher parameters.
    	         *
    	         * @example
    	         *
    	         *     var cipherParams = CryptoJS.lib.CipherParams.create({
    	         *         ciphertext: ciphertextWordArray,
    	         *         key: keyWordArray,
    	         *         iv: ivWordArray,
    	         *         salt: saltWordArray,
    	         *         algorithm: CryptoJS.algo.AES,
    	         *         mode: CryptoJS.mode.CBC,
    	         *         padding: CryptoJS.pad.PKCS7,
    	         *         blockSize: 4,
    	         *         formatter: CryptoJS.format.OpenSSL
    	         *     });
    	         */
    	        init: function (cipherParams) {
    	            this.mixIn(cipherParams);
    	        },

    	        /**
    	         * Converts this cipher params object to a string.
    	         *
    	         * @param {Format} formatter (Optional) The formatting strategy to use.
    	         *
    	         * @return {string} The stringified cipher params.
    	         *
    	         * @throws Error If neither the formatter nor the default formatter is set.
    	         *
    	         * @example
    	         *
    	         *     var string = cipherParams + '';
    	         *     var string = cipherParams.toString();
    	         *     var string = cipherParams.toString(CryptoJS.format.OpenSSL);
    	         */
    	        toString: function (formatter) {
    	            return (formatter || this.formatter).stringify(this);
    	        }
    	    });

    	    /**
    	     * Format namespace.
    	     */
    	    var C_format = C.format = {};

    	    /**
    	     * OpenSSL formatting strategy.
    	     */
    	    var OpenSSLFormatter = C_format.OpenSSL = {
    	        /**
    	         * Converts a cipher params object to an OpenSSL-compatible string.
    	         *
    	         * @param {CipherParams} cipherParams The cipher params object.
    	         *
    	         * @return {string} The OpenSSL-compatible string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);
    	         */
    	        stringify: function (cipherParams) {
    	            // Shortcuts
    	            var ciphertext = cipherParams.ciphertext;
    	            var salt = cipherParams.salt;

    	            // Format
    	            if (salt) {
    	                var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
    	            } else {
    	                var wordArray = ciphertext;
    	            }

    	            return wordArray.toString(Base64);
    	        },

    	        /**
    	         * Converts an OpenSSL-compatible string to a cipher params object.
    	         *
    	         * @param {string} openSSLStr The OpenSSL-compatible string.
    	         *
    	         * @return {CipherParams} The cipher params object.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);
    	         */
    	        parse: function (openSSLStr) {
    	            // Parse base64
    	            var ciphertext = Base64.parse(openSSLStr);

    	            // Shortcut
    	            var ciphertextWords = ciphertext.words;

    	            // Test for salt
    	            if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) {
    	                // Extract salt
    	                var salt = WordArray.create(ciphertextWords.slice(2, 4));

    	                // Remove salt from ciphertext
    	                ciphertextWords.splice(0, 4);
    	                ciphertext.sigBytes -= 16;
    	            }

    	            return CipherParams.create({ ciphertext: ciphertext, salt: salt });
    	        }
    	    };

    	    /**
    	     * A cipher wrapper that returns ciphertext as a serializable cipher params object.
    	     */
    	    var SerializableCipher = C_lib.SerializableCipher = Base.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL
    	         */
    	        cfg: Base.extend({
    	            format: OpenSSLFormatter
    	        }),

    	        /**
    	         * Encrypts a message.
    	         *
    	         * @param {Cipher} cipher The cipher algorithm to use.
    	         * @param {WordArray|string} message The message to encrypt.
    	         * @param {WordArray} key The key.
    	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
    	         *
    	         * @return {CipherParams} A cipher params object.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);
    	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
    	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });
    	         */
    	        encrypt: function (cipher, message, key, cfg) {
    	            // Apply config defaults
    	            cfg = this.cfg.extend(cfg);

    	            // Encrypt
    	            var encryptor = cipher.createEncryptor(key, cfg);
    	            var ciphertext = encryptor.finalize(message);

    	            // Shortcut
    	            var cipherCfg = encryptor.cfg;

    	            // Create and return serializable cipher params
    	            return CipherParams.create({
    	                ciphertext: ciphertext,
    	                key: key,
    	                iv: cipherCfg.iv,
    	                algorithm: cipher,
    	                mode: cipherCfg.mode,
    	                padding: cipherCfg.padding,
    	                blockSize: cipher.blockSize,
    	                formatter: cfg.format
    	            });
    	        },

    	        /**
    	         * Decrypts serialized ciphertext.
    	         *
    	         * @param {Cipher} cipher The cipher algorithm to use.
    	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
    	         * @param {WordArray} key The key.
    	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
    	         *
    	         * @return {WordArray} The plaintext.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL });
    	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL });
    	         */
    	        decrypt: function (cipher, ciphertext, key, cfg) {
    	            // Apply config defaults
    	            cfg = this.cfg.extend(cfg);

    	            // Convert string to CipherParams
    	            ciphertext = this._parse(ciphertext, cfg.format);

    	            // Decrypt
    	            var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);

    	            return plaintext;
    	        },

    	        /**
    	         * Converts serialized ciphertext to CipherParams,
    	         * else assumed CipherParams already and returns ciphertext unchanged.
    	         *
    	         * @param {CipherParams|string} ciphertext The ciphertext.
    	         * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.
    	         *
    	         * @return {CipherParams} The unserialized ciphertext.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
    	         */
    	        _parse: function (ciphertext, format) {
    	            if (typeof ciphertext == 'string') {
    	                return format.parse(ciphertext, this);
    	            } else {
    	                return ciphertext;
    	            }
    	        }
    	    });

    	    /**
    	     * Key derivation function namespace.
    	     */
    	    var C_kdf = C.kdf = {};

    	    /**
    	     * OpenSSL key derivation function.
    	     */
    	    var OpenSSLKdf = C_kdf.OpenSSL = {
    	        /**
    	         * Derives a key and IV from a password.
    	         *
    	         * @param {string} password The password to derive from.
    	         * @param {number} keySize The size in words of the key to generate.
    	         * @param {number} ivSize The size in words of the IV to generate.
    	         * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
    	         *
    	         * @return {CipherParams} A cipher params object with the key, IV, and salt.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
    	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
    	         */
    	        execute: function (password, keySize, ivSize, salt) {
    	            // Generate random salt
    	            if (!salt) {
    	                salt = WordArray.random(64/8);
    	            }

    	            // Derive key and IV
    	            var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);

    	            // Separate key and IV
    	            var iv = WordArray.create(key.words.slice(keySize), ivSize * 4);
    	            key.sigBytes = keySize * 4;

    	            // Return params
    	            return CipherParams.create({ key: key, iv: iv, salt: salt });
    	        }
    	    };

    	    /**
    	     * A serializable cipher wrapper that derives the key from a password,
    	     * and returns ciphertext as a serializable cipher params object.
    	     */
    	    var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL
    	         */
    	        cfg: SerializableCipher.cfg.extend({
    	            kdf: OpenSSLKdf
    	        }),

    	        /**
    	         * Encrypts a message using a password.
    	         *
    	         * @param {Cipher} cipher The cipher algorithm to use.
    	         * @param {WordArray|string} message The message to encrypt.
    	         * @param {string} password The password.
    	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
    	         *
    	         * @return {CipherParams} A cipher params object.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password');
    	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });
    	         */
    	        encrypt: function (cipher, message, password, cfg) {
    	            // Apply config defaults
    	            cfg = this.cfg.extend(cfg);

    	            // Derive key and other params
    	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize);

    	            // Add IV to config
    	            cfg.iv = derivedParams.iv;

    	            // Encrypt
    	            var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg);

    	            // Mix in derived params
    	            ciphertext.mixIn(derivedParams);

    	            return ciphertext;
    	        },

    	        /**
    	         * Decrypts serialized ciphertext using a password.
    	         *
    	         * @param {Cipher} cipher The cipher algorithm to use.
    	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
    	         * @param {string} password The password.
    	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
    	         *
    	         * @return {WordArray} The plaintext.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL });
    	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL });
    	         */
    	        decrypt: function (cipher, ciphertext, password, cfg) {
    	            // Apply config defaults
    	            cfg = this.cfg.extend(cfg);

    	            // Convert string to CipherParams
    	            ciphertext = this._parse(ciphertext, cfg.format);

    	            // Derive key and other params
    	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt);

    	            // Add IV to config
    	            cfg.iv = derivedParams.iv;

    	            // Decrypt
    	            var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg);

    	            return plaintext;
    	        }
    	    });
    	}());

    }));
    },{"./core":46}],46:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory();
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define([], factory);
    	}
    	else {
    		// Global (browser)
    		root.CryptoJS = factory();
    	}
    }(this, function () {

    	/**
    	 * CryptoJS core components.
    	 */
    	var CryptoJS = CryptoJS || (function (Math, undefined) {
    	    /**
    	     * CryptoJS namespace.
    	     */
    	    var C = {};

    	    /**
    	     * Library namespace.
    	     */
    	    var C_lib = C.lib = {};

    	    /**
    	     * Base object for prototypal inheritance.
    	     */
    	    var Base = C_lib.Base = (function () {
    	        function F() {}

    	        return {
    	            /**
    	             * Creates a new object that inherits from this object.
    	             *
    	             * @param {Object} overrides Properties to copy into the new object.
    	             *
    	             * @return {Object} The new object.
    	             *
    	             * @static
    	             *
    	             * @example
    	             *
    	             *     var MyType = CryptoJS.lib.Base.extend({
    	             *         field: 'value',
    	             *
    	             *         method: function () {
    	             *         }
    	             *     });
    	             */
    	            extend: function (overrides) {
    	                // Spawn
    	                F.prototype = this;
    	                var subtype = new F();

    	                // Augment
    	                if (overrides) {
    	                    subtype.mixIn(overrides);
    	                }

    	                // Create default initializer
    	                if (!subtype.hasOwnProperty('init')) {
    	                    subtype.init = function () {
    	                        subtype.$super.init.apply(this, arguments);
    	                    };
    	                }

    	                // Initializer's prototype is the subtype object
    	                subtype.init.prototype = subtype;

    	                // Reference supertype
    	                subtype.$super = this;

    	                return subtype;
    	            },

    	            /**
    	             * Extends this object and runs the init method.
    	             * Arguments to create() will be passed to init().
    	             *
    	             * @return {Object} The new object.
    	             *
    	             * @static
    	             *
    	             * @example
    	             *
    	             *     var instance = MyType.create();
    	             */
    	            create: function () {
    	                var instance = this.extend();
    	                instance.init.apply(instance, arguments);

    	                return instance;
    	            },

    	            /**
    	             * Initializes a newly created object.
    	             * Override this method to add some logic when your objects are created.
    	             *
    	             * @example
    	             *
    	             *     var MyType = CryptoJS.lib.Base.extend({
    	             *         init: function () {
    	             *             // ...
    	             *         }
    	             *     });
    	             */
    	            init: function () {
    	            },

    	            /**
    	             * Copies properties into this object.
    	             *
    	             * @param {Object} properties The properties to mix in.
    	             *
    	             * @example
    	             *
    	             *     MyType.mixIn({
    	             *         field: 'value'
    	             *     });
    	             */
    	            mixIn: function (properties) {
    	                for (var propertyName in properties) {
    	                    if (properties.hasOwnProperty(propertyName)) {
    	                        this[propertyName] = properties[propertyName];
    	                    }
    	                }

    	                // IE won't copy toString using the loop above
    	                if (properties.hasOwnProperty('toString')) {
    	                    this.toString = properties.toString;
    	                }
    	            },

    	            /**
    	             * Creates a copy of this object.
    	             *
    	             * @return {Object} The clone.
    	             *
    	             * @example
    	             *
    	             *     var clone = instance.clone();
    	             */
    	            clone: function () {
    	                return this.init.prototype.extend(this);
    	            }
    	        };
    	    }());

    	    /**
    	     * An array of 32-bit words.
    	     *
    	     * @property {Array} words The array of 32-bit words.
    	     * @property {number} sigBytes The number of significant bytes in this word array.
    	     */
    	    var WordArray = C_lib.WordArray = Base.extend({
    	        /**
    	         * Initializes a newly created word array.
    	         *
    	         * @param {Array} words (Optional) An array of 32-bit words.
    	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.lib.WordArray.create();
    	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
    	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
    	         */
    	        init: function (words, sigBytes) {
    	            words = this.words = words || [];

    	            if (sigBytes != undefined) {
    	                this.sigBytes = sigBytes;
    	            } else {
    	                this.sigBytes = words.length * 4;
    	            }
    	        },

    	        /**
    	         * Converts this word array to a string.
    	         *
    	         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
    	         *
    	         * @return {string} The stringified word array.
    	         *
    	         * @example
    	         *
    	         *     var string = wordArray + '';
    	         *     var string = wordArray.toString();
    	         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
    	         */
    	        toString: function (encoder) {
    	            return (encoder || Hex).stringify(this);
    	        },

    	        /**
    	         * Concatenates a word array to this word array.
    	         *
    	         * @param {WordArray} wordArray The word array to append.
    	         *
    	         * @return {WordArray} This word array.
    	         *
    	         * @example
    	         *
    	         *     wordArray1.concat(wordArray2);
    	         */
    	        concat: function (wordArray) {
    	            // Shortcuts
    	            var thisWords = this.words;
    	            var thatWords = wordArray.words;
    	            var thisSigBytes = this.sigBytes;
    	            var thatSigBytes = wordArray.sigBytes;

    	            // Clamp excess bits
    	            this.clamp();

    	            // Concat
    	            if (thisSigBytes % 4) {
    	                // Copy one byte at a time
    	                for (var i = 0; i < thatSigBytes; i++) {
    	                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
    	                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
    	                }
    	            } else {
    	                // Copy one word at a time
    	                for (var i = 0; i < thatSigBytes; i += 4) {
    	                    thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
    	                }
    	            }
    	            this.sigBytes += thatSigBytes;

    	            // Chainable
    	            return this;
    	        },

    	        /**
    	         * Removes insignificant bits.
    	         *
    	         * @example
    	         *
    	         *     wordArray.clamp();
    	         */
    	        clamp: function () {
    	            // Shortcuts
    	            var words = this.words;
    	            var sigBytes = this.sigBytes;

    	            // Clamp
    	            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
    	            words.length = Math.ceil(sigBytes / 4);
    	        },

    	        /**
    	         * Creates a copy of this word array.
    	         *
    	         * @return {WordArray} The clone.
    	         *
    	         * @example
    	         *
    	         *     var clone = wordArray.clone();
    	         */
    	        clone: function () {
    	            var clone = Base.clone.call(this);
    	            clone.words = this.words.slice(0);

    	            return clone;
    	        },

    	        /**
    	         * Creates a word array filled with random bytes.
    	         *
    	         * @param {number} nBytes The number of random bytes to generate.
    	         *
    	         * @return {WordArray} The random word array.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.lib.WordArray.random(16);
    	         */
    	        random: function (nBytes) {
    	            var words = [];

    	            var r = (function (m_w) {
    	                var m_w = m_w;
    	                var m_z = 0x3ade68b1;
    	                var mask = 0xffffffff;

    	                return function () {
    	                    m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
    	                    m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
    	                    var result = ((m_z << 0x10) + m_w) & mask;
    	                    result /= 0x100000000;
    	                    result += 0.5;
    	                    return result * (Math.random() > .5 ? 1 : -1);
    	                }
    	            });

    	            for (var i = 0, rcache; i < nBytes; i += 4) {
    	                var _r = r((rcache || Math.random()) * 0x100000000);

    	                rcache = _r() * 0x3ade67b7;
    	                words.push((_r() * 0x100000000) | 0);
    	            }

    	            return new WordArray.init(words, nBytes);
    	        }
    	    });

    	    /**
    	     * Encoder namespace.
    	     */
    	    var C_enc = C.enc = {};

    	    /**
    	     * Hex encoding strategy.
    	     */
    	    var Hex = C_enc.Hex = {
    	        /**
    	         * Converts a word array to a hex string.
    	         *
    	         * @param {WordArray} wordArray The word array.
    	         *
    	         * @return {string} The hex string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
    	         */
    	        stringify: function (wordArray) {
    	            // Shortcuts
    	            var words = wordArray.words;
    	            var sigBytes = wordArray.sigBytes;

    	            // Convert
    	            var hexChars = [];
    	            for (var i = 0; i < sigBytes; i++) {
    	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
    	                hexChars.push((bite >>> 4).toString(16));
    	                hexChars.push((bite & 0x0f).toString(16));
    	            }

    	            return hexChars.join('');
    	        },

    	        /**
    	         * Converts a hex string to a word array.
    	         *
    	         * @param {string} hexStr The hex string.
    	         *
    	         * @return {WordArray} The word array.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
    	         */
    	        parse: function (hexStr) {
    	            // Shortcut
    	            var hexStrLength = hexStr.length;

    	            // Convert
    	            var words = [];
    	            for (var i = 0; i < hexStrLength; i += 2) {
    	                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
    	            }

    	            return new WordArray.init(words, hexStrLength / 2);
    	        }
    	    };

    	    /**
    	     * Latin1 encoding strategy.
    	     */
    	    var Latin1 = C_enc.Latin1 = {
    	        /**
    	         * Converts a word array to a Latin1 string.
    	         *
    	         * @param {WordArray} wordArray The word array.
    	         *
    	         * @return {string} The Latin1 string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
    	         */
    	        stringify: function (wordArray) {
    	            // Shortcuts
    	            var words = wordArray.words;
    	            var sigBytes = wordArray.sigBytes;

    	            // Convert
    	            var latin1Chars = [];
    	            for (var i = 0; i < sigBytes; i++) {
    	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
    	                latin1Chars.push(String.fromCharCode(bite));
    	            }

    	            return latin1Chars.join('');
    	        },

    	        /**
    	         * Converts a Latin1 string to a word array.
    	         *
    	         * @param {string} latin1Str The Latin1 string.
    	         *
    	         * @return {WordArray} The word array.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
    	         */
    	        parse: function (latin1Str) {
    	            // Shortcut
    	            var latin1StrLength = latin1Str.length;

    	            // Convert
    	            var words = [];
    	            for (var i = 0; i < latin1StrLength; i++) {
    	                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
    	            }

    	            return new WordArray.init(words, latin1StrLength);
    	        }
    	    };

    	    /**
    	     * UTF-8 encoding strategy.
    	     */
    	    var Utf8 = C_enc.Utf8 = {
    	        /**
    	         * Converts a word array to a UTF-8 string.
    	         *
    	         * @param {WordArray} wordArray The word array.
    	         *
    	         * @return {string} The UTF-8 string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
    	         */
    	        stringify: function (wordArray) {
    	            try {
    	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
    	            } catch (e) {
    	                throw new Error('Malformed UTF-8 data');
    	            }
    	        },

    	        /**
    	         * Converts a UTF-8 string to a word array.
    	         *
    	         * @param {string} utf8Str The UTF-8 string.
    	         *
    	         * @return {WordArray} The word array.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
    	         */
    	        parse: function (utf8Str) {
    	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
    	        }
    	    };

    	    /**
    	     * Abstract buffered block algorithm template.
    	     *
    	     * The property blockSize must be implemented in a concrete subtype.
    	     *
    	     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
    	     */
    	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
    	        /**
    	         * Resets this block algorithm's data buffer to its initial state.
    	         *
    	         * @example
    	         *
    	         *     bufferedBlockAlgorithm.reset();
    	         */
    	        reset: function () {
    	            // Initial values
    	            this._data = new WordArray.init();
    	            this._nDataBytes = 0;
    	        },

    	        /**
    	         * Adds new data to this block algorithm's buffer.
    	         *
    	         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
    	         *
    	         * @example
    	         *
    	         *     bufferedBlockAlgorithm._append('data');
    	         *     bufferedBlockAlgorithm._append(wordArray);
    	         */
    	        _append: function (data) {
    	            // Convert string to WordArray, else assume WordArray already
    	            if (typeof data == 'string') {
    	                data = Utf8.parse(data);
    	            }

    	            // Append
    	            this._data.concat(data);
    	            this._nDataBytes += data.sigBytes;
    	        },

    	        /**
    	         * Processes available data blocks.
    	         *
    	         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
    	         *
    	         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
    	         *
    	         * @return {WordArray} The processed data.
    	         *
    	         * @example
    	         *
    	         *     var processedData = bufferedBlockAlgorithm._process();
    	         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
    	         */
    	        _process: function (doFlush) {
    	            // Shortcuts
    	            var data = this._data;
    	            var dataWords = data.words;
    	            var dataSigBytes = data.sigBytes;
    	            var blockSize = this.blockSize;
    	            var blockSizeBytes = blockSize * 4;

    	            // Count blocks ready
    	            var nBlocksReady = dataSigBytes / blockSizeBytes;
    	            if (doFlush) {
    	                // Round up to include partial blocks
    	                nBlocksReady = Math.ceil(nBlocksReady);
    	            } else {
    	                // Round down to include only full blocks,
    	                // less the number of blocks that must remain in the buffer
    	                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
    	            }

    	            // Count words ready
    	            var nWordsReady = nBlocksReady * blockSize;

    	            // Count bytes ready
    	            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);

    	            // Process blocks
    	            if (nWordsReady) {
    	                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
    	                    // Perform concrete-algorithm logic
    	                    this._doProcessBlock(dataWords, offset);
    	                }

    	                // Remove processed words
    	                var processedWords = dataWords.splice(0, nWordsReady);
    	                data.sigBytes -= nBytesReady;
    	            }

    	            // Return processed words
    	            return new WordArray.init(processedWords, nBytesReady);
    	        },

    	        /**
    	         * Creates a copy of this object.
    	         *
    	         * @return {Object} The clone.
    	         *
    	         * @example
    	         *
    	         *     var clone = bufferedBlockAlgorithm.clone();
    	         */
    	        clone: function () {
    	            var clone = Base.clone.call(this);
    	            clone._data = this._data.clone();

    	            return clone;
    	        },

    	        _minBufferSize: 0
    	    });

    	    /**
    	     * Abstract hasher template.
    	     *
    	     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
    	     */
    	    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
    	        /**
    	         * Configuration options.
    	         */
    	        cfg: Base.extend(),

    	        /**
    	         * Initializes a newly created hasher.
    	         *
    	         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
    	         *
    	         * @example
    	         *
    	         *     var hasher = CryptoJS.algo.SHA256.create();
    	         */
    	        init: function (cfg) {
    	            // Apply config defaults
    	            this.cfg = this.cfg.extend(cfg);

    	            // Set initial values
    	            this.reset();
    	        },

    	        /**
    	         * Resets this hasher to its initial state.
    	         *
    	         * @example
    	         *
    	         *     hasher.reset();
    	         */
    	        reset: function () {
    	            // Reset data buffer
    	            BufferedBlockAlgorithm.reset.call(this);

    	            // Perform concrete-hasher logic
    	            this._doReset();
    	        },

    	        /**
    	         * Updates this hasher with a message.
    	         *
    	         * @param {WordArray|string} messageUpdate The message to append.
    	         *
    	         * @return {Hasher} This hasher.
    	         *
    	         * @example
    	         *
    	         *     hasher.update('message');
    	         *     hasher.update(wordArray);
    	         */
    	        update: function (messageUpdate) {
    	            // Append
    	            this._append(messageUpdate);

    	            // Update the hash
    	            this._process();

    	            // Chainable
    	            return this;
    	        },

    	        /**
    	         * Finalizes the hash computation.
    	         * Note that the finalize operation is effectively a destructive, read-once operation.
    	         *
    	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
    	         *
    	         * @return {WordArray} The hash.
    	         *
    	         * @example
    	         *
    	         *     var hash = hasher.finalize();
    	         *     var hash = hasher.finalize('message');
    	         *     var hash = hasher.finalize(wordArray);
    	         */
    	        finalize: function (messageUpdate) {
    	            // Final message update
    	            Eif (messageUpdate) {
    	                this._append(messageUpdate);
    	            }

    	            // Perform concrete-hasher logic
    	            var hash = this._doFinalize();

    	            return hash;
    	        },

    	        blockSize: 512/32,

    	        /**
    	         * Creates a shortcut function to a hasher's object interface.
    	         *
    	         * @param {Hasher} hasher The hasher to create a helper for.
    	         *
    	         * @return {Function} The shortcut function.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
    	         */
    	        _createHelper: function (hasher) {
    	            return function (message, cfg) {
    	                return new hasher.init(cfg).finalize(message);
    	            };
    	        },

    	        /**
    	         * Creates a shortcut function to the HMAC's object interface.
    	         *
    	         * @param {Hasher} hasher The hasher to use in this HMAC helper.
    	         *
    	         * @return {Function} The shortcut function.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
    	         */
    	        _createHmacHelper: function (hasher) {
    	            return function (message, key) {
    	                return new C_algo.HMAC.init(hasher, key).finalize(message);
    	            };
    	        }
    	    });

    	    /**
    	     * Algorithm namespace.
    	     */
    	    var C_algo = C.algo = {};

    	    return C;
    	}(Math));

    	return CryptoJS;

    }));
    },{}],47:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var C_enc = C.enc;

    	    /**
    	     * Base64 encoding strategy.
    	     */
    	    var Base64 = C_enc.Base64 = {
    	        /**
    	         * Converts a word array to a Base64 string.
    	         *
    	         * @param {WordArray} wordArray The word array.
    	         *
    	         * @return {string} The Base64 string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var base64String = CryptoJS.enc.Base64.stringify(wordArray);
    	         */
    	        stringify: function (wordArray) {
    	            // Shortcuts
    	            var words = wordArray.words;
    	            var sigBytes = wordArray.sigBytes;
    	            var map = this._map;

    	            // Clamp excess bits
    	            wordArray.clamp();

    	            // Convert
    	            var base64Chars = [];
    	            for (var i = 0; i < sigBytes; i += 3) {
    	                var byte1 = (words[i >>> 2]       >>> (24 - (i % 4) * 8))       & 0xff;
    	                var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;
    	                var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;

    	                var triplet = (byte1 << 16) | (byte2 << 8) | byte3;

    	                for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {
    	                    base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));
    	                }
    	            }

    	            // Add padding
    	            var paddingChar = map.charAt(64);
    	            Eif (paddingChar) {
    	                while (base64Chars.length % 4) {
    	                    base64Chars.push(paddingChar);
    	                }
    	            }

    	            return base64Chars.join('');
    	        },

    	        /**
    	         * Converts a Base64 string to a word array.
    	         *
    	         * @param {string} base64Str The Base64 string.
    	         *
    	         * @return {WordArray} The word array.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.enc.Base64.parse(base64String);
    	         */
    	        parse: function (base64Str) {
    	            // Shortcuts
    	            var base64StrLength = base64Str.length;
    	            var map = this._map;

    	            // Ignore padding
    	            var paddingChar = map.charAt(64);
    	            Eif (paddingChar) {
    	                var paddingIndex = base64Str.indexOf(paddingChar);
    	                Eif (paddingIndex != -1) {
    	                    base64StrLength = paddingIndex;
    	                }
    	            }

    	            // Convert
    	            var words = [];
    	            var nBytes = 0;
    	            for (var i = 0; i < base64StrLength; i++) {
    	                if (i % 4) {
    	                    var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2);
    	                    var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2);
    	                    words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);
    	                    nBytes++;
    	                }
    	            }

    	            return WordArray.create(words, nBytes);
    	        },

    	        _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
    	    };
    	}());

    	return CryptoJS.enc.Base64;

    }));
    },{"./core":46}],48:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var C_enc = C.enc;

    	    /**
    	     * UTF-16 BE encoding strategy.
    	     */
    	    var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = {
    	        /**
    	         * Converts a word array to a UTF-16 BE string.
    	         *
    	         * @param {WordArray} wordArray The word array.
    	         *
    	         * @return {string} The UTF-16 BE string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var utf16String = CryptoJS.enc.Utf16.stringify(wordArray);
    	         */
    	        stringify: function (wordArray) {
    	            // Shortcuts
    	            var words = wordArray.words;
    	            var sigBytes = wordArray.sigBytes;

    	            // Convert
    	            var utf16Chars = [];
    	            for (var i = 0; i < sigBytes; i += 2) {
    	                var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff;
    	                utf16Chars.push(String.fromCharCode(codePoint));
    	            }

    	            return utf16Chars.join('');
    	        },

    	        /**
    	         * Converts a UTF-16 BE string to a word array.
    	         *
    	         * @param {string} utf16Str The UTF-16 BE string.
    	         *
    	         * @return {WordArray} The word array.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.enc.Utf16.parse(utf16String);
    	         */
    	        parse: function (utf16Str) {
    	            // Shortcut
    	            var utf16StrLength = utf16Str.length;

    	            // Convert
    	            var words = [];
    	            for (var i = 0; i < utf16StrLength; i++) {
    	                words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16);
    	            }

    	            return WordArray.create(words, utf16StrLength * 2);
    	        }
    	    };

    	    /**
    	     * UTF-16 LE encoding strategy.
    	     */
    	    C_enc.Utf16LE = {
    	        /**
    	         * Converts a word array to a UTF-16 LE string.
    	         *
    	         * @param {WordArray} wordArray The word array.
    	         *
    	         * @return {string} The UTF-16 LE string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray);
    	         */
    	        stringify: function (wordArray) {
    	            // Shortcuts
    	            var words = wordArray.words;
    	            var sigBytes = wordArray.sigBytes;

    	            // Convert
    	            var utf16Chars = [];
    	            for (var i = 0; i < sigBytes; i += 2) {
    	                var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff);
    	                utf16Chars.push(String.fromCharCode(codePoint));
    	            }

    	            return utf16Chars.join('');
    	        },

    	        /**
    	         * Converts a UTF-16 LE string to a word array.
    	         *
    	         * @param {string} utf16Str The UTF-16 LE string.
    	         *
    	         * @return {WordArray} The word array.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str);
    	         */
    	        parse: function (utf16Str) {
    	            // Shortcut
    	            var utf16StrLength = utf16Str.length;

    	            // Convert
    	            var words = [];
    	            for (var i = 0; i < utf16StrLength; i++) {
    	                words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16));
    	            }

    	            return WordArray.create(words, utf16StrLength * 2);
    	        }
    	    };

    	    function swapEndian(word) {
    	        return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff);
    	    }
    	}());

    	return CryptoJS.enc.Utf16;

    }));
    },{"./core":46}],49:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./sha1"), _dereq_("./hmac"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./sha1", "./hmac"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var Base = C_lib.Base;
    	    var WordArray = C_lib.WordArray;
    	    var C_algo = C.algo;
    	    var MD5 = C_algo.MD5;

    	    /**
    	     * This key derivation function is meant to conform with EVP_BytesToKey.
    	     * www.openssl.org/docs/crypto/EVP_BytesToKey.html
    	     */
    	    var EvpKDF = C_algo.EvpKDF = Base.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
    	         * @property {Hasher} hasher The hash algorithm to use. Default: MD5
    	         * @property {number} iterations The number of iterations to perform. Default: 1
    	         */
    	        cfg: Base.extend({
    	            keySize: 128/32,
    	            hasher: MD5,
    	            iterations: 1
    	        }),

    	        /**
    	         * Initializes a newly created key derivation function.
    	         *
    	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
    	         *
    	         * @example
    	         *
    	         *     var kdf = CryptoJS.algo.EvpKDF.create();
    	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 });
    	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 });
    	         */
    	        init: function (cfg) {
    	            this.cfg = this.cfg.extend(cfg);
    	        },

    	        /**
    	         * Derives a key from a password.
    	         *
    	         * @param {WordArray|string} password The password.
    	         * @param {WordArray|string} salt A salt.
    	         *
    	         * @return {WordArray} The derived key.
    	         *
    	         * @example
    	         *
    	         *     var key = kdf.compute(password, salt);
    	         */
    	        compute: function (password, salt) {
    	            // Shortcut
    	            var cfg = this.cfg;

    	            // Init hasher
    	            var hasher = cfg.hasher.create();

    	            // Initial values
    	            var derivedKey = WordArray.create();

    	            // Shortcuts
    	            var derivedKeyWords = derivedKey.words;
    	            var keySize = cfg.keySize;
    	            var iterations = cfg.iterations;

    	            // Generate key
    	            while (derivedKeyWords.length < keySize) {
    	                if (block) {
    	                    hasher.update(block);
    	                }
    	                var block = hasher.update(password).finalize(salt);
    	                hasher.reset();

    	                // Iterations
    	                for (var i = 1; i < iterations; i++) {
    	                    block = hasher.finalize(block);
    	                    hasher.reset();
    	                }

    	                derivedKey.concat(block);
    	            }
    	            derivedKey.sigBytes = keySize * 4;

    	            return derivedKey;
    	        }
    	    });

    	    /**
    	     * Derives a key from a password.
    	     *
    	     * @param {WordArray|string} password The password.
    	     * @param {WordArray|string} salt A salt.
    	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
    	     *
    	     * @return {WordArray} The derived key.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var key = CryptoJS.EvpKDF(password, salt);
    	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 });
    	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 });
    	     */
    	    C.EvpKDF = function (password, salt, cfg) {
    	        return EvpKDF.create(cfg).compute(password, salt);
    	    };
    	}());

    	return CryptoJS.EvpKDF;

    }));
    },{"./core":46,"./hmac":51,"./sha1":70}],50:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function (undefined) {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var CipherParams = C_lib.CipherParams;
    	    var C_enc = C.enc;
    	    var Hex = C_enc.Hex;
    	    var C_format = C.format;

    	    var HexFormatter = C_format.Hex = {
    	        /**
    	         * Converts the ciphertext of a cipher params object to a hexadecimally encoded string.
    	         *
    	         * @param {CipherParams} cipherParams The cipher params object.
    	         *
    	         * @return {string} The hexadecimally encoded string.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var hexString = CryptoJS.format.Hex.stringify(cipherParams);
    	         */
    	        stringify: function (cipherParams) {
    	            return cipherParams.ciphertext.toString(Hex);
    	        },

    	        /**
    	         * Converts a hexadecimally encoded ciphertext string to a cipher params object.
    	         *
    	         * @param {string} input The hexadecimally encoded string.
    	         *
    	         * @return {CipherParams} The cipher params object.
    	         *
    	         * @static
    	         *
    	         * @example
    	         *
    	         *     var cipherParams = CryptoJS.format.Hex.parse(hexString);
    	         */
    	        parse: function (input) {
    	            var ciphertext = Hex.parse(input);
    	            return CipherParams.create({ ciphertext: ciphertext });
    	        }
    	    };
    	}());

    	return CryptoJS.format.Hex;

    }));
    },{"./cipher-core":45,"./core":46}],51:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var Base = C_lib.Base;
    	    var C_enc = C.enc;
    	    var Utf8 = C_enc.Utf8;
    	    var C_algo = C.algo;

    	    /**
    	     * HMAC algorithm.
    	     */
    	    var HMAC = C_algo.HMAC = Base.extend({
    	        /**
    	         * Initializes a newly created HMAC.
    	         *
    	         * @param {Hasher} hasher The hash algorithm to use.
    	         * @param {WordArray|string} key The secret key.
    	         *
    	         * @example
    	         *
    	         *     var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
    	         */
    	        init: function (hasher, key) {
    	            // Init hasher
    	            hasher = this._hasher = new hasher.init();

    	            // Convert string to WordArray, else assume WordArray already
    	            if (typeof key == 'string') {
    	                key = Utf8.parse(key);
    	            }

    	            // Shortcuts
    	            var hasherBlockSize = hasher.blockSize;
    	            var hasherBlockSizeBytes = hasherBlockSize * 4;

    	            // Allow arbitrary length keys
    	            if (key.sigBytes > hasherBlockSizeBytes) {
    	                key = hasher.finalize(key);
    	            }

    	            // Clamp excess bits
    	            key.clamp();

    	            // Clone key for inner and outer pads
    	            var oKey = this._oKey = key.clone();
    	            var iKey = this._iKey = key.clone();

    	            // Shortcuts
    	            var oKeyWords = oKey.words;
    	            var iKeyWords = iKey.words;

    	            // XOR keys with pad constants
    	            for (var i = 0; i < hasherBlockSize; i++) {
    	                oKeyWords[i] ^= 0x5c5c5c5c;
    	                iKeyWords[i] ^= 0x36363636;
    	            }
    	            oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;

    	            // Set initial values
    	            this.reset();
    	        },

    	        /**
    	         * Resets this HMAC to its initial state.
    	         *
    	         * @example
    	         *
    	         *     hmacHasher.reset();
    	         */
    	        reset: function () {
    	            // Shortcut
    	            var hasher = this._hasher;

    	            // Reset
    	            hasher.reset();
    	            hasher.update(this._iKey);
    	        },

    	        /**
    	         * Updates this HMAC with a message.
    	         *
    	         * @param {WordArray|string} messageUpdate The message to append.
    	         *
    	         * @return {HMAC} This HMAC instance.
    	         *
    	         * @example
    	         *
    	         *     hmacHasher.update('message');
    	         *     hmacHasher.update(wordArray);
    	         */
    	        update: function (messageUpdate) {
    	            this._hasher.update(messageUpdate);

    	            // Chainable
    	            return this;
    	        },

    	        /**
    	         * Finalizes the HMAC computation.
    	         * Note that the finalize operation is effectively a destructive, read-once operation.
    	         *
    	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
    	         *
    	         * @return {WordArray} The HMAC.
    	         *
    	         * @example
    	         *
    	         *     var hmac = hmacHasher.finalize();
    	         *     var hmac = hmacHasher.finalize('message');
    	         *     var hmac = hmacHasher.finalize(wordArray);
    	         */
    	        finalize: function (messageUpdate) {
    	            // Shortcut
    	            var hasher = this._hasher;

    	            // Compute HMAC
    	            var innerHash = hasher.finalize(messageUpdate);
    	            hasher.reset();
    	            var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));

    	            return hmac;
    	        }
    	    });
    	}());

    }));
    },{"./core":46}],52:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./x64-core"), _dereq_("./lib-typedarrays"), _dereq_("./enc-utf16"), _dereq_("./enc-base64"), _dereq_("./md5"), _dereq_("./sha1"), _dereq_("./sha256"), _dereq_("./sha224"), _dereq_("./sha512"), _dereq_("./sha384"), _dereq_("./sha3"), _dereq_("./ripemd160"), _dereq_("./hmac"), _dereq_("./pbkdf2"), _dereq_("./evpkdf"), _dereq_("./cipher-core"), _dereq_("./mode-cfb"), _dereq_("./mode-ctr"), _dereq_("./mode-ctr-gladman"), _dereq_("./mode-ofb"), _dereq_("./mode-ecb"), _dereq_("./pad-ansix923"), _dereq_("./pad-iso10126"), _dereq_("./pad-iso97971"), _dereq_("./pad-zeropadding"), _dereq_("./pad-nopadding"), _dereq_("./format-hex"), _dereq_("./aes"), _dereq_("./tripledes"), _dereq_("./rc4"), _dereq_("./rabbit"), _dereq_("./rabbit-legacy"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./x64-core", "./lib-typedarrays", "./enc-utf16", "./enc-base64", "./md5", "./sha1", "./sha256", "./sha224", "./sha512", "./sha384", "./sha3", "./ripemd160", "./hmac", "./pbkdf2", "./evpkdf", "./cipher-core", "./mode-cfb", "./mode-ctr", "./mode-ctr-gladman", "./mode-ofb", "./mode-ecb", "./pad-ansix923", "./pad-iso10126", "./pad-iso97971", "./pad-zeropadding", "./pad-nopadding", "./format-hex", "./aes", "./tripledes", "./rc4", "./rabbit", "./rabbit-legacy"], factory);
    	}
    	else {
    		// Global (browser)
    		root.CryptoJS = factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	return CryptoJS;

    }));
    },{"./aes":44,"./cipher-core":45,"./core":46,"./enc-base64":47,"./enc-utf16":48,"./evpkdf":49,"./format-hex":50,"./hmac":51,"./lib-typedarrays":53,"./md5":54,"./mode-cfb":55,"./mode-ctr":57,"./mode-ctr-gladman":56,"./mode-ecb":58,"./mode-ofb":59,"./pad-ansix923":60,"./pad-iso10126":61,"./pad-iso97971":62,"./pad-nopadding":63,"./pad-zeropadding":64,"./pbkdf2":65,"./rabbit":67,"./rabbit-legacy":66,"./rc4":68,"./ripemd160":69,"./sha1":70,"./sha224":71,"./sha256":72,"./sha3":73,"./sha384":74,"./sha512":75,"./tripledes":76,"./x64-core":77}],53:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Check if typed arrays are supported
    	    Eif (typeof ArrayBuffer != 'function') {
    	        return;
    	    }

    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;

    	    // Reference original init
    	    var superInit = WordArray.init;

    	    // Augment WordArray.init to handle typed arrays
    	    var subInit = WordArray.init = function (typedArray) {
    	        // Convert buffers to uint8
    	        if (typedArray instanceof ArrayBuffer) {
    	            typedArray = new Uint8Array(typedArray);
    	        }

    	        // Convert other array views to uint8
    	        if (
    	            typedArray instanceof Int8Array ||
    	            (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) ||
    	            typedArray instanceof Int16Array ||
    	            typedArray instanceof Uint16Array ||
    	            typedArray instanceof Int32Array ||
    	            typedArray instanceof Uint32Array ||
    	            typedArray instanceof Float32Array ||
    	            typedArray instanceof Float64Array
    	        ) {
    	            typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);
    	        }

    	        // Handle Uint8Array
    	        if (typedArray instanceof Uint8Array) {
    	            // Shortcut
    	            var typedArrayByteLength = typedArray.byteLength;

    	            // Extract bytes
    	            var words = [];
    	            for (var i = 0; i < typedArrayByteLength; i++) {
    	                words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);
    	            }

    	            // Initialize this word array
    	            superInit.call(this, words, typedArrayByteLength);
    	        } else {
    	            // Else call normal init
    	            superInit.apply(this, arguments);
    	        }
    	    };

    	    subInit.prototype = WordArray;
    	}());

    	return CryptoJS.lib.WordArray;

    }));
    },{"./core":46}],54:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function (Math) {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var Hasher = C_lib.Hasher;
    	    var C_algo = C.algo;

    	    // Constants table
    	    var T = [];

    	    // Compute constants
    	    (function () {
    	        for (var i = 0; i < 64; i++) {
    	            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
    	        }
    	    }());

    	    /**
    	     * MD5 hash algorithm.
    	     */
    	    var MD5 = C_algo.MD5 = Hasher.extend({
    	        _doReset: function () {
    	            this._hash = new WordArray.init([
    	                0x67452301, 0xefcdab89,
    	                0x98badcfe, 0x10325476
    	            ]);
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            // Swap endian
    	            for (var i = 0; i < 16; i++) {
    	                // Shortcuts
    	                var offset_i = offset + i;
    	                var M_offset_i = M[offset_i];

    	                M[offset_i] = (
    	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
    	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
    	                );
    	            }

    	            // Shortcuts
    	            var H = this._hash.words;

    	            var M_offset_0  = M[offset + 0];
    	            var M_offset_1  = M[offset + 1];
    	            var M_offset_2  = M[offset + 2];
    	            var M_offset_3  = M[offset + 3];
    	            var M_offset_4  = M[offset + 4];
    	            var M_offset_5  = M[offset + 5];
    	            var M_offset_6  = M[offset + 6];
    	            var M_offset_7  = M[offset + 7];
    	            var M_offset_8  = M[offset + 8];
    	            var M_offset_9  = M[offset + 9];
    	            var M_offset_10 = M[offset + 10];
    	            var M_offset_11 = M[offset + 11];
    	            var M_offset_12 = M[offset + 12];
    	            var M_offset_13 = M[offset + 13];
    	            var M_offset_14 = M[offset + 14];
    	            var M_offset_15 = M[offset + 15];

    	            // Working varialbes
    	            var a = H[0];
    	            var b = H[1];
    	            var c = H[2];
    	            var d = H[3];

    	            // Computation
    	            a = FF(a, b, c, d, M_offset_0,  7,  T[0]);
    	            d = FF(d, a, b, c, M_offset_1,  12, T[1]);
    	            c = FF(c, d, a, b, M_offset_2,  17, T[2]);
    	            b = FF(b, c, d, a, M_offset_3,  22, T[3]);
    	            a = FF(a, b, c, d, M_offset_4,  7,  T[4]);
    	            d = FF(d, a, b, c, M_offset_5,  12, T[5]);
    	            c = FF(c, d, a, b, M_offset_6,  17, T[6]);
    	            b = FF(b, c, d, a, M_offset_7,  22, T[7]);
    	            a = FF(a, b, c, d, M_offset_8,  7,  T[8]);
    	            d = FF(d, a, b, c, M_offset_9,  12, T[9]);
    	            c = FF(c, d, a, b, M_offset_10, 17, T[10]);
    	            b = FF(b, c, d, a, M_offset_11, 22, T[11]);
    	            a = FF(a, b, c, d, M_offset_12, 7,  T[12]);
    	            d = FF(d, a, b, c, M_offset_13, 12, T[13]);
    	            c = FF(c, d, a, b, M_offset_14, 17, T[14]);
    	            b = FF(b, c, d, a, M_offset_15, 22, T[15]);

    	            a = GG(a, b, c, d, M_offset_1,  5,  T[16]);
    	            d = GG(d, a, b, c, M_offset_6,  9,  T[17]);
    	            c = GG(c, d, a, b, M_offset_11, 14, T[18]);
    	            b = GG(b, c, d, a, M_offset_0,  20, T[19]);
    	            a = GG(a, b, c, d, M_offset_5,  5,  T[20]);
    	            d = GG(d, a, b, c, M_offset_10, 9,  T[21]);
    	            c = GG(c, d, a, b, M_offset_15, 14, T[22]);
    	            b = GG(b, c, d, a, M_offset_4,  20, T[23]);
    	            a = GG(a, b, c, d, M_offset_9,  5,  T[24]);
    	            d = GG(d, a, b, c, M_offset_14, 9,  T[25]);
    	            c = GG(c, d, a, b, M_offset_3,  14, T[26]);
    	            b = GG(b, c, d, a, M_offset_8,  20, T[27]);
    	            a = GG(a, b, c, d, M_offset_13, 5,  T[28]);
    	            d = GG(d, a, b, c, M_offset_2,  9,  T[29]);
    	            c = GG(c, d, a, b, M_offset_7,  14, T[30]);
    	            b = GG(b, c, d, a, M_offset_12, 20, T[31]);

    	            a = HH(a, b, c, d, M_offset_5,  4,  T[32]);
    	            d = HH(d, a, b, c, M_offset_8,  11, T[33]);
    	            c = HH(c, d, a, b, M_offset_11, 16, T[34]);
    	            b = HH(b, c, d, a, M_offset_14, 23, T[35]);
    	            a = HH(a, b, c, d, M_offset_1,  4,  T[36]);
    	            d = HH(d, a, b, c, M_offset_4,  11, T[37]);
    	            c = HH(c, d, a, b, M_offset_7,  16, T[38]);
    	            b = HH(b, c, d, a, M_offset_10, 23, T[39]);
    	            a = HH(a, b, c, d, M_offset_13, 4,  T[40]);
    	            d = HH(d, a, b, c, M_offset_0,  11, T[41]);
    	            c = HH(c, d, a, b, M_offset_3,  16, T[42]);
    	            b = HH(b, c, d, a, M_offset_6,  23, T[43]);
    	            a = HH(a, b, c, d, M_offset_9,  4,  T[44]);
    	            d = HH(d, a, b, c, M_offset_12, 11, T[45]);
    	            c = HH(c, d, a, b, M_offset_15, 16, T[46]);
    	            b = HH(b, c, d, a, M_offset_2,  23, T[47]);

    	            a = II(a, b, c, d, M_offset_0,  6,  T[48]);
    	            d = II(d, a, b, c, M_offset_7,  10, T[49]);
    	            c = II(c, d, a, b, M_offset_14, 15, T[50]);
    	            b = II(b, c, d, a, M_offset_5,  21, T[51]);
    	            a = II(a, b, c, d, M_offset_12, 6,  T[52]);
    	            d = II(d, a, b, c, M_offset_3,  10, T[53]);
    	            c = II(c, d, a, b, M_offset_10, 15, T[54]);
    	            b = II(b, c, d, a, M_offset_1,  21, T[55]);
    	            a = II(a, b, c, d, M_offset_8,  6,  T[56]);
    	            d = II(d, a, b, c, M_offset_15, 10, T[57]);
    	            c = II(c, d, a, b, M_offset_6,  15, T[58]);
    	            b = II(b, c, d, a, M_offset_13, 21, T[59]);
    	            a = II(a, b, c, d, M_offset_4,  6,  T[60]);
    	            d = II(d, a, b, c, M_offset_11, 10, T[61]);
    	            c = II(c, d, a, b, M_offset_2,  15, T[62]);
    	            b = II(b, c, d, a, M_offset_9,  21, T[63]);

    	            // Intermediate hash value
    	            H[0] = (H[0] + a) | 0;
    	            H[1] = (H[1] + b) | 0;
    	            H[2] = (H[2] + c) | 0;
    	            H[3] = (H[3] + d) | 0;
    	        },

    	        _doFinalize: function () {
    	            // Shortcuts
    	            var data = this._data;
    	            var dataWords = data.words;

    	            var nBitsTotal = this._nDataBytes * 8;
    	            var nBitsLeft = data.sigBytes * 8;

    	            // Add padding
    	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);

    	            var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
    	            var nBitsTotalL = nBitsTotal;
    	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
    	                (((nBitsTotalH << 8)  | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
    	                (((nBitsTotalH << 24) | (nBitsTotalH >>> 8))  & 0xff00ff00)
    	            );
    	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
    	                (((nBitsTotalL << 8)  | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
    	                (((nBitsTotalL << 24) | (nBitsTotalL >>> 8))  & 0xff00ff00)
    	            );

    	            data.sigBytes = (dataWords.length + 1) * 4;

    	            // Hash final blocks
    	            this._process();

    	            // Shortcuts
    	            var hash = this._hash;
    	            var H = hash.words;

    	            // Swap endian
    	            for (var i = 0; i < 4; i++) {
    	                // Shortcut
    	                var H_i = H[i];

    	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
    	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
    	            }

    	            // Return final computed hash
    	            return hash;
    	        },

    	        clone: function () {
    	            var clone = Hasher.clone.call(this);
    	            clone._hash = this._hash.clone();

    	            return clone;
    	        }
    	    });

    	    function FF(a, b, c, d, x, s, t) {
    	        var n = a + ((b & c) | (~b & d)) + x + t;
    	        return ((n << s) | (n >>> (32 - s))) + b;
    	    }

    	    function GG(a, b, c, d, x, s, t) {
    	        var n = a + ((b & d) | (c & ~d)) + x + t;
    	        return ((n << s) | (n >>> (32 - s))) + b;
    	    }

    	    function HH(a, b, c, d, x, s, t) {
    	        var n = a + (b ^ c ^ d) + x + t;
    	        return ((n << s) | (n >>> (32 - s))) + b;
    	    }

    	    function II(a, b, c, d, x, s, t) {
    	        var n = a + (c ^ (b | ~d)) + x + t;
    	        return ((n << s) | (n >>> (32 - s))) + b;
    	    }

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.MD5('message');
    	     *     var hash = CryptoJS.MD5(wordArray);
    	     */
    	    C.MD5 = Hasher._createHelper(MD5);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacMD5(message, key);
    	     */
    	    C.HmacMD5 = Hasher._createHmacHelper(MD5);
    	}(Math));

    	return CryptoJS.MD5;

    }));
    },{"./core":46}],55:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * Cipher Feedback block mode.
    	 */
    	CryptoJS.mode.CFB = (function () {
    	    var CFB = CryptoJS.lib.BlockCipherMode.extend();

    	    CFB.Encryptor = CFB.extend({
    	        processBlock: function (words, offset) {
    	            // Shortcuts
    	            var cipher = this._cipher;
    	            var blockSize = cipher.blockSize;

    	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);

    	            // Remember this block to use with next block
    	            this._prevBlock = words.slice(offset, offset + blockSize);
    	        }
    	    });

    	    CFB.Decryptor = CFB.extend({
    	        processBlock: function (words, offset) {
    	            // Shortcuts
    	            var cipher = this._cipher;
    	            var blockSize = cipher.blockSize;

    	            // Remember this block to use with next block
    	            var thisBlock = words.slice(offset, offset + blockSize);

    	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);

    	            // This block becomes the previous block
    	            this._prevBlock = thisBlock;
    	        }
    	    });

    	    function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) {
    	        // Shortcut
    	        var iv = this._iv;

    	        // Generate keystream
    	        if (iv) {
    	            var keystream = iv.slice(0);

    	            // Remove IV for subsequent blocks
    	            this._iv = undefined;
    	        } else {
    	            var keystream = this._prevBlock;
    	        }
    	        cipher.encryptBlock(keystream, 0);

    	        // Encrypt
    	        for (var i = 0; i < blockSize; i++) {
    	            words[offset + i] ^= keystream[i];
    	        }
    	    }

    	    return CFB;
    	}());

    	return CryptoJS.mode.CFB;

    }));
    },{"./cipher-core":45,"./core":46}],56:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/** @preserve
    	 * Counter block mode compatible with  Dr Brian Gladman fileenc.c
    	 * derived from CryptoJS.mode.CTR
    	 * Jan Hruby jhruby.web@gmail.com
    	 */
    	CryptoJS.mode.CTRGladman = (function () {
    	    var CTRGladman = CryptoJS.lib.BlockCipherMode.extend();

    		function incWord(word)
    		{
    			if (((word >> 24) & 0xff) === 0xff) { //overflow
    			var b1 = (word >> 16)&0xff;
    			var b2 = (word >> 8)&0xff;
    			var b3 = word & 0xff;

    			if (b1 === 0xff) // overflow b1
    			{
    			b1 = 0;
    			if (b2 === 0xff)
    			{
    				b2 = 0;
    				if (b3 === 0xff)
    				{
    					b3 = 0;
    				}
    				else
    				{
    					++b3;
    				}
    			}
    			else
    			{
    				++b2;
    			}
    			}
    			else
    			{
    			++b1;
    			}

    			word = 0;
    			word += (b1 << 16);
    			word += (b2 << 8);
    			word += b3;
    			}
    			else
    			{
    			word += (0x01 << 24);
    			}
    			return word;
    		}

    		function incCounter(counter)
    		{
    			if ((counter[0] = incWord(counter[0])) === 0)
    			{
    				// encr_data in fileenc.c from  Dr Brian Gladman's counts only with DWORD j < 8
    				counter[1] = incWord(counter[1]);
    			}
    			return counter;
    		}

    	    var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({
    	        processBlock: function (words, offset) {
    	            // Shortcuts
    	            var cipher = this._cipher
    	            var blockSize = cipher.blockSize;
    	            var iv = this._iv;
    	            var counter = this._counter;

    	            // Generate keystream
    	            if (iv) {
    	                counter = this._counter = iv.slice(0);

    	                // Remove IV for subsequent blocks
    	                this._iv = undefined;
    	            }

    				incCounter(counter);

    				var keystream = counter.slice(0);
    	            cipher.encryptBlock(keystream, 0);

    	            // Encrypt
    	            for (var i = 0; i < blockSize; i++) {
    	                words[offset + i] ^= keystream[i];
    	            }
    	        }
    	    });

    	    CTRGladman.Decryptor = Encryptor;

    	    return CTRGladman;
    	}());

    	return CryptoJS.mode.CTRGladman;

    }));
    },{"./cipher-core":45,"./core":46}],57:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * Counter block mode.
    	 */
    	CryptoJS.mode.CTR = (function () {
    	    var CTR = CryptoJS.lib.BlockCipherMode.extend();

    	    var Encryptor = CTR.Encryptor = CTR.extend({
    	        processBlock: function (words, offset) {
    	            // Shortcuts
    	            var cipher = this._cipher
    	            var blockSize = cipher.blockSize;
    	            var iv = this._iv;
    	            var counter = this._counter;

    	            // Generate keystream
    	            if (iv) {
    	                counter = this._counter = iv.slice(0);

    	                // Remove IV for subsequent blocks
    	                this._iv = undefined;
    	            }
    	            var keystream = counter.slice(0);
    	            cipher.encryptBlock(keystream, 0);

    	            // Increment counter
    	            counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0

    	            // Encrypt
    	            for (var i = 0; i < blockSize; i++) {
    	                words[offset + i] ^= keystream[i];
    	            }
    	        }
    	    });

    	    CTR.Decryptor = Encryptor;

    	    return CTR;
    	}());

    	return CryptoJS.mode.CTR;

    }));
    },{"./cipher-core":45,"./core":46}],58:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * Electronic Codebook block mode.
    	 */
    	CryptoJS.mode.ECB = (function () {
    	    var ECB = CryptoJS.lib.BlockCipherMode.extend();

    	    ECB.Encryptor = ECB.extend({
    	        processBlock: function (words, offset) {
    	            this._cipher.encryptBlock(words, offset);
    	        }
    	    });

    	    ECB.Decryptor = ECB.extend({
    	        processBlock: function (words, offset) {
    	            this._cipher.decryptBlock(words, offset);
    	        }
    	    });

    	    return ECB;
    	}());

    	return CryptoJS.mode.ECB;

    }));
    },{"./cipher-core":45,"./core":46}],59:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * Output Feedback block mode.
    	 */
    	CryptoJS.mode.OFB = (function () {
    	    var OFB = CryptoJS.lib.BlockCipherMode.extend();

    	    var Encryptor = OFB.Encryptor = OFB.extend({
    	        processBlock: function (words, offset) {
    	            // Shortcuts
    	            var cipher = this._cipher
    	            var blockSize = cipher.blockSize;
    	            var iv = this._iv;
    	            var keystream = this._keystream;

    	            // Generate keystream
    	            if (iv) {
    	                keystream = this._keystream = iv.slice(0);

    	                // Remove IV for subsequent blocks
    	                this._iv = undefined;
    	            }
    	            cipher.encryptBlock(keystream, 0);

    	            // Encrypt
    	            for (var i = 0; i < blockSize; i++) {
    	                words[offset + i] ^= keystream[i];
    	            }
    	        }
    	    });

    	    OFB.Decryptor = Encryptor;

    	    return OFB;
    	}());

    	return CryptoJS.mode.OFB;

    }));
    },{"./cipher-core":45,"./core":46}],60:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * ANSI X.923 padding strategy.
    	 */
    	CryptoJS.pad.AnsiX923 = {
    	    pad: function (data, blockSize) {
    	        // Shortcuts
    	        var dataSigBytes = data.sigBytes;
    	        var blockSizeBytes = blockSize * 4;

    	        // Count padding bytes
    	        var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes;

    	        // Compute last byte position
    	        var lastBytePos = dataSigBytes + nPaddingBytes - 1;

    	        // Pad
    	        data.clamp();
    	        data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8);
    	        data.sigBytes += nPaddingBytes;
    	    },

    	    unpad: function (data) {
    	        // Get number of padding bytes from last byte
    	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;

    	        // Remove padding
    	        data.sigBytes -= nPaddingBytes;
    	    }
    	};

    	return CryptoJS.pad.Ansix923;

    }));
    },{"./cipher-core":45,"./core":46}],61:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * ISO 10126 padding strategy.
    	 */
    	CryptoJS.pad.Iso10126 = {
    	    pad: function (data, blockSize) {
    	        // Shortcut
    	        var blockSizeBytes = blockSize * 4;

    	        // Count padding bytes
    	        var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;

    	        // Pad
    	        data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)).
    	             concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1));
    	    },

    	    unpad: function (data) {
    	        // Get number of padding bytes from last byte
    	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;

    	        // Remove padding
    	        data.sigBytes -= nPaddingBytes;
    	    }
    	};

    	return CryptoJS.pad.Iso10126;

    }));
    },{"./cipher-core":45,"./core":46}],62:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * ISO/IEC 9797-1 Padding Method 2.
    	 */
    	CryptoJS.pad.Iso97971 = {
    	    pad: function (data, blockSize) {
    	        // Add 0x80 byte
    	        data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1));

    	        // Zero pad the rest
    	        CryptoJS.pad.ZeroPadding.pad(data, blockSize);
    	    },

    	    unpad: function (data) {
    	        // Remove zero padding
    	        CryptoJS.pad.ZeroPadding.unpad(data);

    	        // Remove one more byte -- the 0x80 byte
    	        data.sigBytes--;
    	    }
    	};

    	return CryptoJS.pad.Iso97971;

    }));
    },{"./cipher-core":45,"./core":46}],63:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * A noop padding strategy.
    	 */
    	CryptoJS.pad.NoPadding = {
    	    pad: function () {
    	    },

    	    unpad: function () {
    	    }
    	};

    	return CryptoJS.pad.NoPadding;

    }));
    },{"./cipher-core":45,"./core":46}],64:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/**
    	 * Zero padding strategy.
    	 */
    	CryptoJS.pad.ZeroPadding = {
    	    pad: function (data, blockSize) {
    	        // Shortcut
    	        var blockSizeBytes = blockSize * 4;

    	        // Pad
    	        data.clamp();
    	        data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes);
    	    },

    	    unpad: function (data) {
    	        // Shortcut
    	        var dataWords = data.words;

    	        // Unpad
    	        var i = data.sigBytes - 1;
    	        while (!((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) {
    	            i--;
    	        }
    	        data.sigBytes = i + 1;
    	    }
    	};

    	return CryptoJS.pad.ZeroPadding;

    }));
    },{"./cipher-core":45,"./core":46}],65:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./sha1"), _dereq_("./hmac"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./sha1", "./hmac"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var Base = C_lib.Base;
    	    var WordArray = C_lib.WordArray;
    	    var C_algo = C.algo;
    	    var SHA1 = C_algo.SHA1;
    	    var HMAC = C_algo.HMAC;

    	    /**
    	     * Password-Based Key Derivation Function 2 algorithm.
    	     */
    	    var PBKDF2 = C_algo.PBKDF2 = Base.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
    	         * @property {Hasher} hasher The hasher to use. Default: SHA1
    	         * @property {number} iterations The number of iterations to perform. Default: 1
    	         */
    	        cfg: Base.extend({
    	            keySize: 128/32,
    	            hasher: SHA1,
    	            iterations: 1
    	        }),

    	        /**
    	         * Initializes a newly created key derivation function.
    	         *
    	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
    	         *
    	         * @example
    	         *
    	         *     var kdf = CryptoJS.algo.PBKDF2.create();
    	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
    	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 });
    	         */
    	        init: function (cfg) {
    	            this.cfg = this.cfg.extend(cfg);
    	        },

    	        /**
    	         * Computes the Password-Based Key Derivation Function 2.
    	         *
    	         * @param {WordArray|string} password The password.
    	         * @param {WordArray|string} salt A salt.
    	         *
    	         * @return {WordArray} The derived key.
    	         *
    	         * @example
    	         *
    	         *     var key = kdf.compute(password, salt);
    	         */
    	        compute: function (password, salt) {
    	            // Shortcut
    	            var cfg = this.cfg;

    	            // Init HMAC
    	            var hmac = HMAC.create(cfg.hasher, password);

    	            // Initial values
    	            var derivedKey = WordArray.create();
    	            var blockIndex = WordArray.create([0x00000001]);

    	            // Shortcuts
    	            var derivedKeyWords = derivedKey.words;
    	            var blockIndexWords = blockIndex.words;
    	            var keySize = cfg.keySize;
    	            var iterations = cfg.iterations;

    	            // Generate key
    	            while (derivedKeyWords.length < keySize) {
    	                var block = hmac.update(salt).finalize(blockIndex);
    	                hmac.reset();

    	                // Shortcuts
    	                var blockWords = block.words;
    	                var blockWordsLength = blockWords.length;

    	                // Iterations
    	                var intermediate = block;
    	                for (var i = 1; i < iterations; i++) {
    	                    intermediate = hmac.finalize(intermediate);
    	                    hmac.reset();

    	                    // Shortcut
    	                    var intermediateWords = intermediate.words;

    	                    // XOR intermediate with block
    	                    for (var j = 0; j < blockWordsLength; j++) {
    	                        blockWords[j] ^= intermediateWords[j];
    	                    }
    	                }

    	                derivedKey.concat(block);
    	                blockIndexWords[0]++;
    	            }
    	            derivedKey.sigBytes = keySize * 4;

    	            return derivedKey;
    	        }
    	    });

    	    /**
    	     * Computes the Password-Based Key Derivation Function 2.
    	     *
    	     * @param {WordArray|string} password The password.
    	     * @param {WordArray|string} salt A salt.
    	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
    	     *
    	     * @return {WordArray} The derived key.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var key = CryptoJS.PBKDF2(password, salt);
    	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
    	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 });
    	     */
    	    C.PBKDF2 = function (password, salt, cfg) {
    	        return PBKDF2.create(cfg).compute(password, salt);
    	    };
    	}());

    	return CryptoJS.PBKDF2;

    }));
    },{"./core":46,"./hmac":51,"./sha1":70}],66:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./enc-base64"), _dereq_("./md5"), _dereq_("./evpkdf"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var StreamCipher = C_lib.StreamCipher;
    	    var C_algo = C.algo;

    	    // Reusable objects
    	    var S  = [];
    	    var C_ = [];
    	    var G  = [];

    	    /**
    	     * Rabbit stream cipher algorithm.
    	     *
    	     * This is a legacy version that neglected to convert the key to little-endian.
    	     * This error doesn't affect the cipher's security,
    	     * but it does affect its compatibility with other implementations.
    	     */
    	    var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({
    	        _doReset: function () {
    	            // Shortcuts
    	            var K = this._key.words;
    	            var iv = this.cfg.iv;

    	            // Generate initial state values
    	            var X = this._X = [
    	                K[0], (K[3] << 16) | (K[2] >>> 16),
    	                K[1], (K[0] << 16) | (K[3] >>> 16),
    	                K[2], (K[1] << 16) | (K[0] >>> 16),
    	                K[3], (K[2] << 16) | (K[1] >>> 16)
    	            ];

    	            // Generate initial counter values
    	            var C = this._C = [
    	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
    	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
    	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
    	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
    	            ];

    	            // Carry bit
    	            this._b = 0;

    	            // Iterate the system four times
    	            for (var i = 0; i < 4; i++) {
    	                nextState.call(this);
    	            }

    	            // Modify the counters
    	            for (var i = 0; i < 8; i++) {
    	                C[i] ^= X[(i + 4) & 7];
    	            }

    	            // IV setup
    	            if (iv) {
    	                // Shortcuts
    	                var IV = iv.words;
    	                var IV_0 = IV[0];
    	                var IV_1 = IV[1];

    	                // Generate four subvectors
    	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
    	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
    	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
    	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);

    	                // Modify counter values
    	                C[0] ^= i0;
    	                C[1] ^= i1;
    	                C[2] ^= i2;
    	                C[3] ^= i3;
    	                C[4] ^= i0;
    	                C[5] ^= i1;
    	                C[6] ^= i2;
    	                C[7] ^= i3;

    	                // Iterate the system four times
    	                for (var i = 0; i < 4; i++) {
    	                    nextState.call(this);
    	                }
    	            }
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            // Shortcut
    	            var X = this._X;

    	            // Iterate the system
    	            nextState.call(this);

    	            // Generate four keystream words
    	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
    	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
    	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
    	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);

    	            for (var i = 0; i < 4; i++) {
    	                // Swap endian
    	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
    	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);

    	                // Encrypt
    	                M[offset + i] ^= S[i];
    	            }
    	        },

    	        blockSize: 128/32,

    	        ivSize: 64/32
    	    });

    	    function nextState() {
    	        // Shortcuts
    	        var X = this._X;
    	        var C = this._C;

    	        // Save old counter values
    	        for (var i = 0; i < 8; i++) {
    	            C_[i] = C[i];
    	        }

    	        // Calculate new counter values
    	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
    	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
    	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
    	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
    	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
    	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
    	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
    	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
    	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;

    	        // Calculate the g-values
    	        for (var i = 0; i < 8; i++) {
    	            var gx = X[i] + C[i];

    	            // Construct high and low argument for squaring
    	            var ga = gx & 0xffff;
    	            var gb = gx >>> 16;

    	            // Calculate high and low result of squaring
    	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
    	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);

    	            // High XOR low
    	            G[i] = gh ^ gl;
    	        }

    	        // Calculate new state values
    	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
    	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
    	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
    	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
    	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
    	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
    	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
    	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
    	    }

    	    /**
    	     * Shortcut functions to the cipher's object interface.
    	     *
    	     * @example
    	     *
    	     *     var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg);
    	     *     var plaintext  = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg);
    	     */
    	    C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy);
    	}());

    	return CryptoJS.RabbitLegacy;

    }));
    },{"./cipher-core":45,"./core":46,"./enc-base64":47,"./evpkdf":49,"./md5":54}],67:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./enc-base64"), _dereq_("./md5"), _dereq_("./evpkdf"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var StreamCipher = C_lib.StreamCipher;
    	    var C_algo = C.algo;

    	    // Reusable objects
    	    var S  = [];
    	    var C_ = [];
    	    var G  = [];

    	    /**
    	     * Rabbit stream cipher algorithm
    	     */
    	    var Rabbit = C_algo.Rabbit = StreamCipher.extend({
    	        _doReset: function () {
    	            // Shortcuts
    	            var K = this._key.words;
    	            var iv = this.cfg.iv;

    	            // Swap endian
    	            for (var i = 0; i < 4; i++) {
    	                K[i] = (((K[i] << 8)  | (K[i] >>> 24)) & 0x00ff00ff) |
    	                       (((K[i] << 24) | (K[i] >>> 8))  & 0xff00ff00);
    	            }

    	            // Generate initial state values
    	            var X = this._X = [
    	                K[0], (K[3] << 16) | (K[2] >>> 16),
    	                K[1], (K[0] << 16) | (K[3] >>> 16),
    	                K[2], (K[1] << 16) | (K[0] >>> 16),
    	                K[3], (K[2] << 16) | (K[1] >>> 16)
    	            ];

    	            // Generate initial counter values
    	            var C = this._C = [
    	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
    	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
    	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
    	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
    	            ];

    	            // Carry bit
    	            this._b = 0;

    	            // Iterate the system four times
    	            for (var i = 0; i < 4; i++) {
    	                nextState.call(this);
    	            }

    	            // Modify the counters
    	            for (var i = 0; i < 8; i++) {
    	                C[i] ^= X[(i + 4) & 7];
    	            }

    	            // IV setup
    	            if (iv) {
    	                // Shortcuts
    	                var IV = iv.words;
    	                var IV_0 = IV[0];
    	                var IV_1 = IV[1];

    	                // Generate four subvectors
    	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
    	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
    	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
    	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);

    	                // Modify counter values
    	                C[0] ^= i0;
    	                C[1] ^= i1;
    	                C[2] ^= i2;
    	                C[3] ^= i3;
    	                C[4] ^= i0;
    	                C[5] ^= i1;
    	                C[6] ^= i2;
    	                C[7] ^= i3;

    	                // Iterate the system four times
    	                for (var i = 0; i < 4; i++) {
    	                    nextState.call(this);
    	                }
    	            }
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            // Shortcut
    	            var X = this._X;

    	            // Iterate the system
    	            nextState.call(this);

    	            // Generate four keystream words
    	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
    	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
    	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
    	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);

    	            for (var i = 0; i < 4; i++) {
    	                // Swap endian
    	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
    	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);

    	                // Encrypt
    	                M[offset + i] ^= S[i];
    	            }
    	        },

    	        blockSize: 128/32,

    	        ivSize: 64/32
    	    });

    	    function nextState() {
    	        // Shortcuts
    	        var X = this._X;
    	        var C = this._C;

    	        // Save old counter values
    	        for (var i = 0; i < 8; i++) {
    	            C_[i] = C[i];
    	        }

    	        // Calculate new counter values
    	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
    	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
    	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
    	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
    	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
    	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
    	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
    	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
    	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;

    	        // Calculate the g-values
    	        for (var i = 0; i < 8; i++) {
    	            var gx = X[i] + C[i];

    	            // Construct high and low argument for squaring
    	            var ga = gx & 0xffff;
    	            var gb = gx >>> 16;

    	            // Calculate high and low result of squaring
    	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
    	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);

    	            // High XOR low
    	            G[i] = gh ^ gl;
    	        }

    	        // Calculate new state values
    	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
    	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
    	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
    	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
    	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
    	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
    	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
    	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
    	    }

    	    /**
    	     * Shortcut functions to the cipher's object interface.
    	     *
    	     * @example
    	     *
    	     *     var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg);
    	     *     var plaintext  = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg);
    	     */
    	    C.Rabbit = StreamCipher._createHelper(Rabbit);
    	}());

    	return CryptoJS.Rabbit;

    }));
    },{"./cipher-core":45,"./core":46,"./enc-base64":47,"./evpkdf":49,"./md5":54}],68:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./enc-base64"), _dereq_("./md5"), _dereq_("./evpkdf"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var StreamCipher = C_lib.StreamCipher;
    	    var C_algo = C.algo;

    	    /**
    	     * RC4 stream cipher algorithm.
    	     */
    	    var RC4 = C_algo.RC4 = StreamCipher.extend({
    	        _doReset: function () {
    	            // Shortcuts
    	            var key = this._key;
    	            var keyWords = key.words;
    	            var keySigBytes = key.sigBytes;

    	            // Init sbox
    	            var S = this._S = [];
    	            for (var i = 0; i < 256; i++) {
    	                S[i] = i;
    	            }

    	            // Key setup
    	            for (var i = 0, j = 0; i < 256; i++) {
    	                var keyByteIndex = i % keySigBytes;
    	                var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff;

    	                j = (j + S[i] + keyByte) % 256;

    	                // Swap
    	                var t = S[i];
    	                S[i] = S[j];
    	                S[j] = t;
    	            }

    	            // Counters
    	            this._i = this._j = 0;
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            M[offset] ^= generateKeystreamWord.call(this);
    	        },

    	        keySize: 256/32,

    	        ivSize: 0
    	    });

    	    function generateKeystreamWord() {
    	        // Shortcuts
    	        var S = this._S;
    	        var i = this._i;
    	        var j = this._j;

    	        // Generate keystream word
    	        var keystreamWord = 0;
    	        for (var n = 0; n < 4; n++) {
    	            i = (i + 1) % 256;
    	            j = (j + S[i]) % 256;

    	            // Swap
    	            var t = S[i];
    	            S[i] = S[j];
    	            S[j] = t;

    	            keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8);
    	        }

    	        // Update counters
    	        this._i = i;
    	        this._j = j;

    	        return keystreamWord;
    	    }

    	    /**
    	     * Shortcut functions to the cipher's object interface.
    	     *
    	     * @example
    	     *
    	     *     var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg);
    	     *     var plaintext  = CryptoJS.RC4.decrypt(ciphertext, key, cfg);
    	     */
    	    C.RC4 = StreamCipher._createHelper(RC4);

    	    /**
    	     * Modified RC4 stream cipher algorithm.
    	     */
    	    var RC4Drop = C_algo.RC4Drop = RC4.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {number} drop The number of keystream words to drop. Default 192
    	         */
    	        cfg: RC4.cfg.extend({
    	            drop: 192
    	        }),

    	        _doReset: function () {
    	            RC4._doReset.call(this);

    	            // Drop
    	            for (var i = this.cfg.drop; i > 0; i--) {
    	                generateKeystreamWord.call(this);
    	            }
    	        }
    	    });

    	    /**
    	     * Shortcut functions to the cipher's object interface.
    	     *
    	     * @example
    	     *
    	     *     var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg);
    	     *     var plaintext  = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg);
    	     */
    	    C.RC4Drop = StreamCipher._createHelper(RC4Drop);
    	}());

    	return CryptoJS.RC4;

    }));
    },{"./cipher-core":45,"./core":46,"./enc-base64":47,"./evpkdf":49,"./md5":54}],69:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	/** @preserve
    	(c) 2012 by Cédric Mesnil. All rights reserved.

    	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    	    - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    	    - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

    	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    	*/

    	(function (Math) {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var Hasher = C_lib.Hasher;
    	    var C_algo = C.algo;

    	    // Constants table
    	    var _zl = WordArray.create([
    	        0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
    	        7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
    	        3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
    	        1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
    	        4,  0,  5,  9,  7, 12,  2, 10, 14,  1,  3,  8, 11,  6, 15, 13]);
    	    var _zr = WordArray.create([
    	        5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
    	        6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
    	        15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
    	        8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
    	        12, 15, 10,  4,  1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11]);
    	    var _sl = WordArray.create([
    	         11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
    	        7, 6,   8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
    	        11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
    	          11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
    	        9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6 ]);
    	    var _sr = WordArray.create([
    	        8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
    	        9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
    	        9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
    	        15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
    	        8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11 ]);

    	    var _hl =  WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]);
    	    var _hr =  WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]);

    	    /**
    	     * RIPEMD160 hash algorithm.
    	     */
    	    var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({
    	        _doReset: function () {
    	            this._hash  = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]);
    	        },

    	        _doProcessBlock: function (M, offset) {

    	            // Swap endian
    	            for (var i = 0; i < 16; i++) {
    	                // Shortcuts
    	                var offset_i = offset + i;
    	                var M_offset_i = M[offset_i];

    	                // Swap
    	                M[offset_i] = (
    	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
    	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
    	                );
    	            }
    	            // Shortcut
    	            var H  = this._hash.words;
    	            var hl = _hl.words;
    	            var hr = _hr.words;
    	            var zl = _zl.words;
    	            var zr = _zr.words;
    	            var sl = _sl.words;
    	            var sr = _sr.words;

    	            // Working variables
    	            var al, bl, cl, dl, el;
    	            var ar, br, cr, dr, er;

    	            ar = al = H[0];
    	            br = bl = H[1];
    	            cr = cl = H[2];
    	            dr = dl = H[3];
    	            er = el = H[4];
    	            // Computation
    	            var t;
    	            for (var i = 0; i < 80; i += 1) {
    	                t = (al +  M[offset+zl[i]])|0;
    	                if (i<16){
    		            t +=  f1(bl,cl,dl) + hl[0];
    	                } else if (i<32) {
    		            t +=  f2(bl,cl,dl) + hl[1];
    	                } else if (i<48) {
    		            t +=  f3(bl,cl,dl) + hl[2];
    	                } else if (i<64) {
    		            t +=  f4(bl,cl,dl) + hl[3];
    	                } else {// if (i<80) {
    		            t +=  f5(bl,cl,dl) + hl[4];
    	                }
    	                t = t|0;
    	                t =  rotl(t,sl[i]);
    	                t = (t+el)|0;
    	                al = el;
    	                el = dl;
    	                dl = rotl(cl, 10);
    	                cl = bl;
    	                bl = t;

    	                t = (ar + M[offset+zr[i]])|0;
    	                if (i<16){
    		            t +=  f5(br,cr,dr) + hr[0];
    	                } else if (i<32) {
    		            t +=  f4(br,cr,dr) + hr[1];
    	                } else if (i<48) {
    		            t +=  f3(br,cr,dr) + hr[2];
    	                } else if (i<64) {
    		            t +=  f2(br,cr,dr) + hr[3];
    	                } else {// if (i<80) {
    		            t +=  f1(br,cr,dr) + hr[4];
    	                }
    	                t = t|0;
    	                t =  rotl(t,sr[i]) ;
    	                t = (t+er)|0;
    	                ar = er;
    	                er = dr;
    	                dr = rotl(cr, 10);
    	                cr = br;
    	                br = t;
    	            }
    	            // Intermediate hash value
    	            t    = (H[1] + cl + dr)|0;
    	            H[1] = (H[2] + dl + er)|0;
    	            H[2] = (H[3] + el + ar)|0;
    	            H[3] = (H[4] + al + br)|0;
    	            H[4] = (H[0] + bl + cr)|0;
    	            H[0] =  t;
    	        },

    	        _doFinalize: function () {
    	            // Shortcuts
    	            var data = this._data;
    	            var dataWords = data.words;

    	            var nBitsTotal = this._nDataBytes * 8;
    	            var nBitsLeft = data.sigBytes * 8;

    	            // Add padding
    	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
    	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
    	                (((nBitsTotal << 8)  | (nBitsTotal >>> 24)) & 0x00ff00ff) |
    	                (((nBitsTotal << 24) | (nBitsTotal >>> 8))  & 0xff00ff00)
    	            );
    	            data.sigBytes = (dataWords.length + 1) * 4;

    	            // Hash final blocks
    	            this._process();

    	            // Shortcuts
    	            var hash = this._hash;
    	            var H = hash.words;

    	            // Swap endian
    	            for (var i = 0; i < 5; i++) {
    	                // Shortcut
    	                var H_i = H[i];

    	                // Swap
    	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
    	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
    	            }

    	            // Return final computed hash
    	            return hash;
    	        },

    	        clone: function () {
    	            var clone = Hasher.clone.call(this);
    	            clone._hash = this._hash.clone();

    	            return clone;
    	        }
    	    });

    	    function f1(x, y, z) {
    	        return ((x) ^ (y) ^ (z));

    	    }

    	    function f2(x, y, z) {
    	        return (((x)&(y)) | ((~x)&(z)));
    	    }

    	    function f3(x, y, z) {
    	        return (((x) | (~(y))) ^ (z));
    	    }

    	    function f4(x, y, z) {
    	        return (((x) & (z)) | ((y)&(~(z))));
    	    }

    	    function f5(x, y, z) {
    	        return ((x) ^ ((y) |(~(z))));

    	    }

    	    function rotl(x,n) {
    	        return (x<<n) | (x>>>(32-n));
    	    }

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.RIPEMD160('message');
    	     *     var hash = CryptoJS.RIPEMD160(wordArray);
    	     */
    	    C.RIPEMD160 = Hasher._createHelper(RIPEMD160);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacRIPEMD160(message, key);
    	     */
    	    C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160);
    	}(Math));

    	return CryptoJS.RIPEMD160;

    }));
    },{"./core":46}],70:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var Hasher = C_lib.Hasher;
    	    var C_algo = C.algo;

    	    // Reusable object
    	    var W = [];

    	    /**
    	     * SHA-1 hash algorithm.
    	     */
    	    var SHA1 = C_algo.SHA1 = Hasher.extend({
    	        _doReset: function () {
    	            this._hash = new WordArray.init([
    	                0x67452301, 0xefcdab89,
    	                0x98badcfe, 0x10325476,
    	                0xc3d2e1f0
    	            ]);
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            // Shortcut
    	            var H = this._hash.words;

    	            // Working variables
    	            var a = H[0];
    	            var b = H[1];
    	            var c = H[2];
    	            var d = H[3];
    	            var e = H[4];

    	            // Computation
    	            for (var i = 0; i < 80; i++) {
    	                if (i < 16) {
    	                    W[i] = M[offset + i] | 0;
    	                } else {
    	                    var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
    	                    W[i] = (n << 1) | (n >>> 31);
    	                }

    	                var t = ((a << 5) | (a >>> 27)) + e + W[i];
    	                if (i < 20) {
    	                    t += ((b & c) | (~b & d)) + 0x5a827999;
    	                } else if (i < 40) {
    	                    t += (b ^ c ^ d) + 0x6ed9eba1;
    	                } else if (i < 60) {
    	                    t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;
    	                } else /* if (i < 80) */ {
    	                    t += (b ^ c ^ d) - 0x359d3e2a;
    	                }

    	                e = d;
    	                d = c;
    	                c = (b << 30) | (b >>> 2);
    	                b = a;
    	                a = t;
    	            }

    	            // Intermediate hash value
    	            H[0] = (H[0] + a) | 0;
    	            H[1] = (H[1] + b) | 0;
    	            H[2] = (H[2] + c) | 0;
    	            H[3] = (H[3] + d) | 0;
    	            H[4] = (H[4] + e) | 0;
    	        },

    	        _doFinalize: function () {
    	            // Shortcuts
    	            var data = this._data;
    	            var dataWords = data.words;

    	            var nBitsTotal = this._nDataBytes * 8;
    	            var nBitsLeft = data.sigBytes * 8;

    	            // Add padding
    	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
    	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
    	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
    	            data.sigBytes = dataWords.length * 4;

    	            // Hash final blocks
    	            this._process();

    	            // Return final computed hash
    	            return this._hash;
    	        },

    	        clone: function () {
    	            var clone = Hasher.clone.call(this);
    	            clone._hash = this._hash.clone();

    	            return clone;
    	        }
    	    });

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.SHA1('message');
    	     *     var hash = CryptoJS.SHA1(wordArray);
    	     */
    	    C.SHA1 = Hasher._createHelper(SHA1);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacSHA1(message, key);
    	     */
    	    C.HmacSHA1 = Hasher._createHmacHelper(SHA1);
    	}());

    	return CryptoJS.SHA1;

    }));
    },{"./core":46}],71:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./sha256"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./sha256"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var C_algo = C.algo;
    	    var SHA256 = C_algo.SHA256;

    	    /**
    	     * SHA-224 hash algorithm.
    	     */
    	    var SHA224 = C_algo.SHA224 = SHA256.extend({
    	        _doReset: function () {
    	            this._hash = new WordArray.init([
    	                0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
    	                0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
    	            ]);
    	        },

    	        _doFinalize: function () {
    	            var hash = SHA256._doFinalize.call(this);

    	            hash.sigBytes -= 4;

    	            return hash;
    	        }
    	    });

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.SHA224('message');
    	     *     var hash = CryptoJS.SHA224(wordArray);
    	     */
    	    C.SHA224 = SHA256._createHelper(SHA224);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacSHA224(message, key);
    	     */
    	    C.HmacSHA224 = SHA256._createHmacHelper(SHA224);
    	}());

    	return CryptoJS.SHA224;

    }));
    },{"./core":46,"./sha256":72}],72:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function (Math) {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var Hasher = C_lib.Hasher;
    	    var C_algo = C.algo;

    	    // Initialization and round constants tables
    	    var H = [];
    	    var K = [];

    	    // Compute constants
    	    (function () {
    	        function isPrime(n) {
    	            var sqrtN = Math.sqrt(n);
    	            for (var factor = 2; factor <= sqrtN; factor++) {
    	                if (!(n % factor)) {
    	                    return false;
    	                }
    	            }

    	            return true;
    	        }

    	        function getFractionalBits(n) {
    	            return ((n - (n | 0)) * 0x100000000) | 0;
    	        }

    	        var n = 2;
    	        var nPrime = 0;
    	        while (nPrime < 64) {
    	            if (isPrime(n)) {
    	                if (nPrime < 8) {
    	                    H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
    	                }
    	                K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));

    	                nPrime++;
    	            }

    	            n++;
    	        }
    	    }());

    	    // Reusable object
    	    var W = [];

    	    /**
    	     * SHA-256 hash algorithm.
    	     */
    	    var SHA256 = C_algo.SHA256 = Hasher.extend({
    	        _doReset: function () {
    	            this._hash = new WordArray.init(H.slice(0));
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            // Shortcut
    	            var H = this._hash.words;

    	            // Working variables
    	            var a = H[0];
    	            var b = H[1];
    	            var c = H[2];
    	            var d = H[3];
    	            var e = H[4];
    	            var f = H[5];
    	            var g = H[6];
    	            var h = H[7];

    	            // Computation
    	            for (var i = 0; i < 64; i++) {
    	                if (i < 16) {
    	                    W[i] = M[offset + i] | 0;
    	                } else {
    	                    var gamma0x = W[i - 15];
    	                    var gamma0  = ((gamma0x << 25) | (gamma0x >>> 7))  ^
    	                                  ((gamma0x << 14) | (gamma0x >>> 18)) ^
    	                                   (gamma0x >>> 3);

    	                    var gamma1x = W[i - 2];
    	                    var gamma1  = ((gamma1x << 15) | (gamma1x >>> 17)) ^
    	                                  ((gamma1x << 13) | (gamma1x >>> 19)) ^
    	                                   (gamma1x >>> 10);

    	                    W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
    	                }

    	                var ch  = (e & f) ^ (~e & g);
    	                var maj = (a & b) ^ (a & c) ^ (b & c);

    	                var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
    	                var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7)  | (e >>> 25));

    	                var t1 = h + sigma1 + ch + K[i] + W[i];
    	                var t2 = sigma0 + maj;

    	                h = g;
    	                g = f;
    	                f = e;
    	                e = (d + t1) | 0;
    	                d = c;
    	                c = b;
    	                b = a;
    	                a = (t1 + t2) | 0;
    	            }

    	            // Intermediate hash value
    	            H[0] = (H[0] + a) | 0;
    	            H[1] = (H[1] + b) | 0;
    	            H[2] = (H[2] + c) | 0;
    	            H[3] = (H[3] + d) | 0;
    	            H[4] = (H[4] + e) | 0;
    	            H[5] = (H[5] + f) | 0;
    	            H[6] = (H[6] + g) | 0;
    	            H[7] = (H[7] + h) | 0;
    	        },

    	        _doFinalize: function () {
    	            // Shortcuts
    	            var data = this._data;
    	            var dataWords = data.words;

    	            var nBitsTotal = this._nDataBytes * 8;
    	            var nBitsLeft = data.sigBytes * 8;

    	            // Add padding
    	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
    	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
    	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
    	            data.sigBytes = dataWords.length * 4;

    	            // Hash final blocks
    	            this._process();

    	            // Return final computed hash
    	            return this._hash;
    	        },

    	        clone: function () {
    	            var clone = Hasher.clone.call(this);
    	            clone._hash = this._hash.clone();

    	            return clone;
    	        }
    	    });

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.SHA256('message');
    	     *     var hash = CryptoJS.SHA256(wordArray);
    	     */
    	    C.SHA256 = Hasher._createHelper(SHA256);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacSHA256(message, key);
    	     */
    	    C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
    	}(Math));

    	return CryptoJS.SHA256;

    }));
    },{"./core":46}],73:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./x64-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./x64-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function (Math) {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var Hasher = C_lib.Hasher;
    	    var C_x64 = C.x64;
    	    var X64Word = C_x64.Word;
    	    var C_algo = C.algo;

    	    // Constants tables
    	    var RHO_OFFSETS = [];
    	    var PI_INDEXES  = [];
    	    var ROUND_CONSTANTS = [];

    	    // Compute Constants
    	    (function () {
    	        // Compute rho offset constants
    	        var x = 1, y = 0;
    	        for (var t = 0; t < 24; t++) {
    	            RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64;

    	            var newX = y % 5;
    	            var newY = (2 * x + 3 * y) % 5;
    	            x = newX;
    	            y = newY;
    	        }

    	        // Compute pi index constants
    	        for (var x = 0; x < 5; x++) {
    	            for (var y = 0; y < 5; y++) {
    	                PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;
    	            }
    	        }

    	        // Compute round constants
    	        var LFSR = 0x01;
    	        for (var i = 0; i < 24; i++) {
    	            var roundConstantMsw = 0;
    	            var roundConstantLsw = 0;

    	            for (var j = 0; j < 7; j++) {
    	                if (LFSR & 0x01) {
    	                    var bitPosition = (1 << j) - 1;
    	                    if (bitPosition < 32) {
    	                        roundConstantLsw ^= 1 << bitPosition;
    	                    } else /* if (bitPosition >= 32) */ {
    	                        roundConstantMsw ^= 1 << (bitPosition - 32);
    	                    }
    	                }

    	                // Compute next LFSR
    	                if (LFSR & 0x80) {
    	                    // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1
    	                    LFSR = (LFSR << 1) ^ 0x71;
    	                } else {
    	                    LFSR <<= 1;
    	                }
    	            }

    	            ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);
    	        }
    	    }());

    	    // Reusable objects for temporary values
    	    var T = [];
    	    (function () {
    	        for (var i = 0; i < 25; i++) {
    	            T[i] = X64Word.create();
    	        }
    	    }());

    	    /**
    	     * SHA-3 hash algorithm.
    	     */
    	    var SHA3 = C_algo.SHA3 = Hasher.extend({
    	        /**
    	         * Configuration options.
    	         *
    	         * @property {number} outputLength
    	         *   The desired number of bits in the output hash.
    	         *   Only values permitted are: 224, 256, 384, 512.
    	         *   Default: 512
    	         */
    	        cfg: Hasher.cfg.extend({
    	            outputLength: 512
    	        }),

    	        _doReset: function () {
    	            var state = this._state = []
    	            for (var i = 0; i < 25; i++) {
    	                state[i] = new X64Word.init();
    	            }

    	            this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            // Shortcuts
    	            var state = this._state;
    	            var nBlockSizeLanes = this.blockSize / 2;

    	            // Absorb
    	            for (var i = 0; i < nBlockSizeLanes; i++) {
    	                // Shortcuts
    	                var M2i  = M[offset + 2 * i];
    	                var M2i1 = M[offset + 2 * i + 1];

    	                // Swap endian
    	                M2i = (
    	                    (((M2i << 8)  | (M2i >>> 24)) & 0x00ff00ff) |
    	                    (((M2i << 24) | (M2i >>> 8))  & 0xff00ff00)
    	                );
    	                M2i1 = (
    	                    (((M2i1 << 8)  | (M2i1 >>> 24)) & 0x00ff00ff) |
    	                    (((M2i1 << 24) | (M2i1 >>> 8))  & 0xff00ff00)
    	                );

    	                // Absorb message into state
    	                var lane = state[i];
    	                lane.high ^= M2i1;
    	                lane.low  ^= M2i;
    	            }

    	            // Rounds
    	            for (var round = 0; round < 24; round++) {
    	                // Theta
    	                for (var x = 0; x < 5; x++) {
    	                    // Mix column lanes
    	                    var tMsw = 0, tLsw = 0;
    	                    for (var y = 0; y < 5; y++) {
    	                        var lane = state[x + 5 * y];
    	                        tMsw ^= lane.high;
    	                        tLsw ^= lane.low;
    	                    }

    	                    // Temporary values
    	                    var Tx = T[x];
    	                    Tx.high = tMsw;
    	                    Tx.low  = tLsw;
    	                }
    	                for (var x = 0; x < 5; x++) {
    	                    // Shortcuts
    	                    var Tx4 = T[(x + 4) % 5];
    	                    var Tx1 = T[(x + 1) % 5];
    	                    var Tx1Msw = Tx1.high;
    	                    var Tx1Lsw = Tx1.low;

    	                    // Mix surrounding columns
    	                    var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));
    	                    var tLsw = Tx4.low  ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));
    	                    for (var y = 0; y < 5; y++) {
    	                        var lane = state[x + 5 * y];
    	                        lane.high ^= tMsw;
    	                        lane.low  ^= tLsw;
    	                    }
    	                }

    	                // Rho Pi
    	                for (var laneIndex = 1; laneIndex < 25; laneIndex++) {
    	                    // Shortcuts
    	                    var lane = state[laneIndex];
    	                    var laneMsw = lane.high;
    	                    var laneLsw = lane.low;
    	                    var rhoOffset = RHO_OFFSETS[laneIndex];

    	                    // Rotate lanes
    	                    if (rhoOffset < 32) {
    	                        var tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));
    	                        var tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));
    	                    } else /* if (rhoOffset >= 32) */ {
    	                        var tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));
    	                        var tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));
    	                    }

    	                    // Transpose lanes
    	                    var TPiLane = T[PI_INDEXES[laneIndex]];
    	                    TPiLane.high = tMsw;
    	                    TPiLane.low  = tLsw;
    	                }

    	                // Rho pi at x = y = 0
    	                var T0 = T[0];
    	                var state0 = state[0];
    	                T0.high = state0.high;
    	                T0.low  = state0.low;

    	                // Chi
    	                for (var x = 0; x < 5; x++) {
    	                    for (var y = 0; y < 5; y++) {
    	                        // Shortcuts
    	                        var laneIndex = x + 5 * y;
    	                        var lane = state[laneIndex];
    	                        var TLane = T[laneIndex];
    	                        var Tx1Lane = T[((x + 1) % 5) + 5 * y];
    	                        var Tx2Lane = T[((x + 2) % 5) + 5 * y];

    	                        // Mix rows
    	                        lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);
    	                        lane.low  = TLane.low  ^ (~Tx1Lane.low  & Tx2Lane.low);
    	                    }
    	                }

    	                // Iota
    	                var lane = state[0];
    	                var roundConstant = ROUND_CONSTANTS[round];
    	                lane.high ^= roundConstant.high;
    	                lane.low  ^= roundConstant.low;;
    	            }
    	        },

    	        _doFinalize: function () {
    	            // Shortcuts
    	            var data = this._data;
    	            var dataWords = data.words;
    	            var nBitsTotal = this._nDataBytes * 8;
    	            var nBitsLeft = data.sigBytes * 8;
    	            var blockSizeBits = this.blockSize * 32;

    	            // Add padding
    	            dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32);
    	            dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
    	            data.sigBytes = dataWords.length * 4;

    	            // Hash final blocks
    	            this._process();

    	            // Shortcuts
    	            var state = this._state;
    	            var outputLengthBytes = this.cfg.outputLength / 8;
    	            var outputLengthLanes = outputLengthBytes / 8;

    	            // Squeeze
    	            var hashWords = [];
    	            for (var i = 0; i < outputLengthLanes; i++) {
    	                // Shortcuts
    	                var lane = state[i];
    	                var laneMsw = lane.high;
    	                var laneLsw = lane.low;

    	                // Swap endian
    	                laneMsw = (
    	                    (((laneMsw << 8)  | (laneMsw >>> 24)) & 0x00ff00ff) |
    	                    (((laneMsw << 24) | (laneMsw >>> 8))  & 0xff00ff00)
    	                );
    	                laneLsw = (
    	                    (((laneLsw << 8)  | (laneLsw >>> 24)) & 0x00ff00ff) |
    	                    (((laneLsw << 24) | (laneLsw >>> 8))  & 0xff00ff00)
    	                );

    	                // Squeeze state to retrieve hash
    	                hashWords.push(laneLsw);
    	                hashWords.push(laneMsw);
    	            }

    	            // Return final computed hash
    	            return new WordArray.init(hashWords, outputLengthBytes);
    	        },

    	        clone: function () {
    	            var clone = Hasher.clone.call(this);

    	            var state = clone._state = this._state.slice(0);
    	            for (var i = 0; i < 25; i++) {
    	                state[i] = state[i].clone();
    	            }

    	            return clone;
    	        }
    	    });

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.SHA3('message');
    	     *     var hash = CryptoJS.SHA3(wordArray);
    	     */
    	    C.SHA3 = Hasher._createHelper(SHA3);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacSHA3(message, key);
    	     */
    	    C.HmacSHA3 = Hasher._createHmacHelper(SHA3);
    	}(Math));

    	return CryptoJS.SHA3;

    }));
    },{"./core":46,"./x64-core":77}],74:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./x64-core"), _dereq_("./sha512"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./x64-core", "./sha512"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_x64 = C.x64;
    	    var X64Word = C_x64.Word;
    	    var X64WordArray = C_x64.WordArray;
    	    var C_algo = C.algo;
    	    var SHA512 = C_algo.SHA512;

    	    /**
    	     * SHA-384 hash algorithm.
    	     */
    	    var SHA384 = C_algo.SHA384 = SHA512.extend({
    	        _doReset: function () {
    	            this._hash = new X64WordArray.init([
    	                new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507),
    	                new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939),
    	                new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511),
    	                new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4)
    	            ]);
    	        },

    	        _doFinalize: function () {
    	            var hash = SHA512._doFinalize.call(this);

    	            hash.sigBytes -= 16;

    	            return hash;
    	        }
    	    });

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.SHA384('message');
    	     *     var hash = CryptoJS.SHA384(wordArray);
    	     */
    	    C.SHA384 = SHA512._createHelper(SHA384);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacSHA384(message, key);
    	     */
    	    C.HmacSHA384 = SHA512._createHmacHelper(SHA384);
    	}());

    	return CryptoJS.SHA384;

    }));
    },{"./core":46,"./sha512":75,"./x64-core":77}],75:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./x64-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./x64-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var Hasher = C_lib.Hasher;
    	    var C_x64 = C.x64;
    	    var X64Word = C_x64.Word;
    	    var X64WordArray = C_x64.WordArray;
    	    var C_algo = C.algo;

    	    function X64Word_create() {
    	        return X64Word.create.apply(X64Word, arguments);
    	    }

    	    // Constants
    	    var K = [
    	        X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd),
    	        X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc),
    	        X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019),
    	        X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118),
    	        X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe),
    	        X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2),
    	        X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1),
    	        X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694),
    	        X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3),
    	        X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65),
    	        X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483),
    	        X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5),
    	        X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210),
    	        X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4),
    	        X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725),
    	        X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70),
    	        X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926),
    	        X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df),
    	        X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8),
    	        X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b),
    	        X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001),
    	        X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30),
    	        X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910),
    	        X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8),
    	        X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53),
    	        X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8),
    	        X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb),
    	        X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3),
    	        X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60),
    	        X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec),
    	        X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9),
    	        X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b),
    	        X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207),
    	        X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178),
    	        X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6),
    	        X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b),
    	        X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493),
    	        X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c),
    	        X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a),
    	        X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817)
    	    ];

    	    // Reusable objects
    	    var W = [];
    	    (function () {
    	        for (var i = 0; i < 80; i++) {
    	            W[i] = X64Word_create();
    	        }
    	    }());

    	    /**
    	     * SHA-512 hash algorithm.
    	     */
    	    var SHA512 = C_algo.SHA512 = Hasher.extend({
    	        _doReset: function () {
    	            this._hash = new X64WordArray.init([
    	                new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b),
    	                new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1),
    	                new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f),
    	                new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179)
    	            ]);
    	        },

    	        _doProcessBlock: function (M, offset) {
    	            // Shortcuts
    	            var H = this._hash.words;

    	            var H0 = H[0];
    	            var H1 = H[1];
    	            var H2 = H[2];
    	            var H3 = H[3];
    	            var H4 = H[4];
    	            var H5 = H[5];
    	            var H6 = H[6];
    	            var H7 = H[7];

    	            var H0h = H0.high;
    	            var H0l = H0.low;
    	            var H1h = H1.high;
    	            var H1l = H1.low;
    	            var H2h = H2.high;
    	            var H2l = H2.low;
    	            var H3h = H3.high;
    	            var H3l = H3.low;
    	            var H4h = H4.high;
    	            var H4l = H4.low;
    	            var H5h = H5.high;
    	            var H5l = H5.low;
    	            var H6h = H6.high;
    	            var H6l = H6.low;
    	            var H7h = H7.high;
    	            var H7l = H7.low;

    	            // Working variables
    	            var ah = H0h;
    	            var al = H0l;
    	            var bh = H1h;
    	            var bl = H1l;
    	            var ch = H2h;
    	            var cl = H2l;
    	            var dh = H3h;
    	            var dl = H3l;
    	            var eh = H4h;
    	            var el = H4l;
    	            var fh = H5h;
    	            var fl = H5l;
    	            var gh = H6h;
    	            var gl = H6l;
    	            var hh = H7h;
    	            var hl = H7l;

    	            // Rounds
    	            for (var i = 0; i < 80; i++) {
    	                // Shortcut
    	                var Wi = W[i];

    	                // Extend message
    	                if (i < 16) {
    	                    var Wih = Wi.high = M[offset + i * 2]     | 0;
    	                    var Wil = Wi.low  = M[offset + i * 2 + 1] | 0;
    	                } else {
    	                    // Gamma0
    	                    var gamma0x  = W[i - 15];
    	                    var gamma0xh = gamma0x.high;
    	                    var gamma0xl = gamma0x.low;
    	                    var gamma0h  = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7);
    	                    var gamma0l  = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25));

    	                    // Gamma1
    	                    var gamma1x  = W[i - 2];
    	                    var gamma1xh = gamma1x.high;
    	                    var gamma1xl = gamma1x.low;
    	                    var gamma1h  = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6);
    	                    var gamma1l  = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26));

    	                    // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
    	                    var Wi7  = W[i - 7];
    	                    var Wi7h = Wi7.high;
    	                    var Wi7l = Wi7.low;

    	                    var Wi16  = W[i - 16];
    	                    var Wi16h = Wi16.high;
    	                    var Wi16l = Wi16.low;

    	                    var Wil = gamma0l + Wi7l;
    	                    var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0);
    	                    var Wil = Wil + gamma1l;
    	                    var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0);
    	                    var Wil = Wil + Wi16l;
    	                    var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0);

    	                    Wi.high = Wih;
    	                    Wi.low  = Wil;
    	                }

    	                var chh  = (eh & fh) ^ (~eh & gh);
    	                var chl  = (el & fl) ^ (~el & gl);
    	                var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
    	                var majl = (al & bl) ^ (al & cl) ^ (bl & cl);

    	                var sigma0h = ((ah >>> 28) | (al << 4))  ^ ((ah << 30)  | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
    	                var sigma0l = ((al >>> 28) | (ah << 4))  ^ ((al << 30)  | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
    	                var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9));
    	                var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9));

    	                // t1 = h + sigma1 + ch + K[i] + W[i]
    	                var Ki  = K[i];
    	                var Kih = Ki.high;
    	                var Kil = Ki.low;

    	                var t1l = hl + sigma1l;
    	                var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
    	                var t1l = t1l + chl;
    	                var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
    	                var t1l = t1l + Kil;
    	                var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0);
    	                var t1l = t1l + Wil;
    	                var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0);

    	                // t2 = sigma0 + maj
    	                var t2l = sigma0l + majl;
    	                var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);

    	                // Update working variables
    	                hh = gh;
    	                hl = gl;
    	                gh = fh;
    	                gl = fl;
    	                fh = eh;
    	                fl = el;
    	                el = (dl + t1l) | 0;
    	                eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
    	                dh = ch;
    	                dl = cl;
    	                ch = bh;
    	                cl = bl;
    	                bh = ah;
    	                bl = al;
    	                al = (t1l + t2l) | 0;
    	                ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
    	            }

    	            // Intermediate hash value
    	            H0l = H0.low  = (H0l + al);
    	            H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0));
    	            H1l = H1.low  = (H1l + bl);
    	            H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0));
    	            H2l = H2.low  = (H2l + cl);
    	            H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0));
    	            H3l = H3.low  = (H3l + dl);
    	            H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0));
    	            H4l = H4.low  = (H4l + el);
    	            H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0));
    	            H5l = H5.low  = (H5l + fl);
    	            H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0));
    	            H6l = H6.low  = (H6l + gl);
    	            H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0));
    	            H7l = H7.low  = (H7l + hl);
    	            H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0));
    	        },

    	        _doFinalize: function () {
    	            // Shortcuts
    	            var data = this._data;
    	            var dataWords = data.words;

    	            var nBitsTotal = this._nDataBytes * 8;
    	            var nBitsLeft = data.sigBytes * 8;

    	            // Add padding
    	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
    	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000);
    	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal;
    	            data.sigBytes = dataWords.length * 4;

    	            // Hash final blocks
    	            this._process();

    	            // Convert hash to 32-bit word array before returning
    	            var hash = this._hash.toX32();

    	            // Return final computed hash
    	            return hash;
    	        },

    	        clone: function () {
    	            var clone = Hasher.clone.call(this);
    	            clone._hash = this._hash.clone();

    	            return clone;
    	        },

    	        blockSize: 1024/32
    	    });

    	    /**
    	     * Shortcut function to the hasher's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     *
    	     * @return {WordArray} The hash.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hash = CryptoJS.SHA512('message');
    	     *     var hash = CryptoJS.SHA512(wordArray);
    	     */
    	    C.SHA512 = Hasher._createHelper(SHA512);

    	    /**
    	     * Shortcut function to the HMAC's object interface.
    	     *
    	     * @param {WordArray|string} message The message to hash.
    	     * @param {WordArray|string} key The secret key.
    	     *
    	     * @return {WordArray} The HMAC.
    	     *
    	     * @static
    	     *
    	     * @example
    	     *
    	     *     var hmac = CryptoJS.HmacSHA512(message, key);
    	     */
    	    C.HmacSHA512 = Hasher._createHmacHelper(SHA512);
    	}());

    	return CryptoJS.SHA512;

    }));
    },{"./core":46,"./x64-core":77}],76:[function(_dereq_,module,exports){
    ;(function (root, factory, undef) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"), _dereq_("./enc-base64"), _dereq_("./md5"), _dereq_("./evpkdf"), _dereq_("./cipher-core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function () {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var WordArray = C_lib.WordArray;
    	    var BlockCipher = C_lib.BlockCipher;
    	    var C_algo = C.algo;

    	    // Permuted Choice 1 constants
    	    var PC1 = [
    	        57, 49, 41, 33, 25, 17, 9,  1,
    	        58, 50, 42, 34, 26, 18, 10, 2,
    	        59, 51, 43, 35, 27, 19, 11, 3,
    	        60, 52, 44, 36, 63, 55, 47, 39,
    	        31, 23, 15, 7,  62, 54, 46, 38,
    	        30, 22, 14, 6,  61, 53, 45, 37,
    	        29, 21, 13, 5,  28, 20, 12, 4
    	    ];

    	    // Permuted Choice 2 constants
    	    var PC2 = [
    	        14, 17, 11, 24, 1,  5,
    	        3,  28, 15, 6,  21, 10,
    	        23, 19, 12, 4,  26, 8,
    	        16, 7,  27, 20, 13, 2,
    	        41, 52, 31, 37, 47, 55,
    	        30, 40, 51, 45, 33, 48,
    	        44, 49, 39, 56, 34, 53,
    	        46, 42, 50, 36, 29, 32
    	    ];

    	    // Cumulative bit shift constants
    	    var BIT_SHIFTS = [1,  2,  4,  6,  8,  10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28];

    	    // SBOXes and round permutation constants
    	    var SBOX_P = [
    	        {
    	            0x0: 0x808200,
    	            0x10000000: 0x8000,
    	            0x20000000: 0x808002,
    	            0x30000000: 0x2,
    	            0x40000000: 0x200,
    	            0x50000000: 0x808202,
    	            0x60000000: 0x800202,
    	            0x70000000: 0x800000,
    	            0x80000000: 0x202,
    	            0x90000000: 0x800200,
    	            0xa0000000: 0x8200,
    	            0xb0000000: 0x808000,
    	            0xc0000000: 0x8002,
    	            0xd0000000: 0x800002,
    	            0xe0000000: 0x0,
    	            0xf0000000: 0x8202,
    	            0x8000000: 0x0,
    	            0x18000000: 0x808202,
    	            0x28000000: 0x8202,
    	            0x38000000: 0x8000,
    	            0x48000000: 0x808200,
    	            0x58000000: 0x200,
    	            0x68000000: 0x808002,
    	            0x78000000: 0x2,
    	            0x88000000: 0x800200,
    	            0x98000000: 0x8200,
    	            0xa8000000: 0x808000,
    	            0xb8000000: 0x800202,
    	            0xc8000000: 0x800002,
    	            0xd8000000: 0x8002,
    	            0xe8000000: 0x202,
    	            0xf8000000: 0x800000,
    	            0x1: 0x8000,
    	            0x10000001: 0x2,
    	            0x20000001: 0x808200,
    	            0x30000001: 0x800000,
    	            0x40000001: 0x808002,
    	            0x50000001: 0x8200,
    	            0x60000001: 0x200,
    	            0x70000001: 0x800202,
    	            0x80000001: 0x808202,
    	            0x90000001: 0x808000,
    	            0xa0000001: 0x800002,
    	            0xb0000001: 0x8202,
    	            0xc0000001: 0x202,
    	            0xd0000001: 0x800200,
    	            0xe0000001: 0x8002,
    	            0xf0000001: 0x0,
    	            0x8000001: 0x808202,
    	            0x18000001: 0x808000,
    	            0x28000001: 0x800000,
    	            0x38000001: 0x200,
    	            0x48000001: 0x8000,
    	            0x58000001: 0x800002,
    	            0x68000001: 0x2,
    	            0x78000001: 0x8202,
    	            0x88000001: 0x8002,
    	            0x98000001: 0x800202,
    	            0xa8000001: 0x202,
    	            0xb8000001: 0x808200,
    	            0xc8000001: 0x800200,
    	            0xd8000001: 0x0,
    	            0xe8000001: 0x8200,
    	            0xf8000001: 0x808002
    	        },
    	        {
    	            0x0: 0x40084010,
    	            0x1000000: 0x4000,
    	            0x2000000: 0x80000,
    	            0x3000000: 0x40080010,
    	            0x4000000: 0x40000010,
    	            0x5000000: 0x40084000,
    	            0x6000000: 0x40004000,
    	            0x7000000: 0x10,
    	            0x8000000: 0x84000,
    	            0x9000000: 0x40004010,
    	            0xa000000: 0x40000000,
    	            0xb000000: 0x84010,
    	            0xc000000: 0x80010,
    	            0xd000000: 0x0,
    	            0xe000000: 0x4010,
    	            0xf000000: 0x40080000,
    	            0x800000: 0x40004000,
    	            0x1800000: 0x84010,
    	            0x2800000: 0x10,
    	            0x3800000: 0x40004010,
    	            0x4800000: 0x40084010,
    	            0x5800000: 0x40000000,
    	            0x6800000: 0x80000,
    	            0x7800000: 0x40080010,
    	            0x8800000: 0x80010,
    	            0x9800000: 0x0,
    	            0xa800000: 0x4000,
    	            0xb800000: 0x40080000,
    	            0xc800000: 0x40000010,
    	            0xd800000: 0x84000,
    	            0xe800000: 0x40084000,
    	            0xf800000: 0x4010,
    	            0x10000000: 0x0,
    	            0x11000000: 0x40080010,
    	            0x12000000: 0x40004010,
    	            0x13000000: 0x40084000,
    	            0x14000000: 0x40080000,
    	            0x15000000: 0x10,
    	            0x16000000: 0x84010,
    	            0x17000000: 0x4000,
    	            0x18000000: 0x4010,
    	            0x19000000: 0x80000,
    	            0x1a000000: 0x80010,
    	            0x1b000000: 0x40000010,
    	            0x1c000000: 0x84000,
    	            0x1d000000: 0x40004000,
    	            0x1e000000: 0x40000000,
    	            0x1f000000: 0x40084010,
    	            0x10800000: 0x84010,
    	            0x11800000: 0x80000,
    	            0x12800000: 0x40080000,
    	            0x13800000: 0x4000,
    	            0x14800000: 0x40004000,
    	            0x15800000: 0x40084010,
    	            0x16800000: 0x10,
    	            0x17800000: 0x40000000,
    	            0x18800000: 0x40084000,
    	            0x19800000: 0x40000010,
    	            0x1a800000: 0x40004010,
    	            0x1b800000: 0x80010,
    	            0x1c800000: 0x0,
    	            0x1d800000: 0x4010,
    	            0x1e800000: 0x40080010,
    	            0x1f800000: 0x84000
    	        },
    	        {
    	            0x0: 0x104,
    	            0x100000: 0x0,
    	            0x200000: 0x4000100,
    	            0x300000: 0x10104,
    	            0x400000: 0x10004,
    	            0x500000: 0x4000004,
    	            0x600000: 0x4010104,
    	            0x700000: 0x4010000,
    	            0x800000: 0x4000000,
    	            0x900000: 0x4010100,
    	            0xa00000: 0x10100,
    	            0xb00000: 0x4010004,
    	            0xc00000: 0x4000104,
    	            0xd00000: 0x10000,
    	            0xe00000: 0x4,
    	            0xf00000: 0x100,
    	            0x80000: 0x4010100,
    	            0x180000: 0x4010004,
    	            0x280000: 0x0,
    	            0x380000: 0x4000100,
    	            0x480000: 0x4000004,
    	            0x580000: 0x10000,
    	            0x680000: 0x10004,
    	            0x780000: 0x104,
    	            0x880000: 0x4,
    	            0x980000: 0x100,
    	            0xa80000: 0x4010000,
    	            0xb80000: 0x10104,
    	            0xc80000: 0x10100,
    	            0xd80000: 0x4000104,
    	            0xe80000: 0x4010104,
    	            0xf80000: 0x4000000,
    	            0x1000000: 0x4010100,
    	            0x1100000: 0x10004,
    	            0x1200000: 0x10000,
    	            0x1300000: 0x4000100,
    	            0x1400000: 0x100,
    	            0x1500000: 0x4010104,
    	            0x1600000: 0x4000004,
    	            0x1700000: 0x0,
    	            0x1800000: 0x4000104,
    	            0x1900000: 0x4000000,
    	            0x1a00000: 0x4,
    	            0x1b00000: 0x10100,
    	            0x1c00000: 0x4010000,
    	            0x1d00000: 0x104,
    	            0x1e00000: 0x10104,
    	            0x1f00000: 0x4010004,
    	            0x1080000: 0x4000000,
    	            0x1180000: 0x104,
    	            0x1280000: 0x4010100,
    	            0x1380000: 0x0,
    	            0x1480000: 0x10004,
    	            0x1580000: 0x4000100,
    	            0x1680000: 0x100,
    	            0x1780000: 0x4010004,
    	            0x1880000: 0x10000,
    	            0x1980000: 0x4010104,
    	            0x1a80000: 0x10104,
    	            0x1b80000: 0x4000004,
    	            0x1c80000: 0x4000104,
    	            0x1d80000: 0x4010000,
    	            0x1e80000: 0x4,
    	            0x1f80000: 0x10100
    	        },
    	        {
    	            0x0: 0x80401000,
    	            0x10000: 0x80001040,
    	            0x20000: 0x401040,
    	            0x30000: 0x80400000,
    	            0x40000: 0x0,
    	            0x50000: 0x401000,
    	            0x60000: 0x80000040,
    	            0x70000: 0x400040,
    	            0x80000: 0x80000000,
    	            0x90000: 0x400000,
    	            0xa0000: 0x40,
    	            0xb0000: 0x80001000,
    	            0xc0000: 0x80400040,
    	            0xd0000: 0x1040,
    	            0xe0000: 0x1000,
    	            0xf0000: 0x80401040,
    	            0x8000: 0x80001040,
    	            0x18000: 0x40,
    	            0x28000: 0x80400040,
    	            0x38000: 0x80001000,
    	            0x48000: 0x401000,
    	            0x58000: 0x80401040,
    	            0x68000: 0x0,
    	            0x78000: 0x80400000,
    	            0x88000: 0x1000,
    	            0x98000: 0x80401000,
    	            0xa8000: 0x400000,
    	            0xb8000: 0x1040,
    	            0xc8000: 0x80000000,
    	            0xd8000: 0x400040,
    	            0xe8000: 0x401040,
    	            0xf8000: 0x80000040,
    	            0x100000: 0x400040,
    	            0x110000: 0x401000,
    	            0x120000: 0x80000040,
    	            0x130000: 0x0,
    	            0x140000: 0x1040,
    	            0x150000: 0x80400040,
    	            0x160000: 0x80401000,
    	            0x170000: 0x80001040,
    	            0x180000: 0x80401040,
    	            0x190000: 0x80000000,
    	            0x1a0000: 0x80400000,
    	            0x1b0000: 0x401040,
    	            0x1c0000: 0x80001000,
    	            0x1d0000: 0x400000,
    	            0x1e0000: 0x40,
    	            0x1f0000: 0x1000,
    	            0x108000: 0x80400000,
    	            0x118000: 0x80401040,
    	            0x128000: 0x0,
    	            0x138000: 0x401000,
    	            0x148000: 0x400040,
    	            0x158000: 0x80000000,
    	            0x168000: 0x80001040,
    	            0x178000: 0x40,
    	            0x188000: 0x80000040,
    	            0x198000: 0x1000,
    	            0x1a8000: 0x80001000,
    	            0x1b8000: 0x80400040,
    	            0x1c8000: 0x1040,
    	            0x1d8000: 0x80401000,
    	            0x1e8000: 0x400000,
    	            0x1f8000: 0x401040
    	        },
    	        {
    	            0x0: 0x80,
    	            0x1000: 0x1040000,
    	            0x2000: 0x40000,
    	            0x3000: 0x20000000,
    	            0x4000: 0x20040080,
    	            0x5000: 0x1000080,
    	            0x6000: 0x21000080,
    	            0x7000: 0x40080,
    	            0x8000: 0x1000000,
    	            0x9000: 0x20040000,
    	            0xa000: 0x20000080,
    	            0xb000: 0x21040080,
    	            0xc000: 0x21040000,
    	            0xd000: 0x0,
    	            0xe000: 0x1040080,
    	            0xf000: 0x21000000,
    	            0x800: 0x1040080,
    	            0x1800: 0x21000080,
    	            0x2800: 0x80,
    	            0x3800: 0x1040000,
    	            0x4800: 0x40000,
    	            0x5800: 0x20040080,
    	            0x6800: 0x21040000,
    	            0x7800: 0x20000000,
    	            0x8800: 0x20040000,
    	            0x9800: 0x0,
    	            0xa800: 0x21040080,
    	            0xb800: 0x1000080,
    	            0xc800: 0x20000080,
    	            0xd800: 0x21000000,
    	            0xe800: 0x1000000,
    	            0xf800: 0x40080,
    	            0x10000: 0x40000,
    	            0x11000: 0x80,
    	            0x12000: 0x20000000,
    	            0x13000: 0x21000080,
    	            0x14000: 0x1000080,
    	            0x15000: 0x21040000,
    	            0x16000: 0x20040080,
    	            0x17000: 0x1000000,
    	            0x18000: 0x21040080,
    	            0x19000: 0x21000000,
    	            0x1a000: 0x1040000,
    	            0x1b000: 0x20040000,
    	            0x1c000: 0x40080,
    	            0x1d000: 0x20000080,
    	            0x1e000: 0x0,
    	            0x1f000: 0x1040080,
    	            0x10800: 0x21000080,
    	            0x11800: 0x1000000,
    	            0x12800: 0x1040000,
    	            0x13800: 0x20040080,
    	            0x14800: 0x20000000,
    	            0x15800: 0x1040080,
    	            0x16800: 0x80,
    	            0x17800: 0x21040000,
    	            0x18800: 0x40080,
    	            0x19800: 0x21040080,
    	            0x1a800: 0x0,
    	            0x1b800: 0x21000000,
    	            0x1c800: 0x1000080,
    	            0x1d800: 0x40000,
    	            0x1e800: 0x20040000,
    	            0x1f800: 0x20000080
    	        },
    	        {
    	            0x0: 0x10000008,
    	            0x100: 0x2000,
    	            0x200: 0x10200000,
    	            0x300: 0x10202008,
    	            0x400: 0x10002000,
    	            0x500: 0x200000,
    	            0x600: 0x200008,
    	            0x700: 0x10000000,
    	            0x800: 0x0,
    	            0x900: 0x10002008,
    	            0xa00: 0x202000,
    	            0xb00: 0x8,
    	            0xc00: 0x10200008,
    	            0xd00: 0x202008,
    	            0xe00: 0x2008,
    	            0xf00: 0x10202000,
    	            0x80: 0x10200000,
    	            0x180: 0x10202008,
    	            0x280: 0x8,
    	            0x380: 0x200000,
    	            0x480: 0x202008,
    	            0x580: 0x10000008,
    	            0x680: 0x10002000,
    	            0x780: 0x2008,
    	            0x880: 0x200008,
    	            0x980: 0x2000,
    	            0xa80: 0x10002008,
    	            0xb80: 0x10200008,
    	            0xc80: 0x0,
    	            0xd80: 0x10202000,
    	            0xe80: 0x202000,
    	            0xf80: 0x10000000,
    	            0x1000: 0x10002000,
    	            0x1100: 0x10200008,
    	            0x1200: 0x10202008,
    	            0x1300: 0x2008,
    	            0x1400: 0x200000,
    	            0x1500: 0x10000000,
    	            0x1600: 0x10000008,
    	            0x1700: 0x202000,
    	            0x1800: 0x202008,
    	            0x1900: 0x0,
    	            0x1a00: 0x8,
    	            0x1b00: 0x10200000,
    	            0x1c00: 0x2000,
    	            0x1d00: 0x10002008,
    	            0x1e00: 0x10202000,
    	            0x1f00: 0x200008,
    	            0x1080: 0x8,
    	            0x1180: 0x202000,
    	            0x1280: 0x200000,
    	            0x1380: 0x10000008,
    	            0x1480: 0x10002000,
    	            0x1580: 0x2008,
    	            0x1680: 0x10202008,
    	            0x1780: 0x10200000,
    	            0x1880: 0x10202000,
    	            0x1980: 0x10200008,
    	            0x1a80: 0x2000,
    	            0x1b80: 0x202008,
    	            0x1c80: 0x200008,
    	            0x1d80: 0x0,
    	            0x1e80: 0x10000000,
    	            0x1f80: 0x10002008
    	        },
    	        {
    	            0x0: 0x100000,
    	            0x10: 0x2000401,
    	            0x20: 0x400,
    	            0x30: 0x100401,
    	            0x40: 0x2100401,
    	            0x50: 0x0,
    	            0x60: 0x1,
    	            0x70: 0x2100001,
    	            0x80: 0x2000400,
    	            0x90: 0x100001,
    	            0xa0: 0x2000001,
    	            0xb0: 0x2100400,
    	            0xc0: 0x2100000,
    	            0xd0: 0x401,
    	            0xe0: 0x100400,
    	            0xf0: 0x2000000,
    	            0x8: 0x2100001,
    	            0x18: 0x0,
    	            0x28: 0x2000401,
    	            0x38: 0x2100400,
    	            0x48: 0x100000,
    	            0x58: 0x2000001,
    	            0x68: 0x2000000,
    	            0x78: 0x401,
    	            0x88: 0x100401,
    	            0x98: 0x2000400,
    	            0xa8: 0x2100000,
    	            0xb8: 0x100001,
    	            0xc8: 0x400,
    	            0xd8: 0x2100401,
    	            0xe8: 0x1,
    	            0xf8: 0x100400,
    	            0x100: 0x2000000,
    	            0x110: 0x100000,
    	            0x120: 0x2000401,
    	            0x130: 0x2100001,
    	            0x140: 0x100001,
    	            0x150: 0x2000400,
    	            0x160: 0x2100400,
    	            0x170: 0x100401,
    	            0x180: 0x401,
    	            0x190: 0x2100401,
    	            0x1a0: 0x100400,
    	            0x1b0: 0x1,
    	            0x1c0: 0x0,
    	            0x1d0: 0x2100000,
    	            0x1e0: 0x2000001,
    	            0x1f0: 0x400,
    	            0x108: 0x100400,
    	            0x118: 0x2000401,
    	            0x128: 0x2100001,
    	            0x138: 0x1,
    	            0x148: 0x2000000,
    	            0x158: 0x100000,
    	            0x168: 0x401,
    	            0x178: 0x2100400,
    	            0x188: 0x2000001,
    	            0x198: 0x2100000,
    	            0x1a8: 0x0,
    	            0x1b8: 0x2100401,
    	            0x1c8: 0x100401,
    	            0x1d8: 0x400,
    	            0x1e8: 0x2000400,
    	            0x1f8: 0x100001
    	        },
    	        {
    	            0x0: 0x8000820,
    	            0x1: 0x20000,
    	            0x2: 0x8000000,
    	            0x3: 0x20,
    	            0x4: 0x20020,
    	            0x5: 0x8020820,
    	            0x6: 0x8020800,
    	            0x7: 0x800,
    	            0x8: 0x8020000,
    	            0x9: 0x8000800,
    	            0xa: 0x20800,
    	            0xb: 0x8020020,
    	            0xc: 0x820,
    	            0xd: 0x0,
    	            0xe: 0x8000020,
    	            0xf: 0x20820,
    	            0x80000000: 0x800,
    	            0x80000001: 0x8020820,
    	            0x80000002: 0x8000820,
    	            0x80000003: 0x8000000,
    	            0x80000004: 0x8020000,
    	            0x80000005: 0x20800,
    	            0x80000006: 0x20820,
    	            0x80000007: 0x20,
    	            0x80000008: 0x8000020,
    	            0x80000009: 0x820,
    	            0x8000000a: 0x20020,
    	            0x8000000b: 0x8020800,
    	            0x8000000c: 0x0,
    	            0x8000000d: 0x8020020,
    	            0x8000000e: 0x8000800,
    	            0x8000000f: 0x20000,
    	            0x10: 0x20820,
    	            0x11: 0x8020800,
    	            0x12: 0x20,
    	            0x13: 0x800,
    	            0x14: 0x8000800,
    	            0x15: 0x8000020,
    	            0x16: 0x8020020,
    	            0x17: 0x20000,
    	            0x18: 0x0,
    	            0x19: 0x20020,
    	            0x1a: 0x8020000,
    	            0x1b: 0x8000820,
    	            0x1c: 0x8020820,
    	            0x1d: 0x20800,
    	            0x1e: 0x820,
    	            0x1f: 0x8000000,
    	            0x80000010: 0x20000,
    	            0x80000011: 0x800,
    	            0x80000012: 0x8020020,
    	            0x80000013: 0x20820,
    	            0x80000014: 0x20,
    	            0x80000015: 0x8020000,
    	            0x80000016: 0x8000000,
    	            0x80000017: 0x8000820,
    	            0x80000018: 0x8020820,
    	            0x80000019: 0x8000020,
    	            0x8000001a: 0x8000800,
    	            0x8000001b: 0x0,
    	            0x8000001c: 0x20800,
    	            0x8000001d: 0x820,
    	            0x8000001e: 0x20020,
    	            0x8000001f: 0x8020800
    	        }
    	    ];

    	    // Masks that select the SBOX input
    	    var SBOX_MASK = [
    	        0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000,
    	        0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f
    	    ];

    	    /**
    	     * DES block cipher algorithm.
    	     */
    	    var DES = C_algo.DES = BlockCipher.extend({
    	        _doReset: function () {
    	            // Shortcuts
    	            var key = this._key;
    	            var keyWords = key.words;

    	            // Select 56 bits according to PC1
    	            var keyBits = [];
    	            for (var i = 0; i < 56; i++) {
    	                var keyBitPos = PC1[i] - 1;
    	                keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1;
    	            }

    	            // Assemble 16 subkeys
    	            var subKeys = this._subKeys = [];
    	            for (var nSubKey = 0; nSubKey < 16; nSubKey++) {
    	                // Create subkey
    	                var subKey = subKeys[nSubKey] = [];

    	                // Shortcut
    	                var bitShift = BIT_SHIFTS[nSubKey];

    	                // Select 48 bits according to PC2
    	                for (var i = 0; i < 24; i++) {
    	                    // Select from the left 28 key bits
    	                    subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6);

    	                    // Select from the right 28 key bits
    	                    subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6);
    	                }

    	                // Since each subkey is applied to an expanded 32-bit input,
    	                // the subkey can be broken into 8 values scaled to 32-bits,
    	                // which allows the key to be used without expansion
    	                subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31);
    	                for (var i = 1; i < 7; i++) {
    	                    subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3);
    	                }
    	                subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27);
    	            }

    	            // Compute inverse subkeys
    	            var invSubKeys = this._invSubKeys = [];
    	            for (var i = 0; i < 16; i++) {
    	                invSubKeys[i] = subKeys[15 - i];
    	            }
    	        },

    	        encryptBlock: function (M, offset) {
    	            this._doCryptBlock(M, offset, this._subKeys);
    	        },

    	        decryptBlock: function (M, offset) {
    	            this._doCryptBlock(M, offset, this._invSubKeys);
    	        },

    	        _doCryptBlock: function (M, offset, subKeys) {
    	            // Get input
    	            this._lBlock = M[offset];
    	            this._rBlock = M[offset + 1];

    	            // Initial permutation
    	            exchangeLR.call(this, 4,  0x0f0f0f0f);
    	            exchangeLR.call(this, 16, 0x0000ffff);
    	            exchangeRL.call(this, 2,  0x33333333);
    	            exchangeRL.call(this, 8,  0x00ff00ff);
    	            exchangeLR.call(this, 1,  0x55555555);

    	            // Rounds
    	            for (var round = 0; round < 16; round++) {
    	                // Shortcuts
    	                var subKey = subKeys[round];
    	                var lBlock = this._lBlock;
    	                var rBlock = this._rBlock;

    	                // Feistel function
    	                var f = 0;
    	                for (var i = 0; i < 8; i++) {
    	                    f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0];
    	                }
    	                this._lBlock = rBlock;
    	                this._rBlock = lBlock ^ f;
    	            }

    	            // Undo swap from last round
    	            var t = this._lBlock;
    	            this._lBlock = this._rBlock;
    	            this._rBlock = t;

    	            // Final permutation
    	            exchangeLR.call(this, 1,  0x55555555);
    	            exchangeRL.call(this, 8,  0x00ff00ff);
    	            exchangeRL.call(this, 2,  0x33333333);
    	            exchangeLR.call(this, 16, 0x0000ffff);
    	            exchangeLR.call(this, 4,  0x0f0f0f0f);

    	            // Set output
    	            M[offset] = this._lBlock;
    	            M[offset + 1] = this._rBlock;
    	        },

    	        keySize: 64/32,

    	        ivSize: 64/32,

    	        blockSize: 64/32
    	    });

    	    // Swap bits across the left and right words
    	    function exchangeLR(offset, mask) {
    	        var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask;
    	        this._rBlock ^= t;
    	        this._lBlock ^= t << offset;
    	    }

    	    function exchangeRL(offset, mask) {
    	        var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask;
    	        this._lBlock ^= t;
    	        this._rBlock ^= t << offset;
    	    }

    	    /**
    	     * Shortcut functions to the cipher's object interface.
    	     *
    	     * @example
    	     *
    	     *     var ciphertext = CryptoJS.DES.encrypt(message, key, cfg);
    	     *     var plaintext  = CryptoJS.DES.decrypt(ciphertext, key, cfg);
    	     */
    	    C.DES = BlockCipher._createHelper(DES);

    	    /**
    	     * Triple-DES block cipher algorithm.
    	     */
    	    var TripleDES = C_algo.TripleDES = BlockCipher.extend({
    	        _doReset: function () {
    	            // Shortcuts
    	            var key = this._key;
    	            var keyWords = key.words;

    	            // Create DES instances
    	            this._des1 = DES.createEncryptor(WordArray.create(keyWords.slice(0, 2)));
    	            this._des2 = DES.createEncryptor(WordArray.create(keyWords.slice(2, 4)));
    	            this._des3 = DES.createEncryptor(WordArray.create(keyWords.slice(4, 6)));
    	        },

    	        encryptBlock: function (M, offset) {
    	            this._des1.encryptBlock(M, offset);
    	            this._des2.decryptBlock(M, offset);
    	            this._des3.encryptBlock(M, offset);
    	        },

    	        decryptBlock: function (M, offset) {
    	            this._des3.decryptBlock(M, offset);
    	            this._des2.encryptBlock(M, offset);
    	            this._des1.decryptBlock(M, offset);
    	        },

    	        keySize: 192/32,

    	        ivSize: 64/32,

    	        blockSize: 64/32
    	    });

    	    /**
    	     * Shortcut functions to the cipher's object interface.
    	     *
    	     * @example
    	     *
    	     *     var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg);
    	     *     var plaintext  = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg);
    	     */
    	    C.TripleDES = BlockCipher._createHelper(TripleDES);
    	}());

    	return CryptoJS.TripleDES;

    }));
    },{"./cipher-core":45,"./core":46,"./enc-base64":47,"./evpkdf":49,"./md5":54}],77:[function(_dereq_,module,exports){
    ;(function (root, factory) {
    	Eif (typeof exports === "object") {
    		// CommonJS
    		module.exports = exports = factory(_dereq_("./core"));
    	}
    	else if (typeof define === "function" && define.amd) {
    		// AMD
    		define(["./core"], factory);
    	}
    	else {
    		// Global (browser)
    		factory(root.CryptoJS);
    	}
    }(this, function (CryptoJS) {

    	(function (undefined) {
    	    // Shortcuts
    	    var C = CryptoJS;
    	    var C_lib = C.lib;
    	    var Base = C_lib.Base;
    	    var X32WordArray = C_lib.WordArray;

    	    /**
    	     * x64 namespace.
    	     */
    	    var C_x64 = C.x64 = {};

    	    /**
    	     * A 64-bit word.
    	     */
    	    var X64Word = C_x64.Word = Base.extend({
    	        /**
    	         * Initializes a newly created 64-bit word.
    	         *
    	         * @param {number} high The high 32 bits.
    	         * @param {number} low The low 32 bits.
    	         *
    	         * @example
    	         *
    	         *     var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607);
    	         */
    	        init: function (high, low) {
    	            this.high = high;
    	            this.low = low;
    	        }

    	        /**
    	         * Bitwise NOTs this word.
    	         *
    	         * @return {X64Word} A new x64-Word object after negating.
    	         *
    	         * @example
    	         *
    	         *     var negated = x64Word.not();
    	         */
    	        // not: function () {
    	            // var high = ~this.high;
    	            // var low = ~this.low;

    	            // return X64Word.create(high, low);
    	        // },

    	        /**
    	         * Bitwise ANDs this word with the passed word.
    	         *
    	         * @param {X64Word} word The x64-Word to AND with this word.
    	         *
    	         * @return {X64Word} A new x64-Word object after ANDing.
    	         *
    	         * @example
    	         *
    	         *     var anded = x64Word.and(anotherX64Word);
    	         */
    	        // and: function (word) {
    	            // var high = this.high & word.high;
    	            // var low = this.low & word.low;

    	            // return X64Word.create(high, low);
    	        // },

    	        /**
    	         * Bitwise ORs this word with the passed word.
    	         *
    	         * @param {X64Word} word The x64-Word to OR with this word.
    	         *
    	         * @return {X64Word} A new x64-Word object after ORing.
    	         *
    	         * @example
    	         *
    	         *     var ored = x64Word.or(anotherX64Word);
    	         */
    	        // or: function (word) {
    	            // var high = this.high | word.high;
    	            // var low = this.low | word.low;

    	            // return X64Word.create(high, low);
    	        // },

    	        /**
    	         * Bitwise XORs this word with the passed word.
    	         *
    	         * @param {X64Word} word The x64-Word to XOR with this word.
    	         *
    	         * @return {X64Word} A new x64-Word object after XORing.
    	         *
    	         * @example
    	         *
    	         *     var xored = x64Word.xor(anotherX64Word);
    	         */
    	        // xor: function (word) {
    	            // var high = this.high ^ word.high;
    	            // var low = this.low ^ word.low;

    	            // return X64Word.create(high, low);
    	        // },

    	        /**
    	         * Shifts this word n bits to the left.
    	         *
    	         * @param {number} n The number of bits to shift.
    	         *
    	         * @return {X64Word} A new x64-Word object after shifting.
    	         *
    	         * @example
    	         *
    	         *     var shifted = x64Word.shiftL(25);
    	         */
    	        // shiftL: function (n) {
    	            // if (n < 32) {
    	                // var high = (this.high << n) | (this.low >>> (32 - n));
    	                // var low = this.low << n;
    	            // } else {
    	                // var high = this.low << (n - 32);
    	                // var low = 0;
    	            // }

    	            // return X64Word.create(high, low);
    	        // },

    	        /**
    	         * Shifts this word n bits to the right.
    	         *
    	         * @param {number} n The number of bits to shift.
    	         *
    	         * @return {X64Word} A new x64-Word object after shifting.
    	         *
    	         * @example
    	         *
    	         *     var shifted = x64Word.shiftR(7);
    	         */
    	        // shiftR: function (n) {
    	            // if (n < 32) {
    	                // var low = (this.low >>> n) | (this.high << (32 - n));
    	                // var high = this.high >>> n;
    	            // } else {
    	                // var low = this.high >>> (n - 32);
    	                // var high = 0;
    	            // }

    	            // return X64Word.create(high, low);
    	        // },

    	        /**
    	         * Rotates this word n bits to the left.
    	         *
    	         * @param {number} n The number of bits to rotate.
    	         *
    	         * @return {X64Word} A new x64-Word object after rotating.
    	         *
    	         * @example
    	         *
    	         *     var rotated = x64Word.rotL(25);
    	         */
    	        // rotL: function (n) {
    	            // return this.shiftL(n).or(this.shiftR(64 - n));
    	        // },

    	        /**
    	         * Rotates this word n bits to the right.
    	         *
    	         * @param {number} n The number of bits to rotate.
    	         *
    	         * @return {X64Word} A new x64-Word object after rotating.
    	         *
    	         * @example
    	         *
    	         *     var rotated = x64Word.rotR(7);
    	         */
    	        // rotR: function (n) {
    	            // return this.shiftR(n).or(this.shiftL(64 - n));
    	        // },

    	        /**
    	         * Adds this word with the passed word.
    	         *
    	         * @param {X64Word} word The x64-Word to add with this word.
    	         *
    	         * @return {X64Word} A new x64-Word object after adding.
    	         *
    	         * @example
    	         *
    	         *     var added = x64Word.add(anotherX64Word);
    	         */
    	        // add: function (word) {
    	            // var low = (this.low + word.low) | 0;
    	            // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0;
    	            // var high = (this.high + word.high + carry) | 0;

    	            // return X64Word.create(high, low);
    	        // }
    	    });

    	    /**
    	     * An array of 64-bit words.
    	     *
    	     * @property {Array} words The array of CryptoJS.x64.Word objects.
    	     * @property {number} sigBytes The number of significant bytes in this word array.
    	     */
    	    var X64WordArray = C_x64.WordArray = Base.extend({
    	        /**
    	         * Initializes a newly created word array.
    	         *
    	         * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects.
    	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
    	         *
    	         * @example
    	         *
    	         *     var wordArray = CryptoJS.x64.WordArray.create();
    	         *
    	         *     var wordArray = CryptoJS.x64.WordArray.create([
    	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
    	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
    	         *     ]);
    	         *
    	         *     var wordArray = CryptoJS.x64.WordArray.create([
    	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
    	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
    	         *     ], 10);
    	         */
    	        init: function (words, sigBytes) {
    	            words = this.words = words || [];

    	            if (sigBytes != undefined) {
    	                this.sigBytes = sigBytes;
    	            } else {
    	                this.sigBytes = words.length * 8;
    	            }
    	        },

    	        /**
    	         * Converts this 64-bit word array to a 32-bit word array.
    	         *
    	         * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array.
    	         *
    	         * @example
    	         *
    	         *     var x32WordArray = x64WordArray.toX32();
    	         */
    	        toX32: function () {
    	            // Shortcuts
    	            var x64Words = this.words;
    	            var x64WordsLength = x64Words.length;

    	            // Convert
    	            var x32Words = [];
    	            for (var i = 0; i < x64WordsLength; i++) {
    	                var x64Word = x64Words[i];
    	                x32Words.push(x64Word.high);
    	                x32Words.push(x64Word.low);
    	            }

    	            return X32WordArray.create(x32Words, this.sigBytes);
    	        },

    	        /**
    	         * Creates a copy of this word array.
    	         *
    	         * @return {X64WordArray} The clone.
    	         *
    	         * @example
    	         *
    	         *     var clone = x64WordArray.clone();
    	         */
    	        clone: function () {
    	            var clone = Base.clone.call(this);

    	            // Clone "words" array
    	            var words = clone.words = this.words.slice(0);

    	            // Clone each X64Word object
    	            var wordsLength = words.length;
    	            for (var i = 0; i < wordsLength; i++) {
    	                words[i] = words[i].clone();
    	            }

    	            return clone;
    	        }
    	    });
    	}());

    	return CryptoJS;

    }));
    },{"./core":46}],78:[function(_dereq_,module,exports){
    // shim for using process in browser

    var process = module.exports = {};
    var queue = [];
    var draining = false;
    var currentQueue;
    var queueIndex = -1;

    function cleanUpNextTick() {
        draining = false;
        if (currentQueue.length) {
            queue = currentQueue.concat(queue);
        } else {
            queueIndex = -1;
        }
        if (queue.length) {
            drainQueue();
        }
    }

    function drainQueue() {
        Iif (draining) {
            return;
        }
        var timeout = setTimeout(cleanUpNextTick);
        draining = true;

        var len = queue.length;
        while(len) {
            currentQueue = queue;
            queue = [];
            while (++queueIndex < len) {
                Eif (currentQueue) {
                    currentQueue[queueIndex].run();
                }
            }
            queueIndex = -1;
            len = queue.length;
        }
        currentQueue = null;
        draining = false;
        clearTimeout(timeout);
    }

    process.nextTick = function (fun) {
        var args = new Array(arguments.length - 1);
        Iif (arguments.length > 1) {
            for (var i = 1; i < arguments.length; i++) {
                args[i - 1] = arguments[i];
            }
        }
        queue.push(new Item(fun, args));
        if (queue.length === 1 && !draining) {
            setTimeout(drainQueue, 0);
        }
    };

    // v8 likes predictible objects
    function Item(fun, array) {
        this.fun = fun;
        this.array = array;
    }
    Item.prototype.run = function () {
        this.fun.apply(null, this.array);
    };
    process.title = 'browser';
    process.browser = true;
    process.env = {};
    process.argv = [];
    process.version = ''; // empty string to avoid regexp issues
    process.versions = {};

    function noop() {}

    process.on = noop;
    process.addListener = noop;
    process.once = noop;
    process.off = noop;
    process.removeListener = noop;
    process.removeAllListeners = noop;
    process.emit = noop;

    process.binding = function (name) {
        throw new Error('process.binding is not supported');
    };

    process.cwd = function () { return '/' };
    process.chdir = function (dir) {
        throw new Error('process.chdir is not supported');
    };
    process.umask = function() { return 0; };

    },{}],79:[function(_dereq_,module,exports){
    (function (process,global){
    /*!
        localForage -- Offline Storage, Improved
        Version 1.3.0
        https://mozilla.github.io/localForage
        (c) 2013-2015 Mozilla, Apache License 2.0
    */
    (function() {
    var define, requireModule, _dereq_, requirejs;

    (function() {
      var registry = {}, seen = {};

      define = function(name, deps, callback) {
        registry[name] = { deps: deps, callback: callback };
      };

      requirejs = _dereq_ = requireModule = function(name) {
      requirejs._eak_seen = registry;

        if (seen[name]) { return seen[name]; }
        seen[name] = {};

        Iif (!registry[name]) {
          throw new Error("Could not find module " + name);
        }

        var mod = registry[name],
            deps = mod.deps,
            callback = mod.callback,
            reified = [],
            exports;

        for (var i=0, l=deps.length; i<l; i++) {
          if (deps[i] === 'exports') {
            reified.push(exports = {});
          } else {
            reified.push(requireModule(resolve(deps[i])));
          }
        }

        var value = callback.apply(this, reified);
        return seen[name] = exports || value;

        function resolve(child) {
          Iif (child.charAt(0) !== '.') { return child; }
          var parts = child.split("/");
          var parentBase = name.split("/").slice(0, -1);

          for (var i=0, l=parts.length; i<l; i++) {
            var part = parts[i];

            Iif (part === '..') { parentBase.pop(); }
            else if (part === '.') { continue; }
            else { parentBase.push(part); }
          }

          return parentBase.join("/");
        }
      };
    })();

    define("promise/all",
      ["./utils","exports"],
      function(__dependency1__, __exports__) {
        "use strict";
        /* global toString */

        var isArray = __dependency1__.isArray;
        var isFunction = __dependency1__.isFunction;

        /**
          Returns a promise that is fulfilled when all the given promises have been
          fulfilled, or rejected if any of them become rejected. The return promise
          is fulfilled with an array that gives all the values in the order they were
          passed in the `promises` array argument.

          Example:

          ```javascript
          var promise1 = RSVP.resolve(1);
          var promise2 = RSVP.resolve(2);
          var promise3 = RSVP.resolve(3);
          var promises = [ promise1, promise2, promise3 ];

          RSVP.all(promises).then(function(array){
            // The array here would be [ 1, 2, 3 ];
          });
          ```

          If any of the `promises` given to `RSVP.all` are rejected, the first promise
          that is rejected will be given as an argument to the returned promises's
          rejection handler. For example:

          Example:

          ```javascript
          var promise1 = RSVP.resolve(1);
          var promise2 = RSVP.reject(new Error("2"));
          var promise3 = RSVP.reject(new Error("3"));
          var promises = [ promise1, promise2, promise3 ];

          RSVP.all(promises).then(function(array){
            // Code here never runs because there are rejected promises!
          }, function(error) {
            // error.message === "2"
          });
          ```

          @method all
          @for RSVP
          @param {Array} promises
          @param {String} label
          @return {Promise} promise that is fulfilled when all `promises` have been
          fulfilled, or rejected if any of them become rejected.
        */
        function all(promises) {
          /*jshint validthis:true */
          var Promise = this;

          if (!isArray(promises)) {
            throw new TypeError('You must pass an array to all.');
          }

          return new Promise(function(resolve, reject) {
            var results = [], remaining = promises.length,
            promise;

            if (remaining === 0) {
              resolve([]);
            }

            function resolver(index) {
              return function(value) {
                resolveAll(index, value);
              };
            }

            function resolveAll(index, value) {
              results[index] = value;
              if (--remaining === 0) {
                resolve(results);
              }
            }

            for (var i = 0; i < promises.length; i++) {
              promise = promises[i];

              if (promise && isFunction(promise.then)) {
                promise.then(resolver(i), reject);
              } else {
                resolveAll(i, promise);
              }
            }
          });
        }

        __exports__.all = all;
      });
    define("promise/asap",
      ["exports"],
      function(__exports__) {
        "use strict";
        var browserGlobal = (typeof window !== 'undefined') ? window : {};
        var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
        var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this);

        // node
        function useNextTick() {
          return function() {
            process.nextTick(flush);
          };
        }

        function useMutationObserver() {
          var iterations = 0;
          var observer = new BrowserMutationObserver(flush);
          var node = document.createTextNode('');
          observer.observe(node, { characterData: true });

          return function() {
            node.data = (iterations = ++iterations % 2);
          };
        }

        function useSetTimeout() {
          return function() {
            local.setTimeout(flush, 1);
          };
        }

        var queue = [];
        function flush() {
          for (var i = 0; i < queue.length; i++) {
            var tuple = queue[i];
            var callback = tuple[0], arg = tuple[1];
            callback(arg);
          }
          queue = [];
        }

        var scheduleFlush;

        // Decide what async method to use to triggering processing of queued callbacks:
        Iif (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
          scheduleFlush = useNextTick();
        } else Iif (BrowserMutationObserver) {
          scheduleFlush = useMutationObserver();
        } else {
          scheduleFlush = useSetTimeout();
        }

        function asap(callback, arg) {
          var length = queue.push([callback, arg]);
          if (length === 1) {
            // If length is 1, that means that we need to schedule an async flush.
            // If additional callbacks are queued before the queue is flushed, they
            // will be processed by this flush that we are scheduling.
            scheduleFlush();
          }
        }

        __exports__.asap = asap;
      });
    define("promise/config",
      ["exports"],
      function(__exports__) {
        "use strict";
        var config = {
          instrument: false
        };

        function configure(name, value) {
          if (arguments.length === 2) {
            config[name] = value;
          } else {
            return config[name];
          }
        }

        __exports__.config = config;
        __exports__.configure = configure;
      });
    define("promise/polyfill",
      ["./promise","./utils","exports"],
      function(__dependency1__, __dependency2__, __exports__) {
        "use strict";
        /*global self*/
        var RSVPPromise = __dependency1__.Promise;
        var isFunction = __dependency2__.isFunction;

        function polyfill() {
          var local;

          Eif (typeof global !== 'undefined') {
            local = global;
          } else if (typeof window !== 'undefined' && window.document) {
            local = window;
          } else {
            local = self;
          }

          var es6PromiseSupport =
            "Promise" in local &&
            // Some of these methods are missing from
            // Firefox/Chrome experimental implementations
            "resolve" in local.Promise &&
            "reject" in local.Promise &&
            "all" in local.Promise &&
            "race" in local.Promise &&
            // Older version of the spec had a resolver object
            // as the arg rather than a function
            (function() {
              var resolve;
              new local.Promise(function(r) { resolve = r; });
              return isFunction(resolve);
            }());

          Eif (!es6PromiseSupport) {
            local.Promise = RSVPPromise;
          }
        }

        __exports__.polyfill = polyfill;
      });
    define("promise/promise",
      ["./config","./utils","./all","./race","./resolve","./reject","./asap","exports"],
      function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {
        "use strict";
        var config = __dependency1__.config;
        var configure = __dependency1__.configure;
        var objectOrFunction = __dependency2__.objectOrFunction;
        var isFunction = __dependency2__.isFunction;
        var now = __dependency2__.now;
        var all = __dependency3__.all;
        var race = __dependency4__.race;
        var staticResolve = __dependency5__.resolve;
        var staticReject = __dependency6__.reject;
        var asap = __dependency7__.asap;

        var counter = 0;

        config.async = asap; // default async is asap;

        function Promise(resolver) {
          Iif (!isFunction(resolver)) {
            throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
          }

          Iif (!(this instanceof Promise)) {
            throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
          }

          this._subscribers = [];

          invokeResolver(resolver, this);
        }

        function invokeResolver(resolver, promise) {
          function resolvePromise(value) {
            resolve(promise, value);
          }

          function rejectPromise(reason) {
            reject(promise, reason);
          }

          try {
            resolver(resolvePromise, rejectPromise);
          } catch(e) {
            rejectPromise(e);
          }
        }

        function invokeCallback(settled, promise, callback, detail) {
          var hasCallback = isFunction(callback),
              value, error, succeeded, failed;

          if (hasCallback) {
            try {
              value = callback(detail);
              succeeded = true;
            } catch(e) {
              failed = true;
              error = e;
            }
          } else {
            value = detail;
            succeeded = true;
          }

          if (handleThenable(promise, value)) {
            return;
          } else if (hasCallback && succeeded) {
            resolve(promise, value);
          } else Iif (failed) {
            reject(promise, error);
          } else Eif (settled === FULFILLED) {
            resolve(promise, value);
          } else if (settled === REJECTED) {
            reject(promise, value);
          }
        }

        var PENDING   = void 0;
        var SEALED    = 0;
        var FULFILLED = 1;
        var REJECTED  = 2;

        function subscribe(parent, child, onFulfillment, onRejection) {
          var subscribers = parent._subscribers;
          var length = subscribers.length;

          subscribers[length] = child;
          subscribers[length + FULFILLED] = onFulfillment;
          subscribers[length + REJECTED]  = onRejection;
        }

        function publish(promise, settled) {
          var child, callback, subscribers = promise._subscribers, detail = promise._detail;

          for (var i = 0; i < subscribers.length; i += 3) {
            child = subscribers[i];
            callback = subscribers[i + settled];

            invokeCallback(settled, child, callback, detail);
          }

          promise._subscribers = null;
        }

        Promise.prototype = {
          constructor: Promise,

          _state: undefined,
          _detail: undefined,
          _subscribers: undefined,

          then: function(onFulfillment, onRejection) {
            var promise = this;

            var thenPromise = new this.constructor(function() {});

            if (this._state) {
              var callbacks = arguments;
              config.async(function invokePromiseCallback() {
                invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);
              });
            } else {
              subscribe(this, thenPromise, onFulfillment, onRejection);
            }

            return thenPromise;
          },

          'catch': function(onRejection) {
            return this.then(null, onRejection);
          }
        };

        Promise.all = all;
        Promise.race = race;
        Promise.resolve = staticResolve;
        Promise.reject = staticReject;

        function handleThenable(promise, value) {
          var then = null,
          resolved;

          try {
            Iif (promise === value) {
              throw new TypeError("A promises callback cannot return that same promise.");
            }

            if (objectOrFunction(value)) {
              then = value.then;

              if (isFunction(then)) {
                then.call(value, function(val) {
                  Iif (resolved) { return true; }
                  resolved = true;

                  Eif (value !== val) {
                    resolve(promise, val);
                  } else {
                    fulfill(promise, val);
                  }
                }, function(val) {
                  if (resolved) { return true; }
                  resolved = true;

                  reject(promise, val);
                });

                return true;
              }
            }
          } catch (error) {
            if (resolved) { return true; }
            reject(promise, error);
            return true;
          }

          return false;
        }

        function resolve(promise, value) {
          Iif (promise === value) {
            fulfill(promise, value);
          } else Eif (!handleThenable(promise, value)) {
            fulfill(promise, value);
          }
        }

        function fulfill(promise, value) {
          Iif (promise._state !== PENDING) { return; }
          promise._state = SEALED;
          promise._detail = value;

          config.async(publishFulfillment, promise);
        }

        function reject(promise, reason) {
          if (promise._state !== PENDING) { return; }
          promise._state = SEALED;
          promise._detail = reason;

          config.async(publishRejection, promise);
        }

        function publishFulfillment(promise) {
          publish(promise, promise._state = FULFILLED);
        }

        function publishRejection(promise) {
          publish(promise, promise._state = REJECTED);
        }

        __exports__.Promise = Promise;
      });
    define("promise/race",
      ["./utils","exports"],
      function(__dependency1__, __exports__) {
        "use strict";
        /* global toString */
        var isArray = __dependency1__.isArray;

        /**
          `RSVP.race` allows you to watch a series of promises and act as soon as the
          first promise given to the `promises` argument fulfills or rejects.

          Example:

          ```javascript
          var promise1 = new RSVP.Promise(function(resolve, reject){
            setTimeout(function(){
              resolve("promise 1");
            }, 200);
          });

          var promise2 = new RSVP.Promise(function(resolve, reject){
            setTimeout(function(){
              resolve("promise 2");
            }, 100);
          });

          RSVP.race([promise1, promise2]).then(function(result){
            // result === "promise 2" because it was resolved before promise1
            // was resolved.
          });
          ```

          `RSVP.race` is deterministic in that only the state of the first completed
          promise matters. For example, even if other promises given to the `promises`
          array argument are resolved, but the first completed promise has become
          rejected before the other promises became fulfilled, the returned promise
          will become rejected:

          ```javascript
          var promise1 = new RSVP.Promise(function(resolve, reject){
            setTimeout(function(){
              resolve("promise 1");
            }, 200);
          });

          var promise2 = new RSVP.Promise(function(resolve, reject){
            setTimeout(function(){
              reject(new Error("promise 2"));
            }, 100);
          });

          RSVP.race([promise1, promise2]).then(function(result){
            // Code here never runs because there are rejected promises!
          }, function(reason){
            // reason.message === "promise2" because promise 2 became rejected before
            // promise 1 became fulfilled
          });
          ```

          @method race
          @for RSVP
          @param {Array} promises array of promises to observe
          @param {String} label optional string for describing the promise returned.
          Useful for tooling.
          @return {Promise} a promise that becomes fulfilled with the value the first
          completed promises is resolved with if the first completed promise was
          fulfilled, or rejected with the reason that the first completed promise
          was rejected with.
        */
        function race(promises) {
          /*jshint validthis:true */
          var Promise = this;

          if (!isArray(promises)) {
            throw new TypeError('You must pass an array to race.');
          }
          return new Promise(function(resolve, reject) {
            var results = [], promise;

            for (var i = 0; i < promises.length; i++) {
              promise = promises[i];

              if (promise && typeof promise.then === 'function') {
                promise.then(resolve, reject);
              } else {
                resolve(promise);
              }
            }
          });
        }

        __exports__.race = race;
      });
    define("promise/reject",
      ["exports"],
      function(__exports__) {
        "use strict";
        /**
          `RSVP.reject` returns a promise that will become rejected with the passed
          `reason`. `RSVP.reject` is essentially shorthand for the following:

          ```javascript
          var promise = new RSVP.Promise(function(resolve, reject){
            reject(new Error('WHOOPS'));
          });

          promise.then(function(value){
            // Code here doesn't run because the promise is rejected!
          }, function(reason){
            // reason.message === 'WHOOPS'
          });
          ```

          Instead of writing the above, your code now simply becomes the following:

          ```javascript
          var promise = RSVP.reject(new Error('WHOOPS'));

          promise.then(function(value){
            // Code here doesn't run because the promise is rejected!
          }, function(reason){
            // reason.message === 'WHOOPS'
          });
          ```

          @method reject
          @for RSVP
          @param {Any} reason value that the returned promise will be rejected with.
          @param {String} label optional string for identifying the returned promise.
          Useful for tooling.
          @return {Promise} a promise that will become rejected with the given
          `reason`.
        */
        function reject(reason) {
          /*jshint validthis:true */
          var Promise = this;

          return new Promise(function (resolve, reject) {
            reject(reason);
          });
        }

        __exports__.reject = reject;
      });
    define("promise/resolve",
      ["exports"],
      function(__exports__) {
        "use strict";
        function resolve(value) {
          /*jshint validthis:true */
          Iif (value && typeof value === 'object' && value.constructor === this) {
            return value;
          }

          var Promise = this;

          return new Promise(function(resolve) {
            resolve(value);
          });
        }

        __exports__.resolve = resolve;
      });
    define("promise/utils",
      ["exports"],
      function(__exports__) {
        "use strict";
        function objectOrFunction(x) {
          return isFunction(x) || (typeof x === "object" && x !== null);
        }

        function isFunction(x) {
          return typeof x === "function";
        }

        function isArray(x) {
          return Object.prototype.toString.call(x) === "[object Array]";
        }

        // Date.now is not available in browsers < IE9
        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility
        var now = Date.now || function() { return new Date().getTime(); };

        __exports__.objectOrFunction = objectOrFunction;
        __exports__.isFunction = isFunction;
        __exports__.isArray = isArray;
        __exports__.now = now;
      });
    requireModule('promise/polyfill').polyfill();
    }());(function webpackUniversalModuleDefinition(root, factory) {
    	Eif(typeof exports === 'object' && typeof module === 'object')
    		module.exports = factory();
    	else if(typeof define === 'function' && define.amd)
    		define([], factory);
    	else if(typeof exports === 'object')
    		exports["localforage"] = factory();
    	else
    		root["localforage"] = factory();
    })(this, function() {
    return /******/ (function(modules) { // webpackBootstrap
    /******/ 	// The module cache
    /******/ 	var installedModules = {};

    /******/ 	// The require function
    /******/ 	function __webpack_require__(moduleId) {

    /******/ 		// Check if module is in cache
    /******/ 		if(installedModules[moduleId])
    /******/ 			return installedModules[moduleId].exports;

    /******/ 		// Create a new module (and put it into the cache)
    /******/ 		var module = installedModules[moduleId] = {
    /******/ 			exports: {},
    /******/ 			id: moduleId,
    /******/ 			loaded: false
    /******/ 		};

    /******/ 		// Execute the module function
    /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

    /******/ 		// Flag the module as loaded
    /******/ 		module.loaded = true;

    /******/ 		// Return the exports of the module
    /******/ 		return module.exports;
    /******/ 	}

    /******/ 	// expose the modules object (__webpack_modules__)
    /******/ 	__webpack_require__.m = modules;

    /******/ 	// expose the module cache
    /******/ 	__webpack_require__.c = installedModules;

    /******/ 	// __webpack_public_path__
    /******/ 	__webpack_require__.p = "";

    /******/ 	// Load entry module and return exports
    /******/ 	return __webpack_require__(0);
    /******/ })
    /************************************************************************/
    /******/ ([
    /* 0 */
    /***/ function(module, exports, __webpack_require__) {

    	'use strict';

    	exports.__esModule = true;

    	function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

    	(function () {
    	    'use strict';

    	    // Custom drivers are stored here when `defineDriver()` is called.
    	    // They are shared across all instances of localForage.
    	    var CustomDrivers = {};

    	    var DriverType = {
    	        INDEXEDDB: 'asyncStorage',
    	        LOCALSTORAGE: 'localStorageWrapper',
    	        WEBSQL: 'webSQLStorage'
    	    };

    	    var DefaultDriverOrder = [DriverType.INDEXEDDB, DriverType.WEBSQL, DriverType.LOCALSTORAGE];

    	    var LibraryMethods = ['clear', 'getItem', 'iterate', 'key', 'keys', 'length', 'removeItem', 'setItem'];

    	    var DefaultConfig = {
    	        description: '',
    	        driver: DefaultDriverOrder.slice(),
    	        name: 'localforage',
    	        // Default DB size is _JUST UNDER_ 5MB, as it's the highest size
    	        // we can use without a prompt.
    	        size: 4980736,
    	        storeName: 'keyvaluepairs',
    	        version: 1.0
    	    };

    	    // Check to see if IndexedDB is available and if it is the latest
    	    // implementation; it's our preferred backend library. We use "_spec_test"
    	    // as the name of the database because it's not the one we'll operate on,
    	    // but it's useful to make sure its using the right spec.
    	    // See: https://github.com/mozilla/localForage/issues/128
    	    var driverSupport = (function (self) {
    	        // Initialize IndexedDB; fall back to vendor-prefixed versions
    	        // if needed.
    	        var indexedDB = indexedDB || self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.OIndexedDB || self.msIndexedDB;

    	        var result = {};

    	        result[DriverType.WEBSQL] = !!self.openDatabase;
    	        result[DriverType.INDEXEDDB] = !!(function () {
    	            // We mimic PouchDB here; just UA test for Safari (which, as of
    	            // iOS 8/Yosemite, doesn't properly support IndexedDB).
    	            // IndexedDB support is broken and different from Blink's.
    	            // This is faster than the test case (and it's sync), so we just
    	            // do this. *SIGH*
    	            // http://bl.ocks.org/nolanlawson/raw/c83e9039edf2278047e9/
    	            //
    	            // We test for openDatabase because IE Mobile identifies itself
    	            // as Safari. Oh the lulz...
    	            Eif (typeof self.openDatabase !== 'undefined' && self.navigator && self.navigator.userAgent && /Safari/.test(self.navigator.userAgent) && !/Chrome/.test(self.navigator.userAgent)) {
    	                return false;
    	            }
    	            try {
    	                return indexedDB && typeof indexedDB.open === 'function' &&
    	                // Some Samsung/HTC Android 4.0-4.3 devices
    	                // have older IndexedDB specs; if this isn't available
    	                // their IndexedDB is too old for us to use.
    	                // (Replaces the onupgradeneeded test.)
    	                typeof self.IDBKeyRange !== 'undefined';
    	            } catch (e) {
    	                return false;
    	            }
    	        })();

    	        result[DriverType.LOCALSTORAGE] = !!(function () {
    	            try {
    	                return self.localStorage && 'setItem' in self.localStorage && self.localStorage.setItem;
    	            } catch (e) {
    	                return false;
    	            }
    	        })();

    	        return result;
    	    })(this);

    	    var isArray = Array.isArray || function (arg) {
    	        return Object.prototype.toString.call(arg) === '[object Array]';
    	    };

    	    function callWhenReady(localForageInstance, libraryMethod) {
    	        localForageInstance[libraryMethod] = function () {
    	            var _args = arguments;
    	            return localForageInstance.ready().then(function () {
    	                return localForageInstance[libraryMethod].apply(localForageInstance, _args);
    	            });
    	        };
    	    }

    	    function extend() {
    	        for (var i = 1; i < arguments.length; i++) {
    	            var arg = arguments[i];

    	            if (arg) {
    	                for (var key in arg) {
    	                    Eif (arg.hasOwnProperty(key)) {
    	                        if (isArray(arg[key])) {
    	                            arguments[0][key] = arg[key].slice();
    	                        } else {
    	                            arguments[0][key] = arg[key];
    	                        }
    	                    }
    	                }
    	            }
    	        }

    	        return arguments[0];
    	    }

    	    function isLibraryDriver(driverName) {
    	        for (var driver in DriverType) {
    	            if (DriverType.hasOwnProperty(driver) && DriverType[driver] === driverName) {
    	                return true;
    	            }
    	        }

    	        return false;
    	    }

    	    var LocalForage = (function () {
    	        function LocalForage(options) {
    	            _classCallCheck(this, LocalForage);

    	            this.INDEXEDDB = DriverType.INDEXEDDB;
    	            this.LOCALSTORAGE = DriverType.LOCALSTORAGE;
    	            this.WEBSQL = DriverType.WEBSQL;

    	            this._defaultConfig = extend({}, DefaultConfig);
    	            this._config = extend({}, this._defaultConfig, options);
    	            this._driverSet = null;
    	            this._initDriver = null;
    	            this._ready = false;
    	            this._dbInfo = null;

    	            this._wrapLibraryMethodsWithReady();
    	            this.setDriver(this._config.driver);
    	        }

    	        // The actual localForage object that we expose as a module or via a
    	        // global. It's extended by pulling in one of our other libraries.

    	        // Set any config values for localForage; can be called anytime before
    	        // the first API call (e.g. `getItem`, `setItem`).
    	        // We loop through options so we don't overwrite existing config
    	        // values.

    	        LocalForage.prototype.config = function config(options) {
    	            // If the options argument is an object, we use it to set values.
    	            // Otherwise, we return either a specified config value or all
    	            // config values.
    	            Eif (typeof options === 'object') {
    	                // If localforage is ready and fully initialized, we can't set
    	                // any new configuration values. Instead, we return an error.
    	                if (this._ready) {
    	                    return new Error("Can't call config() after localforage " + 'has been used.');
    	                }

    	                for (var i in options) {
    	                    if (i === 'storeName') {
    	                        options[i] = options[i].replace(/\W/g, '_');
    	                    }

    	                    this._config[i] = options[i];
    	                }

    	                // after all config options are set and
    	                // the driver option is used, try setting it
    	                Eif ('driver' in options && options.driver) {
    	                    this.setDriver(this._config.driver);
    	                }

    	                return true;
    	            } else if (typeof options === 'string') {
    	                return this._config[options];
    	            } else {
    	                return this._config;
    	            }
    	        };

    	        // Used to define a custom driver, shared across all instances of
    	        // localForage.

    	        LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) {
    	            var promise = new Promise(function (resolve, reject) {
    	                try {
    	                    var driverName = driverObject._driver;
    	                    var complianceError = new Error('Custom driver not compliant; see ' + 'https://mozilla.github.io/localForage/#definedriver');
    	                    var namingError = new Error('Custom driver name already in use: ' + driverObject._driver);

    	                    // A driver name should be defined and not overlap with the
    	                    // library-defined, default drivers.
    	                    if (!driverObject._driver) {
    	                        reject(complianceError);
    	                        return;
    	                    }
    	                    if (isLibraryDriver(driverObject._driver)) {
    	                        reject(namingError);
    	                        return;
    	                    }

    	                    var customDriverMethods = LibraryMethods.concat('_initStorage');
    	                    for (var i = 0; i < customDriverMethods.length; i++) {
    	                        var customDriverMethod = customDriverMethods[i];
    	                        if (!customDriverMethod || !driverObject[customDriverMethod] || typeof driverObject[customDriverMethod] !== 'function') {
    	                            reject(complianceError);
    	                            return;
    	                        }
    	                    }

    	                    var supportPromise = Promise.resolve(true);
    	                    if ('_support' in driverObject) {
    	                        if (driverObject._support && typeof driverObject._support === 'function') {
    	                            supportPromise = driverObject._support();
    	                        } else {
    	                            supportPromise = Promise.resolve(!!driverObject._support);
    	                        }
    	                    }

    	                    supportPromise.then(function (supportResult) {
    	                        driverSupport[driverName] = supportResult;
    	                        CustomDrivers[driverName] = driverObject;
    	                        resolve();
    	                    }, reject);
    	                } catch (e) {
    	                    reject(e);
    	                }
    	            });

    	            promise.then(callback, errorCallback);
    	            return promise;
    	        };

    	        LocalForage.prototype.driver = function driver() {
    	            return this._driver || null;
    	        };

    	        LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) {
    	            var self = this;
    	            var getDriverPromise = (function () {
    	                Eif (isLibraryDriver(driverName)) {
    	                    switch (driverName) {
    	                        case self.INDEXEDDB:
    	                            return new Promise(function (resolve, reject) {
    	                                resolve(__webpack_require__(1));
    	                            });
    	                        case self.LOCALSTORAGE:
    	                            return new Promise(function (resolve, reject) {
    	                                resolve(__webpack_require__(2));
    	                            });
    	                        case self.WEBSQL:
    	                            return new Promise(function (resolve, reject) {
    	                                resolve(__webpack_require__(4));
    	                            });
    	                    }
    	                } else if (CustomDrivers[driverName]) {
    	                    return Promise.resolve(CustomDrivers[driverName]);
    	                }

    	                return Promise.reject(new Error('Driver not found.'));
    	            })();

    	            getDriverPromise.then(callback, errorCallback);
    	            return getDriverPromise;
    	        };

    	        LocalForage.prototype.getSerializer = function getSerializer(callback) {
    	            var serializerPromise = new Promise(function (resolve, reject) {
    	                resolve(__webpack_require__(3));
    	            });
    	            if (callback && typeof callback === 'function') {
    	                serializerPromise.then(function (result) {
    	                    callback(result);
    	                });
    	            }
    	            return serializerPromise;
    	        };

    	        LocalForage.prototype.ready = function ready(callback) {
    	            var self = this;

    	            var promise = self._driverSet.then(function () {
    	                if (self._ready === null) {
    	                    self._ready = self._initDriver();
    	                }

    	                return self._ready;
    	            });

    	            promise.then(callback, callback);
    	            return promise;
    	        };

    	        LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) {
    	            var self = this;

    	            Iif (!isArray(drivers)) {
    	                drivers = [drivers];
    	            }

    	            var supportedDrivers = this._getSupportedDrivers(drivers);

    	            function setDriverToConfig() {
    	                self._config.driver = self.driver();
    	            }

    	            function initDriver(supportedDrivers) {
    	                return function () {
    	                    var currentDriverIndex = 0;

    	                    function driverPromiseLoop() {
    	                        while (currentDriverIndex < supportedDrivers.length) {
    	                            var driverName = supportedDrivers[currentDriverIndex];
    	                            currentDriverIndex++;

    	                            self._dbInfo = null;
    	                            self._ready = null;

    	                            return self.getDriver(driverName).then(function (driver) {
    	                                self._extend(driver);
    	                                setDriverToConfig();

    	                                self._ready = self._initStorage(self._config);
    	                                return self._ready;
    	                            })['catch'](driverPromiseLoop);
    	                        }

    	                        setDriverToConfig();
    	                        var error = new Error('No available storage method found.');
    	                        self._driverSet = Promise.reject(error);
    	                        return self._driverSet;
    	                    }

    	                    return driverPromiseLoop();
    	                };
    	            }

    	            // There might be a driver initialization in progress
    	            // so wait for it to finish in order to avoid a possible
    	            // race condition to set _dbInfo
    	            var oldDriverSetDone = this._driverSet !== null ? this._driverSet['catch'](function () {
    	                return Promise.resolve();
    	            }) : Promise.resolve();

    	            this._driverSet = oldDriverSetDone.then(function () {
    	                var driverName = supportedDrivers[0];
    	                self._dbInfo = null;
    	                self._ready = null;

    	                return self.getDriver(driverName).then(function (driver) {
    	                    self._driver = driver._driver;
    	                    setDriverToConfig();
    	                    self._wrapLibraryMethodsWithReady();
    	                    self._initDriver = initDriver(supportedDrivers);
    	                });
    	            })['catch'](function () {
    	                setDriverToConfig();
    	                var error = new Error('No available storage method found.');
    	                self._driverSet = Promise.reject(error);
    	                return self._driverSet;
    	            });

    	            this._driverSet.then(callback, errorCallback);
    	            return this._driverSet;
    	        };

    	        LocalForage.prototype.supports = function supports(driverName) {
    	            return !!driverSupport[driverName];
    	        };

    	        LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) {
    	            extend(this, libraryMethodsAndProperties);
    	        };

    	        LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) {
    	            var supportedDrivers = [];
    	            for (var i = 0, len = drivers.length; i < len; i++) {
    	                var driverName = drivers[i];
    	                if (this.supports(driverName)) {
    	                    supportedDrivers.push(driverName);
    	                }
    	            }
    	            return supportedDrivers;
    	        };

    	        LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() {
    	            // Add a stub for each driver API method that delays the call to the
    	            // corresponding driver method until localForage is ready. These stubs
    	            // will be replaced by the driver methods as soon as the driver is
    	            // loaded, so there is no performance impact.
    	            for (var i = 0; i < LibraryMethods.length; i++) {
    	                callWhenReady(this, LibraryMethods[i]);
    	            }
    	        };

    	        LocalForage.prototype.createInstance = function createInstance(options) {
    	            return new LocalForage(options);
    	        };

    	        return LocalForage;
    	    })();

    	    var localForage = new LocalForage();

    	    exports['default'] = localForage;
    	}).call(typeof window !== 'undefined' ? window : self);
    	module.exports = exports['default'];

    /***/ },
    /* 1 */
    /***/ function(module, exports) {

    	// Some code originally from async_storage.js in
    	// [Gaia](https://github.com/mozilla-b2g/gaia).
    	'use strict';

    	exports.__esModule = true;
    	(function () {
    	    'use strict';

    	    var globalObject = this;
    	    // Initialize IndexedDB; fall back to vendor-prefixed versions if needed.
    	    var indexedDB = indexedDB || this.indexedDB || this.webkitIndexedDB || this.mozIndexedDB || this.OIndexedDB || this.msIndexedDB;

    	    // If IndexedDB isn't available, we get outta here!
    	    if (!indexedDB) {
    	        return;
    	    }

    	    var DETECT_BLOB_SUPPORT_STORE = 'local-forage-detect-blob-support';
    	    var supportsBlobs;
    	    var dbContexts;

    	    // Abstracts constructing a Blob object, so it also works in older
    	    // browsers that don't support the native Blob constructor. (i.e.
    	    // old QtWebKit versions, at least).
    	    function _createBlob(parts, properties) {
    	        parts = parts || [];
    	        properties = properties || {};
    	        try {
    	            return new Blob(parts, properties);
    	        } catch (e) {
    	            if (e.name !== 'TypeError') {
    	                throw e;
    	            }
    	            var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;
    	            var builder = new BlobBuilder();
    	            for (var i = 0; i < parts.length; i += 1) {
    	                builder.append(parts[i]);
    	            }
    	            return builder.getBlob(properties.type);
    	        }
    	    }

    	    // Transform a binary string to an array buffer, because otherwise
    	    // weird stuff happens when you try to work with the binary string directly.
    	    // It is known.
    	    // From http://stackoverflow.com/questions/14967647/ (continues on next line)
    	    // encode-decode-image-with-base64-breaks-image (2013-04-21)
    	    function _binStringToArrayBuffer(bin) {
    	        var length = bin.length;
    	        var buf = new ArrayBuffer(length);
    	        var arr = new Uint8Array(buf);
    	        for (var i = 0; i < length; i++) {
    	            arr[i] = bin.charCodeAt(i);
    	        }
    	        return buf;
    	    }

    	    // Fetch a blob using ajax. This reveals bugs in Chrome < 43.
    	    // For details on all this junk:
    	    // https://github.com/nolanlawson/state-of-binary-data-in-the-browser#readme
    	    function _blobAjax(url) {
    	        return new Promise(function (resolve, reject) {
    	            var xhr = new XMLHttpRequest();
    	            xhr.open('GET', url);
    	            xhr.withCredentials = true;
    	            xhr.responseType = 'arraybuffer';

    	            xhr.onreadystatechange = function () {
    	                if (xhr.readyState !== 4) {
    	                    return;
    	                }
    	                if (xhr.status === 200) {
    	                    return resolve({
    	                        response: xhr.response,
    	                        type: xhr.getResponseHeader('Content-Type')
    	                    });
    	                }
    	                reject({ status: xhr.status, response: xhr.response });
    	            };
    	            xhr.send();
    	        });
    	    }

    	    //
    	    // Detect blob support. Chrome didn't support it until version 38.
    	    // In version 37 they had a broken version where PNGs (and possibly
    	    // other binary types) aren't stored correctly, because when you fetch
    	    // them, the content type is always null.
    	    //
    	    // Furthermore, they have some outstanding bugs where blobs occasionally
    	    // are read by FileReader as null, or by ajax as 404s.
    	    //
    	    // Sadly we use the 404 bug to detect the FileReader bug, so if they
    	    // get fixed independently and released in different versions of Chrome,
    	    // then the bug could come back. So it's worthwhile to watch these issues:
    	    // 404 bug: https://code.google.com/p/chromium/issues/detail?id=447916
    	    // FileReader bug: https://code.google.com/p/chromium/issues/detail?id=447836
    	    //
    	    function _checkBlobSupportWithoutCaching(idb) {
    	        return new Promise(function (resolve, reject) {
    	            var blob = _createBlob([''], { type: 'image/png' });
    	            var txn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');
    	            txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key');
    	            txn.oncomplete = function () {
    	                // have to do it in a separate transaction, else the correct
    	                // content type is always returned
    	                var blobTxn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');
    	                var getBlobReq = blobTxn.objectStore(DETECT_BLOB_SUPPORT_STORE).get('key');
    	                getBlobReq.onerror = reject;
    	                getBlobReq.onsuccess = function (e) {

    	                    var storedBlob = e.target.result;
    	                    var url = URL.createObjectURL(storedBlob);

    	                    _blobAjax(url).then(function (res) {
    	                        resolve(!!(res && res.type === 'image/png'));
    	                    }, function () {
    	                        resolve(false);
    	                    }).then(function () {
    	                        URL.revokeObjectURL(url);
    	                    });
    	                };
    	            };
    	        })['catch'](function () {
    	            return false; // error, so assume unsupported
    	        });
    	    }

    	    function _checkBlobSupport(idb) {
    	        if (typeof supportsBlobs === 'boolean') {
    	            return Promise.resolve(supportsBlobs);
    	        }
    	        return _checkBlobSupportWithoutCaching(idb).then(function (value) {
    	            supportsBlobs = value;
    	            return supportsBlobs;
    	        });
    	    }

    	    // encode a blob for indexeddb engines that don't support blobs
    	    function _encodeBlob(blob) {
    	        return new Promise(function (resolve, reject) {
    	            var reader = new FileReader();
    	            reader.onerror = reject;
    	            reader.onloadend = function (e) {
    	                var base64 = btoa(e.target.result || '');
    	                resolve({
    	                    __local_forage_encoded_blob: true,
    	                    data: base64,
    	                    type: blob.type
    	                });
    	            };
    	            reader.readAsBinaryString(blob);
    	        });
    	    }

    	    // decode an encoded blob
    	    function _decodeBlob(encodedBlob) {
    	        var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));
    	        return _createBlob([arrayBuff], { type: encodedBlob.type });
    	    }

    	    // is this one of our fancy encoded blobs?
    	    function _isEncodedBlob(value) {
    	        return value && value.__local_forage_encoded_blob;
    	    }

    	    // Open the IndexedDB database (automatically creates one if one didn't
    	    // previously exist), using any options set in the config.
    	    function _initStorage(options) {
    	        var self = this;
    	        var dbInfo = {
    	            db: null
    	        };

    	        if (options) {
    	            for (var i in options) {
    	                dbInfo[i] = options[i];
    	            }
    	        }

    	        // Initialize a singleton container for all running localForages.
    	        if (!dbContexts) {
    	            dbContexts = {};
    	        }

    	        // Get the current context of the database;
    	        var dbContext = dbContexts[dbInfo.name];

    	        // ...or create a new context.
    	        if (!dbContext) {
    	            dbContext = {
    	                // Running localForages sharing a database.
    	                forages: [],
    	                // Shared database.
    	                db: null
    	            };
    	            // Register the new context in the global container.
    	            dbContexts[dbInfo.name] = dbContext;
    	        }

    	        // Register itself as a running localForage in the current context.
    	        dbContext.forages.push(this);

    	        // Create an array of readiness of the related localForages.
    	        var readyPromises = [];

    	        function ignoreErrors() {
    	            // Don't handle errors here,
    	            // just makes sure related localForages aren't pending.
    	            return Promise.resolve();
    	        }

    	        for (var j = 0; j < dbContext.forages.length; j++) {
    	            var forage = dbContext.forages[j];
    	            if (forage !== this) {
    	                // Don't wait for itself...
    	                readyPromises.push(forage.ready()['catch'](ignoreErrors));
    	            }
    	        }

    	        // Take a snapshot of the related localForages.
    	        var forages = dbContext.forages.slice(0);

    	        // Initialize the connection process only when
    	        // all the related localForages aren't pending.
    	        return Promise.all(readyPromises).then(function () {
    	            dbInfo.db = dbContext.db;
    	            // Get the connection or open a new one without upgrade.
    	            return _getOriginalConnection(dbInfo);
    	        }).then(function (db) {
    	            dbInfo.db = db;
    	            if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) {
    	                // Reopen the database for upgrading.
    	                return _getUpgradedConnection(dbInfo);
    	            }
    	            return db;
    	        }).then(function (db) {
    	            dbInfo.db = dbContext.db = db;
    	            self._dbInfo = dbInfo;
    	            // Share the final connection amongst related localForages.
    	            for (var k in forages) {
    	                var forage = forages[k];
    	                if (forage !== self) {
    	                    // Self is already up-to-date.
    	                    forage._dbInfo.db = dbInfo.db;
    	                    forage._dbInfo.version = dbInfo.version;
    	                }
    	            }
    	        });
    	    }

    	    function _getOriginalConnection(dbInfo) {
    	        return _getConnection(dbInfo, false);
    	    }

    	    function _getUpgradedConnection(dbInfo) {
    	        return _getConnection(dbInfo, true);
    	    }

    	    function _getConnection(dbInfo, upgradeNeeded) {
    	        return new Promise(function (resolve, reject) {
    	            if (dbInfo.db) {
    	                if (upgradeNeeded) {
    	                    dbInfo.db.close();
    	                } else {
    	                    return resolve(dbInfo.db);
    	                }
    	            }

    	            var dbArgs = [dbInfo.name];

    	            if (upgradeNeeded) {
    	                dbArgs.push(dbInfo.version);
    	            }

    	            var openreq = indexedDB.open.apply(indexedDB, dbArgs);

    	            if (upgradeNeeded) {
    	                openreq.onupgradeneeded = function (e) {
    	                    var db = openreq.result;
    	                    try {
    	                        db.createObjectStore(dbInfo.storeName);
    	                        if (e.oldVersion <= 1) {
    	                            // Added when support for blob shims was added
    	                            db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);
    	                        }
    	                    } catch (ex) {
    	                        if (ex.name === 'ConstraintError') {
    	                            globalObject.console.warn('The database "' + dbInfo.name + '"' + ' has been upgraded from version ' + e.oldVersion + ' to version ' + e.newVersion + ', but the storage "' + dbInfo.storeName + '" already exists.');
    	                        } else {
    	                            throw ex;
    	                        }
    	                    }
    	                };
    	            }

    	            openreq.onerror = function () {
    	                reject(openreq.error);
    	            };

    	            openreq.onsuccess = function () {
    	                resolve(openreq.result);
    	            };
    	        });
    	    }

    	    function _isUpgradeNeeded(dbInfo, defaultVersion) {
    	        if (!dbInfo.db) {
    	            return true;
    	        }

    	        var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);
    	        var isDowngrade = dbInfo.version < dbInfo.db.version;
    	        var isUpgrade = dbInfo.version > dbInfo.db.version;

    	        if (isDowngrade) {
    	            // If the version is not the default one
    	            // then warn for impossible downgrade.
    	            if (dbInfo.version !== defaultVersion) {
    	                globalObject.console.warn('The database "' + dbInfo.name + '"' + ' can\'t be downgraded from version ' + dbInfo.db.version + ' to version ' + dbInfo.version + '.');
    	            }
    	            // Align the versions to prevent errors.
    	            dbInfo.version = dbInfo.db.version;
    	        }

    	        if (isUpgrade || isNewStore) {
    	            // If the store is new then increment the version (if needed).
    	            // This will trigger an "upgradeneeded" event which is required
    	            // for creating a store.
    	            if (isNewStore) {
    	                var incVersion = dbInfo.db.version + 1;
    	                if (incVersion > dbInfo.version) {
    	                    dbInfo.version = incVersion;
    	                }
    	            }

    	            return true;
    	        }

    	        return false;
    	    }

    	    function getItem(key, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        if (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);
    	                var req = store.get(key);

    	                req.onsuccess = function () {
    	                    var value = req.result;
    	                    if (value === undefined) {
    	                        value = null;
    	                    }
    	                    if (_isEncodedBlob(value)) {
    	                        value = _decodeBlob(value);
    	                    }
    	                    resolve(value);
    	                };

    	                req.onerror = function () {
    	                    reject(req.error);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Iterate over all items stored in database.
    	    function iterate(iterator, callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);

    	                var req = store.openCursor();
    	                var iterationNumber = 1;

    	                req.onsuccess = function () {
    	                    var cursor = req.result;

    	                    if (cursor) {
    	                        var value = cursor.value;
    	                        if (_isEncodedBlob(value)) {
    	                            value = _decodeBlob(value);
    	                        }
    	                        var result = iterator(value, cursor.key, iterationNumber++);

    	                        if (result !== void 0) {
    	                            resolve(result);
    	                        } else {
    	                            cursor['continue']();
    	                        }
    	                    } else {
    	                        resolve();
    	                    }
    	                };

    	                req.onerror = function () {
    	                    reject(req.error);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);

    	        return promise;
    	    }

    	    function setItem(key, value, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        if (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = new Promise(function (resolve, reject) {
    	            var dbInfo;
    	            self.ready().then(function () {
    	                dbInfo = self._dbInfo;
    	                return _checkBlobSupport(dbInfo.db);
    	            }).then(function (blobSupport) {
    	                if (!blobSupport && value instanceof Blob) {
    	                    return _encodeBlob(value);
    	                }
    	                return value;
    	            }).then(function (value) {
    	                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
    	                var store = transaction.objectStore(dbInfo.storeName);

    	                // The reason we don't _save_ null is because IE 10 does
    	                // not support saving the `null` type in IndexedDB. How
    	                // ironic, given the bug below!
    	                // See: https://github.com/mozilla/localForage/issues/161
    	                if (value === null) {
    	                    value = undefined;
    	                }

    	                var req = store.put(value, key);
    	                transaction.oncomplete = function () {
    	                    // Cast to undefined so the value passed to
    	                    // callback/promise is the same as what one would get out
    	                    // of `getItem()` later. This leads to some weirdness
    	                    // (setItem('foo', undefined) will return `null`), but
    	                    // it's not my fault localStorage is our baseline and that
    	                    // it's weird.
    	                    if (value === undefined) {
    	                        value = null;
    	                    }

    	                    resolve(value);
    	                };
    	                transaction.onabort = transaction.onerror = function () {
    	                    var err = req.error ? req.error : req.transaction.error;
    	                    reject(err);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function removeItem(key, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        if (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
    	                var store = transaction.objectStore(dbInfo.storeName);

    	                // We use a Grunt task to make this safe for IE and some
    	                // versions of Android (including those used by Cordova).
    	                // Normally IE won't like `['delete']()` and will insist on
    	                // using `['delete']()`, but we have a build step that
    	                // fixes this for us now.
    	                var req = store['delete'](key);
    	                transaction.oncomplete = function () {
    	                    resolve();
    	                };

    	                transaction.onerror = function () {
    	                    reject(req.error);
    	                };

    	                // The request will be also be aborted if we've exceeded our storage
    	                // space.
    	                transaction.onabort = function () {
    	                    var err = req.error ? req.error : req.transaction.error;
    	                    reject(err);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function clear(callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
    	                var store = transaction.objectStore(dbInfo.storeName);
    	                var req = store.clear();

    	                transaction.oncomplete = function () {
    	                    resolve();
    	                };

    	                transaction.onabort = transaction.onerror = function () {
    	                    var err = req.error ? req.error : req.transaction.error;
    	                    reject(err);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function length(callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);
    	                var req = store.count();

    	                req.onsuccess = function () {
    	                    resolve(req.result);
    	                };

    	                req.onerror = function () {
    	                    reject(req.error);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function key(n, callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            if (n < 0) {
    	                resolve(null);

    	                return;
    	            }

    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);

    	                var advanced = false;
    	                var req = store.openCursor();
    	                req.onsuccess = function () {
    	                    var cursor = req.result;
    	                    if (!cursor) {
    	                        // this means there weren't enough keys
    	                        resolve(null);

    	                        return;
    	                    }

    	                    if (n === 0) {
    	                        // We have the first key, return it if that's what they
    	                        // wanted.
    	                        resolve(cursor.key);
    	                    } else {
    	                        if (!advanced) {
    	                            // Otherwise, ask the cursor to skip ahead n
    	                            // records.
    	                            advanced = true;
    	                            cursor.advance(n);
    	                        } else {
    	                            // When we get here, we've got the nth key.
    	                            resolve(cursor.key);
    	                        }
    	                    }
    	                };

    	                req.onerror = function () {
    	                    reject(req.error);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function keys(callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);

    	                var req = store.openCursor();
    	                var keys = [];

    	                req.onsuccess = function () {
    	                    var cursor = req.result;

    	                    if (!cursor) {
    	                        resolve(keys);
    	                        return;
    	                    }

    	                    keys.push(cursor.key);
    	                    cursor['continue']();
    	                };

    	                req.onerror = function () {
    	                    reject(req.error);
    	                };
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function executeCallback(promise, callback) {
    	        if (callback) {
    	            promise.then(function (result) {
    	                callback(null, result);
    	            }, function (error) {
    	                callback(error);
    	            });
    	        }
    	    }

    	    var asyncStorage = {
    	        _driver: 'asyncStorage',
    	        _initStorage: _initStorage,
    	        iterate: iterate,
    	        getItem: getItem,
    	        setItem: setItem,
    	        removeItem: removeItem,
    	        clear: clear,
    	        length: length,
    	        key: key,
    	        keys: keys
    	    };

    	    exports['default'] = asyncStorage;
    	}).call(typeof window !== 'undefined' ? window : self);
    	module.exports = exports['default'];

    /***/ },
    /* 2 */
    /***/ function(module, exports, __webpack_require__) {

    	// If IndexedDB isn't available, we'll fall back to localStorage.
    	// Note that this will have considerable performance and storage
    	// side-effects (all data will be serialized on save and only data that
    	// can be converted to a string via `JSON.stringify()` will be saved).
    	'use strict';

    	exports.__esModule = true;
    	(function () {
    	    'use strict';

    	    var globalObject = this;
    	    var localStorage = null;

    	    // If the app is running inside a Google Chrome packaged webapp, or some
    	    // other context where localStorage isn't available, we don't use
    	    // localStorage. This feature detection is preferred over the old
    	    // `if (window.chrome && window.chrome.runtime)` code.
    	    // See: https://github.com/mozilla/localForage/issues/68
    	    try {
    	        // If localStorage isn't available, we get outta here!
    	        // This should be inside a try catch
    	        if (!this.localStorage || !('setItem' in this.localStorage)) {
    	            return;
    	        }
    	        // Initialize localStorage and create a variable to use throughout
    	        // the code.
    	        localStorage = this.localStorage;
    	    } catch (e) {
    	        return;
    	    }

    	    // Config the localStorage backend, using options set in the config.
    	    function _initStorage(options) {
    	        var self = this;
    	        var dbInfo = {};
    	        if (options) {
    	            for (var i in options) {
    	                dbInfo[i] = options[i];
    	            }
    	        }

    	        dbInfo.keyPrefix = dbInfo.name + '/';

    	        if (dbInfo.storeName !== self._defaultConfig.storeName) {
    	            dbInfo.keyPrefix += dbInfo.storeName + '/';
    	        }

    	        self._dbInfo = dbInfo;

    	        return new Promise(function (resolve, reject) {
    	            resolve(__webpack_require__(3));
    	        }).then(function (lib) {
    	            dbInfo.serializer = lib;
    	            return Promise.resolve();
    	        });
    	    }

    	    // Remove all keys from the datastore, effectively destroying all data in
    	    // the app's key/value store!
    	    function clear(callback) {
    	        var self = this;
    	        var promise = self.ready().then(function () {
    	            var keyPrefix = self._dbInfo.keyPrefix;

    	            for (var i = localStorage.length - 1; i >= 0; i--) {
    	                var key = localStorage.key(i);

    	                if (key.indexOf(keyPrefix) === 0) {
    	                    localStorage.removeItem(key);
    	                }
    	            }
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Retrieve an item from the store. Unlike the original async_storage
    	    // library in Gaia, we don't modify return values at all. If a key's value
    	    // is `undefined`, we pass that value to the callback function.
    	    function getItem(key, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        if (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = self.ready().then(function () {
    	            var dbInfo = self._dbInfo;
    	            var result = localStorage.getItem(dbInfo.keyPrefix + key);

    	            // If a result was found, parse it from the serialized
    	            // string into a JS object. If result isn't truthy, the key
    	            // is likely undefined and we'll pass it straight to the
    	            // callback.
    	            if (result) {
    	                result = dbInfo.serializer.deserialize(result);
    	            }

    	            return result;
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Iterate over all items in the store.
    	    function iterate(iterator, callback) {
    	        var self = this;

    	        var promise = self.ready().then(function () {
    	            var dbInfo = self._dbInfo;
    	            var keyPrefix = dbInfo.keyPrefix;
    	            var keyPrefixLength = keyPrefix.length;
    	            var length = localStorage.length;

    	            // We use a dedicated iterator instead of the `i` variable below
    	            // so other keys we fetch in localStorage aren't counted in
    	            // the `iterationNumber` argument passed to the `iterate()`
    	            // callback.
    	            //
    	            // See: github.com/mozilla/localForage/pull/435#discussion_r38061530
    	            var iterationNumber = 1;

    	            for (var i = 0; i < length; i++) {
    	                var key = localStorage.key(i);
    	                if (key.indexOf(keyPrefix) !== 0) {
    	                    continue;
    	                }
    	                var value = localStorage.getItem(key);

    	                // If a result was found, parse it from the serialized
    	                // string into a JS object. If result isn't truthy, the
    	                // key is likely undefined and we'll pass it straight
    	                // to the iterator.
    	                if (value) {
    	                    value = dbInfo.serializer.deserialize(value);
    	                }

    	                value = iterator(value, key.substring(keyPrefixLength), iterationNumber++);

    	                if (value !== void 0) {
    	                    return value;
    	                }
    	            }
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Same as localStorage's key() method, except takes a callback.
    	    function key(n, callback) {
    	        var self = this;
    	        var promise = self.ready().then(function () {
    	            var dbInfo = self._dbInfo;
    	            var result;
    	            try {
    	                result = localStorage.key(n);
    	            } catch (error) {
    	                result = null;
    	            }

    	            // Remove the prefix from the key, if a key is found.
    	            if (result) {
    	                result = result.substring(dbInfo.keyPrefix.length);
    	            }

    	            return result;
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function keys(callback) {
    	        var self = this;
    	        var promise = self.ready().then(function () {
    	            var dbInfo = self._dbInfo;
    	            var length = localStorage.length;
    	            var keys = [];

    	            for (var i = 0; i < length; i++) {
    	                if (localStorage.key(i).indexOf(dbInfo.keyPrefix) === 0) {
    	                    keys.push(localStorage.key(i).substring(dbInfo.keyPrefix.length));
    	                }
    	            }

    	            return keys;
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Supply the number of keys in the datastore to the callback function.
    	    function length(callback) {
    	        var self = this;
    	        var promise = self.keys().then(function (keys) {
    	            return keys.length;
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Remove an item from the store, nice and simple.
    	    function removeItem(key, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        if (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = self.ready().then(function () {
    	            var dbInfo = self._dbInfo;
    	            localStorage.removeItem(dbInfo.keyPrefix + key);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Set a key's value and run an optional callback once the value is set.
    	    // Unlike Gaia's implementation, the callback function is passed the value,
    	    // in case you want to operate on that value only after you're sure it
    	    // saved, or something like that.
    	    function setItem(key, value, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        if (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = self.ready().then(function () {
    	            // Convert undefined values to null.
    	            // https://github.com/mozilla/localForage/pull/42
    	            if (value === undefined) {
    	                value = null;
    	            }

    	            // Save the original value to pass to the callback.
    	            var originalValue = value;

    	            return new Promise(function (resolve, reject) {
    	                var dbInfo = self._dbInfo;
    	                dbInfo.serializer.serialize(value, function (value, error) {
    	                    if (error) {
    	                        reject(error);
    	                    } else {
    	                        try {
    	                            localStorage.setItem(dbInfo.keyPrefix + key, value);
    	                            resolve(originalValue);
    	                        } catch (e) {
    	                            // localStorage capacity exceeded.
    	                            // TODO: Make this a specific error/event.
    	                            if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
    	                                reject(e);
    	                            }
    	                            reject(e);
    	                        }
    	                    }
    	                });
    	            });
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function executeCallback(promise, callback) {
    	        if (callback) {
    	            promise.then(function (result) {
    	                callback(null, result);
    	            }, function (error) {
    	                callback(error);
    	            });
    	        }
    	    }

    	    var localStorageWrapper = {
    	        _driver: 'localStorageWrapper',
    	        _initStorage: _initStorage,
    	        // Default API, from Gaia/localStorage.
    	        iterate: iterate,
    	        getItem: getItem,
    	        setItem: setItem,
    	        removeItem: removeItem,
    	        clear: clear,
    	        length: length,
    	        key: key,
    	        keys: keys
    	    };

    	    exports['default'] = localStorageWrapper;
    	}).call(typeof window !== 'undefined' ? window : self);
    	module.exports = exports['default'];

    /***/ },
    /* 3 */
    /***/ function(module, exports) {

    	'use strict';

    	exports.__esModule = true;
    	(function () {
    	    'use strict';

    	    // Sadly, the best way to save binary data in WebSQL/localStorage is serializing
    	    // it to Base64, so this is how we store it to prevent very strange errors with less
    	    // verbose ways of binary <-> string data storage.
    	    var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

    	    var BLOB_TYPE_PREFIX = '~~local_forage_type~';
    	    var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;

    	    var SERIALIZED_MARKER = '__lfsc__:';
    	    var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;

    	    // OMG the serializations!
    	    var TYPE_ARRAYBUFFER = 'arbf';
    	    var TYPE_BLOB = 'blob';
    	    var TYPE_INT8ARRAY = 'si08';
    	    var TYPE_UINT8ARRAY = 'ui08';
    	    var TYPE_UINT8CLAMPEDARRAY = 'uic8';
    	    var TYPE_INT16ARRAY = 'si16';
    	    var TYPE_INT32ARRAY = 'si32';
    	    var TYPE_UINT16ARRAY = 'ur16';
    	    var TYPE_UINT32ARRAY = 'ui32';
    	    var TYPE_FLOAT32ARRAY = 'fl32';
    	    var TYPE_FLOAT64ARRAY = 'fl64';
    	    var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;

    	    // Get out of our habit of using `window` inline, at least.
    	    var globalObject = this;

    	    // Abstracts constructing a Blob object, so it also works in older
    	    // browsers that don't support the native Blob constructor. (i.e.
    	    // old QtWebKit versions, at least).
    	    function _createBlob(parts, properties) {
    	        parts = parts || [];
    	        properties = properties || {};

    	        try {
    	            return new Blob(parts, properties);
    	        } catch (err) {
    	            if (err.name !== 'TypeError') {
    	                throw err;
    	            }

    	            var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;

    	            var builder = new BlobBuilder();
    	            for (var i = 0; i < parts.length; i += 1) {
    	                builder.append(parts[i]);
    	            }

    	            return builder.getBlob(properties.type);
    	        }
    	    }

    	    // Serialize a value, afterwards executing a callback (which usually
    	    // instructs the `setItem()` callback/promise to be executed). This is how
    	    // we store binary data with localStorage.
    	    function serialize(value, callback) {
    	        var valueString = '';
    	        Eif (value) {
    	            valueString = value.toString();
    	        }

    	        // Cannot use `value instanceof ArrayBuffer` or such here, as these
    	        // checks fail when running the tests using casper.js...
    	        //
    	        // TODO: See why those tests fail and use a better solution.
    	        Iif (value && (value.toString() === '[object ArrayBuffer]' || value.buffer && value.buffer.toString() === '[object ArrayBuffer]')) {
    	            // Convert binary arrays to a string and prefix the string with
    	            // a special marker.
    	            var buffer;
    	            var marker = SERIALIZED_MARKER;

    	            if (value instanceof ArrayBuffer) {
    	                buffer = value;
    	                marker += TYPE_ARRAYBUFFER;
    	            } else {
    	                buffer = value.buffer;

    	                if (valueString === '[object Int8Array]') {
    	                    marker += TYPE_INT8ARRAY;
    	                } else if (valueString === '[object Uint8Array]') {
    	                    marker += TYPE_UINT8ARRAY;
    	                } else if (valueString === '[object Uint8ClampedArray]') {
    	                    marker += TYPE_UINT8CLAMPEDARRAY;
    	                } else if (valueString === '[object Int16Array]') {
    	                    marker += TYPE_INT16ARRAY;
    	                } else if (valueString === '[object Uint16Array]') {
    	                    marker += TYPE_UINT16ARRAY;
    	                } else if (valueString === '[object Int32Array]') {
    	                    marker += TYPE_INT32ARRAY;
    	                } else if (valueString === '[object Uint32Array]') {
    	                    marker += TYPE_UINT32ARRAY;
    	                } else if (valueString === '[object Float32Array]') {
    	                    marker += TYPE_FLOAT32ARRAY;
    	                } else if (valueString === '[object Float64Array]') {
    	                    marker += TYPE_FLOAT64ARRAY;
    	                } else {
    	                    callback(new Error('Failed to get type for BinaryArray'));
    	                }
    	            }

    	            callback(marker + bufferToString(buffer));
    	        } else Iif (valueString === '[object Blob]') {
    	            // Conver the blob to a binaryArray and then to a string.
    	            var fileReader = new FileReader();

    	            fileReader.onload = function () {
    	                // Backwards-compatible prefix for the blob type.
    	                var str = BLOB_TYPE_PREFIX + value.type + '~' + bufferToString(this.result);

    	                callback(SERIALIZED_MARKER + TYPE_BLOB + str);
    	            };

    	            fileReader.readAsArrayBuffer(value);
    	        } else {
    	            try {
    	                callback(JSON.stringify(value));
    	            } catch (e) {
    	                console.error("Couldn't convert value into a JSON string: ", value);

    	                callback(null, e);
    	            }
    	        }
    	    }

    	    // Deserialize data we've inserted into a value column/field. We place
    	    // special markers into our strings to mark them as encoded; this isn't
    	    // as nice as a meta field, but it's the only sane thing we can do whilst
    	    // keeping localStorage support intact.
    	    //
    	    // Oftentimes this will just deserialize JSON content, but if we have a
    	    // special marker (SERIALIZED_MARKER, defined above), we will extract
    	    // some kind of arraybuffer/binary data/typed array out of the string.
    	    function deserialize(value) {
    	        // If we haven't marked this string as being specially serialized (i.e.
    	        // something other than serialized JSON), we can just return it and be
    	        // done with it.
    	        Eif (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
    	            return JSON.parse(value);
    	        }

    	        // The following code deals with deserializing some kind of Blob or
    	        // TypedArray. First we separate out the type of data we're dealing
    	        // with from the data itself.
    	        var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
    	        var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);

    	        var blobType;
    	        // Backwards-compatible blob type serialization strategy.
    	        // DBs created with older versions of localForage will simply not have the blob type.
    	        if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
    	            var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
    	            blobType = matcher[1];
    	            serializedString = serializedString.substring(matcher[0].length);
    	        }
    	        var buffer = stringToBuffer(serializedString);

    	        // Return the right type based on the code/type set during
    	        // serialization.
    	        switch (type) {
    	            case TYPE_ARRAYBUFFER:
    	                return buffer;
    	            case TYPE_BLOB:
    	                return _createBlob([buffer], { type: blobType });
    	            case TYPE_INT8ARRAY:
    	                return new Int8Array(buffer);
    	            case TYPE_UINT8ARRAY:
    	                return new Uint8Array(buffer);
    	            case TYPE_UINT8CLAMPEDARRAY:
    	                return new Uint8ClampedArray(buffer);
    	            case TYPE_INT16ARRAY:
    	                return new Int16Array(buffer);
    	            case TYPE_UINT16ARRAY:
    	                return new Uint16Array(buffer);
    	            case TYPE_INT32ARRAY:
    	                return new Int32Array(buffer);
    	            case TYPE_UINT32ARRAY:
    	                return new Uint32Array(buffer);
    	            case TYPE_FLOAT32ARRAY:
    	                return new Float32Array(buffer);
    	            case TYPE_FLOAT64ARRAY:
    	                return new Float64Array(buffer);
    	            default:
    	                throw new Error('Unkown type: ' + type);
    	        }
    	    }

    	    function stringToBuffer(serializedString) {
    	        // Fill the string into a ArrayBuffer.
    	        var bufferLength = serializedString.length * 0.75;
    	        var len = serializedString.length;
    	        var i;
    	        var p = 0;
    	        var encoded1, encoded2, encoded3, encoded4;

    	        if (serializedString[serializedString.length - 1] === '=') {
    	            bufferLength--;
    	            if (serializedString[serializedString.length - 2] === '=') {
    	                bufferLength--;
    	            }
    	        }

    	        var buffer = new ArrayBuffer(bufferLength);
    	        var bytes = new Uint8Array(buffer);

    	        for (i = 0; i < len; i += 4) {
    	            encoded1 = BASE_CHARS.indexOf(serializedString[i]);
    	            encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);
    	            encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);
    	            encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);

    	            /*jslint bitwise: true */
    	            bytes[p++] = encoded1 << 2 | encoded2 >> 4;
    	            bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;
    	            bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;
    	        }
    	        return buffer;
    	    }

    	    // Converts a buffer to a string to store, serialized, in the backend
    	    // storage library.
    	    function bufferToString(buffer) {
    	        // base64-arraybuffer
    	        var bytes = new Uint8Array(buffer);
    	        var base64String = '';
    	        var i;

    	        for (i = 0; i < bytes.length; i += 3) {
    	            /*jslint bitwise: true */
    	            base64String += BASE_CHARS[bytes[i] >> 2];
    	            base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];
    	            base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];
    	            base64String += BASE_CHARS[bytes[i + 2] & 63];
    	        }

    	        if (bytes.length % 3 === 2) {
    	            base64String = base64String.substring(0, base64String.length - 1) + '=';
    	        } else if (bytes.length % 3 === 1) {
    	            base64String = base64String.substring(0, base64String.length - 2) + '==';
    	        }

    	        return base64String;
    	    }

    	    var localforageSerializer = {
    	        serialize: serialize,
    	        deserialize: deserialize,
    	        stringToBuffer: stringToBuffer,
    	        bufferToString: bufferToString
    	    };

    	    exports['default'] = localforageSerializer;
    	}).call(typeof window !== 'undefined' ? window : self);
    	module.exports = exports['default'];

    /***/ },
    /* 4 */
    /***/ function(module, exports, __webpack_require__) {

    	/*
    	 * Includes code from:
    	 *
    	 * base64-arraybuffer
    	 * https://github.com/niklasvh/base64-arraybuffer
    	 *
    	 * Copyright (c) 2012 Niklas von Hertzen
    	 * Licensed under the MIT license.
    	 */
    	'use strict';

    	exports.__esModule = true;
    	(function () {
    	    'use strict';

    	    var globalObject = this;
    	    var openDatabase = this.openDatabase;

    	    // If WebSQL methods aren't available, we can stop now.
    	    Iif (!openDatabase) {
    	        return;
    	    }

    	    // Open the WebSQL database (automatically creates one if one didn't
    	    // previously exist), using any options set in the config.
    	    function _initStorage(options) {
    	        var self = this;
    	        var dbInfo = {
    	            db: null
    	        };

    	        Eif (options) {
    	            for (var i in options) {
    	                dbInfo[i] = typeof options[i] !== 'string' ? options[i].toString() : options[i];
    	            }
    	        }

    	        var dbInfoPromise = new Promise(function (resolve, reject) {
    	            // Open the database; the openDatabase API will automatically
    	            // create it for us if it doesn't exist.
    	            try {
    	                dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size);
    	            } catch (e) {
    	                return self.setDriver(self.LOCALSTORAGE).then(function () {
    	                    return self._initStorage(options);
    	                }).then(resolve)['catch'](reject);
    	            }

    	            // Create our key/value table if it doesn't exist.
    	            dbInfo.db.transaction(function (t) {
    	                t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName + ' (id INTEGER PRIMARY KEY, key unique, value)', [], function () {
    	                    self._dbInfo = dbInfo;
    	                    resolve();
    	                }, function (t, error) {
    	                    reject(error);
    	                });
    	            });
    	        });

    	        return new Promise(function (resolve, reject) {
    	            resolve(__webpack_require__(3));
    	        }).then(function (lib) {
    	            dbInfo.serializer = lib;
    	            return dbInfoPromise;
    	        });
    	    }

    	    function getItem(key, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        Iif (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                dbInfo.db.transaction(function (t) {
    	                    t.executeSql('SELECT * FROM ' + dbInfo.storeName + ' WHERE key = ? LIMIT 1', [key], function (t, results) {
    	                        var result = results.rows.length ? results.rows.item(0).value : null;

    	                        // Check to see if this is serialized content we need to
    	                        // unpack.
    	                        if (result) {
    	                            result = dbInfo.serializer.deserialize(result);
    	                        }

    	                        resolve(result);
    	                    }, function (t, error) {

    	                        reject(error);
    	                    });
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function iterate(iterator, callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;

    	                dbInfo.db.transaction(function (t) {
    	                    t.executeSql('SELECT * FROM ' + dbInfo.storeName, [], function (t, results) {
    	                        var rows = results.rows;
    	                        var length = rows.length;

    	                        for (var i = 0; i < length; i++) {
    	                            var item = rows.item(i);
    	                            var result = item.value;

    	                            // Check to see if this is serialized content
    	                            // we need to unpack.
    	                            if (result) {
    	                                result = dbInfo.serializer.deserialize(result);
    	                            }

    	                            result = iterator(result, item.key, i + 1);

    	                            // void(0) prevents problems with redefinition
    	                            // of `undefined`.
    	                            if (result !== void 0) {
    	                                resolve(result);
    	                                return;
    	                            }
    	                        }

    	                        resolve();
    	                    }, function (t, error) {
    	                        reject(error);
    	                    });
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function setItem(key, value, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        Iif (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                // The localStorage API doesn't return undefined values in an
    	                // "expected" way, so undefined is always cast to null in all
    	                // drivers. See: https://github.com/mozilla/localForage/pull/42
    	                Iif (value === undefined) {
    	                    value = null;
    	                }

    	                // Save the original value to pass to the callback.
    	                var originalValue = value;

    	                var dbInfo = self._dbInfo;
    	                dbInfo.serializer.serialize(value, function (value, error) {
    	                    Iif (error) {
    	                        reject(error);
    	                    } else {
    	                        dbInfo.db.transaction(function (t) {
    	                            t.executeSql('INSERT OR REPLACE INTO ' + dbInfo.storeName + ' (key, value) VALUES (?, ?)', [key, value], function () {
    	                                resolve(originalValue);
    	                            }, function (t, error) {
    	                                reject(error);
    	                            });
    	                        }, function (sqlError) {
    	                            // The transaction failed; check
    	                            // to see if it's a quota error.
    	                            if (sqlError.code === sqlError.QUOTA_ERR) {
    	                                // We reject the callback outright for now, but
    	                                // it's worth trying to re-run the transaction.
    	                                // Even if the user accepts the prompt to use
    	                                // more storage on Safari, this error will
    	                                // be called.
    	                                //
    	                                // TODO: Try to re-run the transaction.
    	                                reject(sqlError);
    	                            }
    	                        });
    	                    }
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function removeItem(key, callback) {
    	        var self = this;

    	        // Cast the key to a string, as that's all we can set as a key.
    	        Iif (typeof key !== 'string') {
    	            globalObject.console.warn(key + ' used as a key, but it is not a string.');
    	            key = String(key);
    	        }

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                dbInfo.db.transaction(function (t) {
    	                    t.executeSql('DELETE FROM ' + dbInfo.storeName + ' WHERE key = ?', [key], function () {
    	                        resolve();
    	                    }, function (t, error) {

    	                        reject(error);
    	                    });
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Deletes every item in the table.
    	    // TODO: Find out if this resets the AUTO_INCREMENT number.
    	    function clear(callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                dbInfo.db.transaction(function (t) {
    	                    t.executeSql('DELETE FROM ' + dbInfo.storeName, [], function () {
    	                        resolve();
    	                    }, function (t, error) {
    	                        reject(error);
    	                    });
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Does a simple `COUNT(key)` to get the number of items stored in
    	    // localForage.
    	    function length(callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                dbInfo.db.transaction(function (t) {
    	                    // Ahhh, SQL makes this one soooooo easy.
    	                    t.executeSql('SELECT COUNT(key) as c FROM ' + dbInfo.storeName, [], function (t, results) {
    	                        var result = results.rows.item(0).c;

    	                        resolve(result);
    	                    }, function (t, error) {

    	                        reject(error);
    	                    });
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    // Return the key located at key index X; essentially gets the key from a
    	    // `WHERE id = ?`. This is the most efficient way I can think to implement
    	    // this rarely-used (in my experience) part of the API, but it can seem
    	    // inconsistent, because we do `INSERT OR REPLACE INTO` on `setItem()`, so
    	    // the ID of each key will change every time it's updated. Perhaps a stored
    	    // procedure for the `setItem()` SQL would solve this problem?
    	    // TODO: Don't change ID on `setItem()`.
    	    function key(n, callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                dbInfo.db.transaction(function (t) {
    	                    t.executeSql('SELECT key FROM ' + dbInfo.storeName + ' WHERE id = ? LIMIT 1', [n + 1], function (t, results) {
    	                        var result = results.rows.length ? results.rows.item(0).key : null;
    	                        resolve(result);
    	                    }, function (t, error) {
    	                        reject(error);
    	                    });
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function keys(callback) {
    	        var self = this;

    	        var promise = new Promise(function (resolve, reject) {
    	            self.ready().then(function () {
    	                var dbInfo = self._dbInfo;
    	                dbInfo.db.transaction(function (t) {
    	                    t.executeSql('SELECT key FROM ' + dbInfo.storeName, [], function (t, results) {
    	                        var keys = [];

    	                        for (var i = 0; i < results.rows.length; i++) {
    	                            keys.push(results.rows.item(i).key);
    	                        }

    	                        resolve(keys);
    	                    }, function (t, error) {

    	                        reject(error);
    	                    });
    	                });
    	            })['catch'](reject);
    	        });

    	        executeCallback(promise, callback);
    	        return promise;
    	    }

    	    function executeCallback(promise, callback) {
    	        Iif (callback) {
    	            promise.then(function (result) {
    	                callback(null, result);
    	            }, function (error) {
    	                callback(error);
    	            });
    	        }
    	    }

    	    var webSQLStorage = {
    	        _driver: 'webSQLStorage',
    	        _initStorage: _initStorage,
    	        iterate: iterate,
    	        getItem: getItem,
    	        setItem: setItem,
    	        removeItem: removeItem,
    	        clear: clear,
    	        length: length,
    	        key: key,
    	        keys: keys
    	    };

    	    exports['default'] = webSQLStorage;
    	}).call(typeof window !== 'undefined' ? window : self);
    	module.exports = exports['default'];

    /***/ }
    /******/ ])
    });
    ;
    }).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{"_process":78}],80:[function(_dereq_,module,exports){
    // Top level file is just a mixin of submodules & constants
    'use strict';

    var assign    = _dereq_('./lib/utils/common').assign;

    var deflate   = _dereq_('./lib/deflate');
    var inflate   = _dereq_('./lib/inflate');
    var constants = _dereq_('./lib/zlib/constants');

    var pako = {};

    assign(pako, deflate, inflate, constants);

    module.exports = pako;

    },{"./lib/deflate":81,"./lib/inflate":82,"./lib/utils/common":83,"./lib/zlib/constants":86}],81:[function(_dereq_,module,exports){
    'use strict';

    var zlib_deflate = _dereq_('./zlib/deflate.js');
    var utils = _dereq_('./utils/common');
    var strings = _dereq_('./utils/strings');
    var msg = _dereq_('./zlib/messages');
    var zstream = _dereq_('./zlib/zstream');

    var toString = Object.prototype.toString;

    /* Public constants ==========================================================*/
    /* ===========================================================================*/

    var Z_NO_FLUSH      = 0;
    var Z_FINISH        = 4;

    var Z_OK            = 0;
    var Z_STREAM_END    = 1;
    var Z_SYNC_FLUSH    = 2;

    var Z_DEFAULT_COMPRESSION = -1;

    var Z_DEFAULT_STRATEGY    = 0;

    var Z_DEFLATED  = 8;

    /* ===========================================================================*/

    /**
     * class Deflate
     *
     * Generic JS-style wrapper for zlib calls. If you don't need
     * streaming behaviour - use more simple functions: [[deflate]],
     * [[deflateRaw]] and [[gzip]].
     **/

    /* internal
     * Deflate.chunks -> Array
     *
     * Chunks of output data, if [[Deflate#onData]] not overriden.
     **/

    /**
     * Deflate.result -> Uint8Array|Array
     *
     * Compressed result, generated by default [[Deflate#onData]]
     * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
     * (call [[Deflate#push]] with `Z_FINISH` / `true` param)  or if you
     * push a chunk with explicit flush (call [[Deflate#push]] with
     * `Z_SYNC_FLUSH` param).
     **/

    /**
     * Deflate.err -> Number
     *
     * Error code after deflate finished. 0 (Z_OK) on success.
     * You will not need it in real life, because deflate errors
     * are possible only on wrong options or bad `onData` / `onEnd`
     * custom handlers.
     **/

    /**
     * Deflate.msg -> String
     *
     * Error message, if [[Deflate.err]] != 0
     **/

    /**
     * new Deflate(options)
     * - options (Object): zlib deflate options.
     *
     * Creates new deflator instance with specified params. Throws exception
     * on bad params. Supported options:
     *
     * - `level`
     * - `windowBits`
     * - `memLevel`
     * - `strategy`
     *
     * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
     * for more information on these.
     *
     * Additional options, for internal needs:
     *
     * - `chunkSize` - size of generated data chunks (16K by default)
     * - `raw` (Boolean) - do raw deflate
     * - `gzip` (Boolean) - create gzip wrapper
     * - `to` (String) - if equal to 'string', then result will be "binary string"
     *    (each char code [0..255])
     * - `header` (Object) - custom header for gzip
     *   - `text` (Boolean) - true if compressed data believed to be text
     *   - `time` (Number) - modification time, unix timestamp
     *   - `os` (Number) - operation system code
     *   - `extra` (Array) - array of bytes with extra data (max 65536)
     *   - `name` (String) - file name (binary string)
     *   - `comment` (String) - comment (binary string)
     *   - `hcrc` (Boolean) - true if header crc should be added
     *
     * ##### Example:
     *
     * ```javascript
     * var pako = require('pako')
     *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
     *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
     *
     * var deflate = new pako.Deflate({ level: 3});
     *
     * deflate.push(chunk1, false);
     * deflate.push(chunk2, true);  // true -> last chunk
     *
     * if (deflate.err) { throw new Error(deflate.err); }
     *
     * console.log(deflate.result);
     * ```
     **/
    var Deflate = function(options) {

      this.options = utils.assign({
        level: Z_DEFAULT_COMPRESSION,
        method: Z_DEFLATED,
        chunkSize: 16384,
        windowBits: 15,
        memLevel: 8,
        strategy: Z_DEFAULT_STRATEGY,
        to: ''
      }, options || {});

      var opt = this.options;

      Iif (opt.raw && (opt.windowBits > 0)) {
        opt.windowBits = -opt.windowBits;
      }

      else Iif (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
        opt.windowBits += 16;
      }

      this.err    = 0;      // error code, if happens (0 = Z_OK)
      this.msg    = '';     // error message
      this.ended  = false;  // used to avoid multiple onEnd() calls
      this.chunks = [];     // chunks of compressed data

      this.strm = new zstream();
      this.strm.avail_out = 0;

      var status = zlib_deflate.deflateInit2(
        this.strm,
        opt.level,
        opt.method,
        opt.windowBits,
        opt.memLevel,
        opt.strategy
      );

      Iif (status !== Z_OK) {
        throw new Error(msg[status]);
      }

      Iif (opt.header) {
        zlib_deflate.deflateSetHeader(this.strm, opt.header);
      }
    };

    /**
     * Deflate#push(data[, mode]) -> Boolean
     * - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
     *   converted to utf8 byte sequence.
     * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
     *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
     *
     * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
     * new compressed chunks. Returns `true` on success. The last data block must have
     * mode Z_FINISH (or `true`). That will flush internal pending buffers and call
     * [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you
     * can use mode Z_SYNC_FLUSH, keeping the compression context.
     *
     * On fail call [[Deflate#onEnd]] with error code and return false.
     *
     * We strongly recommend to use `Uint8Array` on input for best speed (output
     * array format is detected automatically). Also, don't skip last param and always
     * use the same type in your code (boolean or number). That will improve JS speed.
     *
     * For regular `Array`-s make sure all elements are [0..255].
     *
     * ##### Example
     *
     * ```javascript
     * push(chunk, false); // push one of data chunks
     * ...
     * push(chunk, true);  // push last chunk
     * ```
     **/
    Deflate.prototype.push = function(data, mode) {
      var strm = this.strm;
      var chunkSize = this.options.chunkSize;
      var status, _mode;

      Iif (this.ended) { return false; }

      _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);

      // Convert data if needed
      Eif (typeof data === 'string') {
        // If we need to compress text, change encoding to utf8.
        strm.input = strings.string2buf(data);
      } else if (toString.call(data) === '[object ArrayBuffer]') {
        strm.input = new Uint8Array(data);
      } else {
        strm.input = data;
      }

      strm.next_in = 0;
      strm.avail_in = strm.input.length;

      do {
        Eif (strm.avail_out === 0) {
          strm.output = new utils.Buf8(chunkSize);
          strm.next_out = 0;
          strm.avail_out = chunkSize;
        }
        status = zlib_deflate.deflate(strm, _mode);    /* no bad return value */

        Iif (status !== Z_STREAM_END && status !== Z_OK) {
          this.onEnd(status);
          this.ended = true;
          return false;
        }
        Eif (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) {
          Eif (this.options.to === 'string') {
            this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
          } else {
            this.onData(utils.shrinkBuf(strm.output, strm.next_out));
          }
        }
      } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);

      // Finalize on the last chunk.
      Eif (_mode === Z_FINISH) {
        status = zlib_deflate.deflateEnd(this.strm);
        this.onEnd(status);
        this.ended = true;
        return status === Z_OK;
      }

      // callback interim results if Z_SYNC_FLUSH.
      if (_mode === Z_SYNC_FLUSH) {
        this.onEnd(Z_OK);
        strm.avail_out = 0;
        return true;
      }

      return true;
    };

    /**
     * Deflate#onData(chunk) -> Void
     * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
     *   on js engine support. When string output requested, each chunk
     *   will be string.
     *
     * By default, stores data blocks in `chunks[]` property and glue
     * those in `onEnd`. Override this handler, if you need another behaviour.
     **/
    Deflate.prototype.onData = function(chunk) {
      this.chunks.push(chunk);
    };

    /**
     * Deflate#onEnd(status) -> Void
     * - status (Number): deflate status. 0 (Z_OK) on success,
     *   other if not.
     *
     * Called once after you tell deflate that the input stream is
     * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
     * or if an error happened. By default - join collected chunks,
     * free memory and fill `results` / `err` properties.
     **/
    Deflate.prototype.onEnd = function(status) {
      // On success - join
      Eif (status === Z_OK) {
        Eif (this.options.to === 'string') {
          this.result = this.chunks.join('');
        } else {
          this.result = utils.flattenChunks(this.chunks);
        }
      }
      this.chunks = [];
      this.err = status;
      this.msg = this.strm.msg;
    };

    /**
     * deflate(data[, options]) -> Uint8Array|Array|String
     * - data (Uint8Array|Array|String): input data to compress.
     * - options (Object): zlib deflate options.
     *
     * Compress `data` with deflate alrorythm and `options`.
     *
     * Supported options are:
     *
     * - level
     * - windowBits
     * - memLevel
     * - strategy
     *
     * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
     * for more information on these.
     *
     * Sugar (options):
     *
     * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
     *   negative windowBits implicitly.
     * - `to` (String) - if equal to 'string', then result will be "binary string"
     *    (each char code [0..255])
     *
     * ##### Example:
     *
     * ```javascript
     * var pako = require('pako')
     *   , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
     *
     * console.log(pako.deflate(data));
     * ```
     **/
    function deflate(input, options) {
      var deflator = new Deflate(options);

      deflator.push(input, true);

      // That will never happens, if you don't cheat with options :)
      Iif (deflator.err) { throw deflator.msg; }

      return deflator.result;
    }

    /**
     * deflateRaw(data[, options]) -> Uint8Array|Array|String
     * - data (Uint8Array|Array|String): input data to compress.
     * - options (Object): zlib deflate options.
     *
     * The same as [[deflate]], but creates raw data, without wrapper
     * (header and adler32 crc).
     **/
    function deflateRaw(input, options) {
      options = options || {};
      options.raw = true;
      return deflate(input, options);
    }

    /**
     * gzip(data[, options]) -> Uint8Array|Array|String
     * - data (Uint8Array|Array|String): input data to compress.
     * - options (Object): zlib deflate options.
     *
     * The same as [[deflate]], but create gzip wrapper instead of
     * deflate one.
     **/
    function gzip(input, options) {
      options = options || {};
      options.gzip = true;
      return deflate(input, options);
    }

    exports.Deflate = Deflate;
    exports.deflate = deflate;
    exports.deflateRaw = deflateRaw;
    exports.gzip = gzip;

    },{"./utils/common":83,"./utils/strings":84,"./zlib/deflate.js":88,"./zlib/messages":93,"./zlib/zstream":95}],82:[function(_dereq_,module,exports){
    'use strict';

    var zlib_inflate = _dereq_('./zlib/inflate.js');
    var utils = _dereq_('./utils/common');
    var strings = _dereq_('./utils/strings');
    var c = _dereq_('./zlib/constants');
    var msg = _dereq_('./zlib/messages');
    var zstream = _dereq_('./zlib/zstream');
    var gzheader = _dereq_('./zlib/gzheader');

    var toString = Object.prototype.toString;

    /**
     * class Inflate
     *
     * Generic JS-style wrapper for zlib calls. If you don't need
     * streaming behaviour - use more simple functions: [[inflate]]
     * and [[inflateRaw]].
     **/

    /* internal
     * inflate.chunks -> Array
     *
     * Chunks of output data, if [[Inflate#onData]] not overriden.
     **/

    /**
     * Inflate.result -> Uint8Array|Array|String
     *
     * Uncompressed result, generated by default [[Inflate#onData]]
     * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
     * (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you
     * push a chunk with explicit flush (call [[Inflate#push]] with
     * `Z_SYNC_FLUSH` param).
     **/

    /**
     * Inflate.err -> Number
     *
     * Error code after inflate finished. 0 (Z_OK) on success.
     * Should be checked if broken data possible.
     **/

    /**
     * Inflate.msg -> String
     *
     * Error message, if [[Inflate.err]] != 0
     **/

    /**
     * new Inflate(options)
     * - options (Object): zlib inflate options.
     *
     * Creates new inflator instance with specified params. Throws exception
     * on bad params. Supported options:
     *
     * - `windowBits`
     *
     * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
     * for more information on these.
     *
     * Additional options, for internal needs:
     *
     * - `chunkSize` - size of generated data chunks (16K by default)
     * - `raw` (Boolean) - do raw inflate
     * - `to` (String) - if equal to 'string', then result will be converted
     *   from utf8 to utf16 (javascript) string. When string output requested,
     *   chunk length can differ from `chunkSize`, depending on content.
     *
     * By default, when no options set, autodetect deflate/gzip data format via
     * wrapper header.
     *
     * ##### Example:
     *
     * ```javascript
     * var pako = require('pako')
     *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
     *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
     *
     * var inflate = new pako.Inflate({ level: 3});
     *
     * inflate.push(chunk1, false);
     * inflate.push(chunk2, true);  // true -> last chunk
     *
     * if (inflate.err) { throw new Error(inflate.err); }
     *
     * console.log(inflate.result);
     * ```
     **/
    var Inflate = function(options) {

      this.options = utils.assign({
        chunkSize: 16384,
        windowBits: 0,
        to: ''
      }, options || {});

      var opt = this.options;

      // Force window size for `raw` data, if not set directly,
      // because we have no header for autodetect.
      if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
        opt.windowBits = -opt.windowBits;
        if (opt.windowBits === 0) { opt.windowBits = -15; }
      }

      // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
      if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
          !(options && options.windowBits)) {
        opt.windowBits += 32;
      }

      // Gzip header has no info about windows size, we can do autodetect only
      // for deflate. So, if window size not set, force it to max when gzip possible
      if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
        // bit 3 (16) -> gzipped data
        // bit 4 (32) -> autodetect gzip/deflate
        if ((opt.windowBits & 15) === 0) {
          opt.windowBits |= 15;
        }
      }

      this.err    = 0;      // error code, if happens (0 = Z_OK)
      this.msg    = '';     // error message
      this.ended  = false;  // used to avoid multiple onEnd() calls
      this.chunks = [];     // chunks of compressed data

      this.strm   = new zstream();
      this.strm.avail_out = 0;

      var status  = zlib_inflate.inflateInit2(
        this.strm,
        opt.windowBits
      );

      if (status !== c.Z_OK) {
        throw new Error(msg[status]);
      }

      this.header = new gzheader();

      zlib_inflate.inflateGetHeader(this.strm, this.header);
    };

    /**
     * Inflate#push(data[, mode]) -> Boolean
     * - data (Uint8Array|Array|ArrayBuffer|String): input data
     * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
     *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
     *
     * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
     * new output chunks. Returns `true` on success. The last data block must have
     * mode Z_FINISH (or `true`). That will flush internal pending buffers and call
     * [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you
     * can use mode Z_SYNC_FLUSH, keeping the decompression context.
     *
     * On fail call [[Inflate#onEnd]] with error code and return false.
     *
     * We strongly recommend to use `Uint8Array` on input for best speed (output
     * format is detected automatically). Also, don't skip last param and always
     * use the same type in your code (boolean or number). That will improve JS speed.
     *
     * For regular `Array`-s make sure all elements are [0..255].
     *
     * ##### Example
     *
     * ```javascript
     * push(chunk, false); // push one of data chunks
     * ...
     * push(chunk, true);  // push last chunk
     * ```
     **/
    Inflate.prototype.push = function(data, mode) {
      var strm = this.strm;
      var chunkSize = this.options.chunkSize;
      var status, _mode;
      var next_out_utf8, tail, utf8str;

      // Flag to properly process Z_BUF_ERROR on testing inflate call
      // when we check that all output data was flushed.
      var allowBufError = false;

      if (this.ended) { return false; }
      _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);

      // Convert data if needed
      if (typeof data === 'string') {
        // Only binary strings can be decompressed on practice
        strm.input = strings.binstring2buf(data);
      } else if (toString.call(data) === '[object ArrayBuffer]') {
        strm.input = new Uint8Array(data);
      } else {
        strm.input = data;
      }

      strm.next_in = 0;
      strm.avail_in = strm.input.length;

      do {
        if (strm.avail_out === 0) {
          strm.output = new utils.Buf8(chunkSize);
          strm.next_out = 0;
          strm.avail_out = chunkSize;
        }

        status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);    /* no bad return value */

        if (status === c.Z_BUF_ERROR && allowBufError === true) {
          status = c.Z_OK;
          allowBufError = false;
        }

        if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
          this.onEnd(status);
          this.ended = true;
          return false;
        }

        if (strm.next_out) {
          if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) {

            if (this.options.to === 'string') {

              next_out_utf8 = strings.utf8border(strm.output, strm.next_out);

              tail = strm.next_out - next_out_utf8;
              utf8str = strings.buf2string(strm.output, next_out_utf8);

              // move tail
              strm.next_out = tail;
              strm.avail_out = chunkSize - tail;
              if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }

              this.onData(utf8str);

            } else {
              this.onData(utils.shrinkBuf(strm.output, strm.next_out));
            }
          }
        }

        // When no more input data, we should check that internal inflate buffers
        // are flushed. The only way to do it when avail_out = 0 - run one more
        // inflate pass. But if output data not exists, inflate return Z_BUF_ERROR.
        // Here we set flag to process this error properly.
        //
        // NOTE. Deflate does not return error in this case and does not needs such
        // logic.
        if (strm.avail_in === 0 && strm.avail_out === 0) {
          allowBufError = true;
        }

      } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END);

      if (status === c.Z_STREAM_END) {
        _mode = c.Z_FINISH;
      }

      // Finalize on the last chunk.
      if (_mode === c.Z_FINISH) {
        status = zlib_inflate.inflateEnd(this.strm);
        this.onEnd(status);
        this.ended = true;
        return status === c.Z_OK;
      }

      // callback interim results if Z_SYNC_FLUSH.
      if (_mode === c.Z_SYNC_FLUSH) {
        this.onEnd(c.Z_OK);
        strm.avail_out = 0;
        return true;
      }

      return true;
    };

    /**
     * Inflate#onData(chunk) -> Void
     * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
     *   on js engine support. When string output requested, each chunk
     *   will be string.
     *
     * By default, stores data blocks in `chunks[]` property and glue
     * those in `onEnd`. Override this handler, if you need another behaviour.
     **/
    Inflate.prototype.onData = function(chunk) {
      this.chunks.push(chunk);
    };

    /**
     * Inflate#onEnd(status) -> Void
     * - status (Number): inflate status. 0 (Z_OK) on success,
     *   other if not.
     *
     * Called either after you tell inflate that the input stream is
     * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
     * or if an error happened. By default - join collected chunks,
     * free memory and fill `results` / `err` properties.
     **/
    Inflate.prototype.onEnd = function(status) {
      // On success - join
      if (status === c.Z_OK) {
        if (this.options.to === 'string') {
          // Glue & convert here, until we teach pako to send
          // utf8 alligned strings to onData
          this.result = this.chunks.join('');
        } else {
          this.result = utils.flattenChunks(this.chunks);
        }
      }
      this.chunks = [];
      this.err = status;
      this.msg = this.strm.msg;
    };

    /**
     * inflate(data[, options]) -> Uint8Array|Array|String
     * - data (Uint8Array|Array|String): input data to decompress.
     * - options (Object): zlib inflate options.
     *
     * Decompress `data` with inflate/ungzip and `options`. Autodetect
     * format via wrapper header by default. That's why we don't provide
     * separate `ungzip` method.
     *
     * Supported options are:
     *
     * - windowBits
     *
     * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
     * for more information.
     *
     * Sugar (options):
     *
     * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
     *   negative windowBits implicitly.
     * - `to` (String) - if equal to 'string', then result will be converted
     *   from utf8 to utf16 (javascript) string. When string output requested,
     *   chunk length can differ from `chunkSize`, depending on content.
     *
     *
     * ##### Example:
     *
     * ```javascript
     * var pako = require('pako')
     *   , input = pako.deflate([1,2,3,4,5,6,7,8,9])
     *   , output;
     *
     * try {
     *   output = pako.inflate(input);
     * } catch (err)
     *   console.log(err);
     * }
     * ```
     **/
    function inflate(input, options) {
      var inflator = new Inflate(options);

      inflator.push(input, true);

      // That will never happens, if you don't cheat with options :)
      if (inflator.err) { throw inflator.msg; }

      return inflator.result;
    }

    /**
     * inflateRaw(data[, options]) -> Uint8Array|Array|String
     * - data (Uint8Array|Array|String): input data to decompress.
     * - options (Object): zlib inflate options.
     *
     * The same as [[inflate]], but creates raw data, without wrapper
     * (header and adler32 crc).
     **/
    function inflateRaw(input, options) {
      options = options || {};
      options.raw = true;
      return inflate(input, options);
    }

    /**
     * ungzip(data[, options]) -> Uint8Array|Array|String
     * - data (Uint8Array|Array|String): input data to decompress.
     * - options (Object): zlib inflate options.
     *
     * Just shortcut to [[inflate]], because it autodetects format
     * by header.content. Done for convenience.
     **/

    exports.Inflate = Inflate;
    exports.inflate = inflate;
    exports.inflateRaw = inflateRaw;
    exports.ungzip  = inflate;

    },{"./utils/common":83,"./utils/strings":84,"./zlib/constants":86,"./zlib/gzheader":89,"./zlib/inflate.js":91,"./zlib/messages":93,"./zlib/zstream":95}],83:[function(_dereq_,module,exports){
    'use strict';

    var TYPED_OK =  (typeof Uint8Array !== 'undefined') &&
                    (typeof Uint16Array !== 'undefined') &&
                    (typeof Int32Array !== 'undefined');

    exports.assign = function (obj /*from1, from2, from3, ...*/) {
      var sources = Array.prototype.slice.call(arguments, 1);
      while (sources.length) {
        var source = sources.shift();
        Iif (!source) { continue; }

        Iif (typeof source !== 'object') {
          throw new TypeError(source + 'must be non-object');
        }

        for (var p in source) {
          Eif (source.hasOwnProperty(p)) {
            obj[p] = source[p];
          }
        }
      }

      return obj;
    };

    // reduce buffer size, avoiding mem copy
    exports.shrinkBuf = function (buf, size) {
      Iif (buf.length === size) { return buf; }
      Eif (buf.subarray) { return buf.subarray(0, size); }
      buf.length = size;
      return buf;
    };

    var fnTyped = {
      arraySet: function (dest, src, src_offs, len, dest_offs) {
        Eif (src.subarray && dest.subarray) {
          dest.set(src.subarray(src_offs, src_offs+len), dest_offs);
          return;
        }
        // Fallback to ordinary array
        for (var i=0; i<len; i++) {
          dest[dest_offs + i] = src[src_offs + i];
        }
      },
      // Join array of chunks to single array.
      flattenChunks: function(chunks) {
        var i, l, len, pos, chunk, result;

        // calculate data length
        len = 0;
        for (i=0, l=chunks.length; i<l; i++) {
          len += chunks[i].length;
        }

        // join chunks
        result = new Uint8Array(len);
        pos = 0;
        for (i=0, l=chunks.length; i<l; i++) {
          chunk = chunks[i];
          result.set(chunk, pos);
          pos += chunk.length;
        }

        return result;
      }
    };

    var fnUntyped = {
      arraySet: function (dest, src, src_offs, len, dest_offs) {
        for (var i=0; i<len; i++) {
          dest[dest_offs + i] = src[src_offs + i];
        }
      },
      // Join array of chunks to single array.
      flattenChunks: function(chunks) {
        return [].concat.apply([], chunks);
      }
    };

    // Enable/Disable typed arrays use, for testing
    //
    exports.setTyped = function (on) {
      Eif (on) {
        exports.Buf8  = Uint8Array;
        exports.Buf16 = Uint16Array;
        exports.Buf32 = Int32Array;
        exports.assign(exports, fnTyped);
      } else {
        exports.Buf8  = Array;
        exports.Buf16 = Array;
        exports.Buf32 = Array;
        exports.assign(exports, fnUntyped);
      }
    };

    exports.setTyped(TYPED_OK);

    },{}],84:[function(_dereq_,module,exports){
    // String encode/decode helpers
    'use strict';

    var utils = _dereq_('./common');

    // Quick check if we can use fast array to bin string conversion
    //
    // - apply(Array) can fail on Android 2.2
    // - apply(Uint8Array) can fail on iOS 5.1 Safary
    //
    var STR_APPLY_OK = true;
    var STR_APPLY_UIA_OK = true;

    try { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; }
    try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; }

    // Table with utf8 lengths (calculated by first byte of sequence)
    // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
    // because max possible codepoint is 0x10ffff
    var _utf8len = new utils.Buf8(256);
    for (var q=0; q<256; q++) {
      _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
    }
    _utf8len[254]=_utf8len[254]=1; // Invalid sequence start

    // convert string to array (typed, when possible)
    exports.string2buf = function (str) {
      var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;

      // count binary size
      for (m_pos = 0; m_pos < str_len; m_pos++) {
        c = str.charCodeAt(m_pos);
        Iif ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
          c2 = str.charCodeAt(m_pos+1);
          if ((c2 & 0xfc00) === 0xdc00) {
            c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
            m_pos++;
          }
        }
        buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
      }

      // allocate buffer
      buf = new utils.Buf8(buf_len);

      // convert
      for (i=0, m_pos = 0; i < buf_len; m_pos++) {
        c = str.charCodeAt(m_pos);
        Iif ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
          c2 = str.charCodeAt(m_pos+1);
          if ((c2 & 0xfc00) === 0xdc00) {
            c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
            m_pos++;
          }
        }
        Eif (c < 0x80) {
          /* one byte */
          buf[i++] = c;
        } else if (c < 0x800) {
          /* two bytes */
          buf[i++] = 0xC0 | (c >>> 6);
          buf[i++] = 0x80 | (c & 0x3f);
        } else if (c < 0x10000) {
          /* three bytes */
          buf[i++] = 0xE0 | (c >>> 12);
          buf[i++] = 0x80 | (c >>> 6 & 0x3f);
          buf[i++] = 0x80 | (c & 0x3f);
        } else {
          /* four bytes */
          buf[i++] = 0xf0 | (c >>> 18);
          buf[i++] = 0x80 | (c >>> 12 & 0x3f);
          buf[i++] = 0x80 | (c >>> 6 & 0x3f);
          buf[i++] = 0x80 | (c & 0x3f);
        }
      }

      return buf;
    };

    // Helper (used in 2 places)
    function buf2binstring(buf, len) {
      // use fallback for big arrays to avoid stack overflow
      Eif (len < 65537) {
        Iif ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
          return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
        }
      }

      var result = '';
      for (var i=0; i < len; i++) {
        result += String.fromCharCode(buf[i]);
      }
      return result;
    }

    // Convert byte array to binary string
    exports.buf2binstring = function(buf) {
      return buf2binstring(buf, buf.length);
    };

    // Convert binary string (typed, when possible)
    exports.binstring2buf = function(str) {
      var buf = new utils.Buf8(str.length);
      for (var i=0, len=buf.length; i < len; i++) {
        buf[i] = str.charCodeAt(i);
      }
      return buf;
    };

    // convert array to string
    exports.buf2string = function (buf, max) {
      var i, out, c, c_len;
      var len = max || buf.length;

      // Reserve max possible length (2 words per char)
      // NB: by unknown reasons, Array is significantly faster for
      //     String.fromCharCode.apply than Uint16Array.
      var utf16buf = new Array(len*2);

      for (out=0, i=0; i<len;) {
        c = buf[i++];
        // quick process ascii
        if (c < 0x80) { utf16buf[out++] = c; continue; }

        c_len = _utf8len[c];
        // skip 5 & 6 byte codes
        if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }

        // apply mask on first byte
        c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
        // join the rest
        while (c_len > 1 && i < len) {
          c = (c << 6) | (buf[i++] & 0x3f);
          c_len--;
        }

        // terminated by end of string?
        if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }

        if (c < 0x10000) {
          utf16buf[out++] = c;
        } else {
          c -= 0x10000;
          utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
          utf16buf[out++] = 0xdc00 | (c & 0x3ff);
        }
      }

      return buf2binstring(utf16buf, out);
    };

    // Calculate max possible position in utf8 buffer,
    // that will not break sequence. If that's not possible
    // - (very small limits) return max size as is.
    //
    // buf[] - utf8 bytes array
    // max   - length limit (mandatory);
    exports.utf8border = function(buf, max) {
      var pos;

      max = max || buf.length;
      if (max > buf.length) { max = buf.length; }

      // go back from last position, until start of sequence found
      pos = max-1;
      while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }

      // Fuckup - very small and broken sequence,
      // return max, because we should return something anyway.
      if (pos < 0) { return max; }

      // If we came to start of buffer - that means vuffer is too small,
      // return max too.
      if (pos === 0) { return max; }

      return (pos + _utf8len[buf[pos]] > max) ? pos : max;
    };

    },{"./common":83}],85:[function(_dereq_,module,exports){
    'use strict';

    // Note: adler32 takes 12% for level 0 and 2% for level 6.
    // It doesn't worth to make additional optimizationa as in original.
    // Small size is preferable.

    function adler32(adler, buf, len, pos) {
      var s1 = (adler & 0xffff) |0,
          s2 = ((adler >>> 16) & 0xffff) |0,
          n = 0;

      while (len !== 0) {
        // Set limit ~ twice less than 5552, to keep
        // s2 in 31-bits, because we force signed ints.
        // in other case %= will fail.
        n = len > 2000 ? 2000 : len;
        len -= n;

        do {
          s1 = (s1 + buf[pos++]) |0;
          s2 = (s2 + s1) |0;
        } while (--n);

        s1 %= 65521;
        s2 %= 65521;
      }

      return (s1 | (s2 << 16)) |0;
    }

    module.exports = adler32;

    },{}],86:[function(_dereq_,module,exports){
    module.exports = {

      /* Allowed flush values; see deflate() and inflate() below for details */
      Z_NO_FLUSH:         0,
      Z_PARTIAL_FLUSH:    1,
      Z_SYNC_FLUSH:       2,
      Z_FULL_FLUSH:       3,
      Z_FINISH:           4,
      Z_BLOCK:            5,
      Z_TREES:            6,

      /* Return codes for the compression/decompression functions. Negative values
      * are errors, positive values are used for special but normal events.
      */
      Z_OK:               0,
      Z_STREAM_END:       1,
      Z_NEED_DICT:        2,
      Z_ERRNO:           -1,
      Z_STREAM_ERROR:    -2,
      Z_DATA_ERROR:      -3,
      //Z_MEM_ERROR:     -4,
      Z_BUF_ERROR:       -5,
      //Z_VERSION_ERROR: -6,

      /* compression levels */
      Z_NO_COMPRESSION:         0,
      Z_BEST_SPEED:             1,
      Z_BEST_COMPRESSION:       9,
      Z_DEFAULT_COMPRESSION:   -1,

      Z_FILTERED:               1,
      Z_HUFFMAN_ONLY:           2,
      Z_RLE:                    3,
      Z_FIXED:                  4,
      Z_DEFAULT_STRATEGY:       0,

      /* Possible values of the data_type field (though see inflate()) */
      Z_BINARY:                 0,
      Z_TEXT:                   1,
      //Z_ASCII:                1, // = Z_TEXT (deprecated)
      Z_UNKNOWN:                2,

      /* The deflate compression method */
      Z_DEFLATED:               8
      //Z_NULL:                 null // Use -1 or null inline, depending on var type
    };

    },{}],87:[function(_dereq_,module,exports){
    'use strict';

    // Note: we can't get significant speed boost here.
    // So write code to minimize size - no pregenerated tables
    // and array tools dependencies.

    // Use ordinary array, since untyped makes no boost here
    function makeTable() {
      var c, table = [];

      for (var n =0; n < 256; n++) {
        c = n;
        for (var k =0; k < 8; k++) {
          c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
        }
        table[n] = c;
      }

      return table;
    }

    // Create table on load. Just 255 signed longs. Not a problem.
    var crcTable = makeTable();

    function crc32(crc, buf, len, pos) {
      var t = crcTable,
          end = pos + len;

      crc = crc ^ (-1);

      for (var i = pos; i < end; i++) {
        crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
      }

      return (crc ^ (-1)); // >>> 0;
    }

    module.exports = crc32;

    },{}],88:[function(_dereq_,module,exports){
    'use strict';

    var utils   = _dereq_('../utils/common');
    var trees   = _dereq_('./trees');
    var adler32 = _dereq_('./adler32');
    var crc32   = _dereq_('./crc32');
    var msg   = _dereq_('./messages');

    /* Public constants ==========================================================*/
    /* ===========================================================================*/

    /* Allowed flush values; see deflate() and inflate() below for details */
    var Z_NO_FLUSH      = 0;
    var Z_PARTIAL_FLUSH = 1;
    //var Z_SYNC_FLUSH    = 2;
    var Z_FULL_FLUSH    = 3;
    var Z_FINISH        = 4;
    var Z_BLOCK         = 5;
    //var Z_TREES         = 6;

    /* Return codes for the compression/decompression functions. Negative values
     * are errors, positive values are used for special but normal events.
     */
    var Z_OK            = 0;
    var Z_STREAM_END    = 1;
    //var Z_NEED_DICT     = 2;
    //var Z_ERRNO         = -1;
    var Z_STREAM_ERROR  = -2;
    var Z_DATA_ERROR    = -3;
    //var Z_MEM_ERROR     = -4;
    var Z_BUF_ERROR     = -5;
    //var Z_VERSION_ERROR = -6;

    /* compression levels */
    //var Z_NO_COMPRESSION      = 0;
    //var Z_BEST_SPEED          = 1;
    //var Z_BEST_COMPRESSION    = 9;
    var Z_DEFAULT_COMPRESSION = -1;

    var Z_FILTERED            = 1;
    var Z_HUFFMAN_ONLY        = 2;
    var Z_RLE                 = 3;
    var Z_FIXED               = 4;
    var Z_DEFAULT_STRATEGY    = 0;

    /* Possible values of the data_type field (though see inflate()) */
    //var Z_BINARY              = 0;
    //var Z_TEXT                = 1;
    //var Z_ASCII               = 1; // = Z_TEXT
    var Z_UNKNOWN             = 2;

    /* The deflate compression method */
    var Z_DEFLATED  = 8;

    /*============================================================================*/

    var MAX_MEM_LEVEL = 9;
    /* Maximum value for memLevel in deflateInit2 */
    var MAX_WBITS = 15;
    /* 32K LZ77 window */
    var DEF_MEM_LEVEL = 8;

    var LENGTH_CODES  = 29;
    /* number of length codes, not counting the special END_BLOCK code */
    var LITERALS      = 256;
    /* number of literal bytes 0..255 */
    var L_CODES       = LITERALS + 1 + LENGTH_CODES;
    /* number of Literal or Length codes, including the END_BLOCK code */
    var D_CODES       = 30;
    /* number of distance codes */
    var BL_CODES      = 19;
    /* number of codes used to transfer the bit lengths */
    var HEAP_SIZE     = 2*L_CODES + 1;
    /* maximum heap size */
    var MAX_BITS  = 15;
    /* All codes must not exceed MAX_BITS bits */

    var MIN_MATCH = 3;
    var MAX_MATCH = 258;
    var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);

    var PRESET_DICT = 0x20;

    var INIT_STATE = 42;
    var EXTRA_STATE = 69;
    var NAME_STATE = 73;
    var COMMENT_STATE = 91;
    var HCRC_STATE = 103;
    var BUSY_STATE = 113;
    var FINISH_STATE = 666;

    var BS_NEED_MORE      = 1; /* block not completed, need more input or more output */
    var BS_BLOCK_DONE     = 2; /* block flush performed */
    var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
    var BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */

    var OS_CODE = 0x03; // Unix :) . Don't detect, use this default.

    function err(strm, errorCode) {
      strm.msg = msg[errorCode];
      return errorCode;
    }

    function rank(f) {
      return ((f) << 1) - ((f) > 4 ? 9 : 0);
    }

    function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }

    /* =========================================================================
     * Flush as much pending output as possible. All deflate() output goes
     * through this function so some applications may wish to modify it
     * to avoid allocating a large strm->output buffer and copying into it.
     * (See also read_buf()).
     */
    function flush_pending(strm) {
      var s = strm.state;

      //_tr_flush_bits(s);
      var len = s.pending;
      Iif (len > strm.avail_out) {
        len = strm.avail_out;
      }
      Iif (len === 0) { return; }

      utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
      strm.next_out += len;
      s.pending_out += len;
      strm.total_out += len;
      strm.avail_out -= len;
      s.pending -= len;
      Eif (s.pending === 0) {
        s.pending_out = 0;
      }
    }

    function flush_block_only (s, last) {
      trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
      s.block_start = s.strstart;
      flush_pending(s.strm);
    }

    function put_byte(s, b) {
      s.pending_buf[s.pending++] = b;
    }

    /* =========================================================================
     * Put a short in the pending buffer. The 16-bit value is put in MSB order.
     * IN assertion: the stream state is correct and there is enough room in
     * pending_buf.
     */
    function putShortMSB(s, b) {
    //  put_byte(s, (Byte)(b >> 8));
    //  put_byte(s, (Byte)(b & 0xff));
      s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
      s.pending_buf[s.pending++] = b & 0xff;
    }

    /* ===========================================================================
     * Read a new buffer from the current input stream, update the adler32
     * and total number of bytes read.  All deflate() input goes through
     * this function so some applications may wish to modify it to avoid
     * allocating a large strm->input buffer and copying from it.
     * (See also flush_pending()).
     */
    function read_buf(strm, buf, start, size) {
      var len = strm.avail_in;

      Iif (len > size) { len = size; }
      Iif (len === 0) { return 0; }

      strm.avail_in -= len;

      utils.arraySet(buf, strm.input, strm.next_in, len, start);
      Eif (strm.state.wrap === 1) {
        strm.adler = adler32(strm.adler, buf, len, start);
      }

      else if (strm.state.wrap === 2) {
        strm.adler = crc32(strm.adler, buf, len, start);
      }

      strm.next_in += len;
      strm.total_in += len;

      return len;
    }

    /* ===========================================================================
     * Set match_start to the longest match starting at the given string and
     * return its length. Matches shorter or equal to prev_length are discarded,
     * in which case the result is equal to prev_length and match_start is
     * garbage.
     * IN assertions: cur_match is the head of the hash chain for the current
     *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
     * OUT assertion: the match length is not greater than s->lookahead.
     */
    function longest_match(s, cur_match) {
      var chain_length = s.max_chain_length;      /* max hash chain length */
      var scan = s.strstart; /* current string */
      var match;                       /* matched string */
      var len;                           /* length of current match */
      var best_len = s.prev_length;              /* best match length so far */
      var nice_match = s.nice_match;             /* stop if match long enough */
      var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
          s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;

      var _win = s.window; // shortcut

      var wmask = s.w_mask;
      var prev  = s.prev;

      /* Stop when cur_match becomes <= limit. To simplify the code,
       * we prevent matches with the string of window index 0.
       */

      var strend = s.strstart + MAX_MATCH;
      var scan_end1  = _win[scan + best_len - 1];
      var scan_end   = _win[scan + best_len];

      /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
       * It is easy to get rid of this optimization if necessary.
       */
      // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");

      /* Do not waste too much time if we already have a good match: */
      Iif (s.prev_length >= s.good_match) {
        chain_length >>= 2;
      }
      /* Do not look for matches beyond the end of the input. This is necessary
       * to make deflate deterministic.
       */
      Eif (nice_match > s.lookahead) { nice_match = s.lookahead; }

      // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");

      do {
        // Assert(cur_match < s->strstart, "no future");
        match = cur_match;

        /* Skip to next match if the match length cannot increase
         * or if the match length is less than 2.  Note that the checks below
         * for insufficient lookahead only occur occasionally for performance
         * reasons.  Therefore uninitialized memory will be accessed, and
         * conditional jumps will be made that depend on those values.
         * However the length of the match is limited to the lookahead, so
         * the output of deflate is not affected by the uninitialized values.
         */

        Iif (_win[match + best_len]     !== scan_end  ||
            _win[match + best_len - 1] !== scan_end1 ||
            _win[match]                !== _win[scan] ||
            _win[++match]              !== _win[scan + 1]) {
          continue;
        }

        /* The check at best_len-1 can be removed because it will be made
         * again later. (This heuristic is not always a win.)
         * It is not necessary to compare scan[2] and match[2] since they
         * are always equal when the other bytes match, given that
         * the hash keys are equal and that HASH_BITS >= 8.
         */
        scan += 2;
        match++;
        // Assert(*scan == *match, "match[2]?");

        /* We check for insufficient lookahead only every 8th comparison;
         * the 256th check will be made at strstart+258.
         */
        do {
          /*jshint noempty:false*/
        } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
                 _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
                 _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
                 _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
                 scan < strend);

        // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");

        len = MAX_MATCH - (strend - scan);
        scan = strend - MAX_MATCH;

        Eif (len > best_len) {
          s.match_start = cur_match;
          best_len = len;
          Iif (len >= nice_match) {
            break;
          }
          scan_end1  = _win[scan + best_len - 1];
          scan_end   = _win[scan + best_len];
        }
      } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);

      Eif (best_len <= s.lookahead) {
        return best_len;
      }
      return s.lookahead;
    }

    /* ===========================================================================
     * Fill the window when the lookahead becomes insufficient.
     * Updates strstart and lookahead.
     *
     * IN assertion: lookahead < MIN_LOOKAHEAD
     * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
     *    At least one byte has been read, or avail_in == 0; reads are
     *    performed for at least two bytes (required for the zip translate_eol
     *    option -- not supported here).
     */
    function fill_window(s) {
      var _w_size = s.w_size;
      var p, n, m, more, str;

      //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");

      do {
        more = s.window_size - s.lookahead - s.strstart;

        // JS ints have 32 bit, block below not needed
        /* Deal with !@#$% 64K limit: */
        //if (sizeof(int) <= 2) {
        //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
        //        more = wsize;
        //
        //  } else if (more == (unsigned)(-1)) {
        //        /* Very unlikely, but possible on 16 bit machine if
        //         * strstart == 0 && lookahead == 1 (input done a byte at time)
        //         */
        //        more--;
        //    }
        //}

        /* If the window is almost full and there is insufficient lookahead,
         * move the upper half to the lower one to make room in the upper half.
         */
        Iif (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {

          utils.arraySet(s.window, s.window, _w_size, _w_size, 0);
          s.match_start -= _w_size;
          s.strstart -= _w_size;
          /* we now have strstart >= MAX_DIST */
          s.block_start -= _w_size;

          /* Slide the hash table (could be avoided with 32 bit values
           at the expense of memory usage). We slide even when level == 0
           to keep the hash table consistent if we switch back to level > 0
           later. (Using level 0 permanently is not an optimal usage of
           zlib, so we don't care about this pathological case.)
           */

          n = s.hash_size;
          p = n;
          do {
            m = s.head[--p];
            s.head[p] = (m >= _w_size ? m - _w_size : 0);
          } while (--n);

          n = _w_size;
          p = n;
          do {
            m = s.prev[--p];
            s.prev[p] = (m >= _w_size ? m - _w_size : 0);
            /* If n is not on any hash chain, prev[n] is garbage but
             * its value will never be used.
             */
          } while (--n);

          more += _w_size;
        }
        if (s.strm.avail_in === 0) {
          break;
        }

        /* If there was no sliding:
         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
         *    more == window_size - lookahead - strstart
         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
         * => more >= window_size - 2*WSIZE + 2
         * In the BIG_MEM or MMAP case (not yet supported),
         *   window_size == input_size + MIN_LOOKAHEAD  &&
         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
         * Otherwise, window_size == 2*WSIZE so more >= 2.
         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
         */
        //Assert(more >= 2, "more < 2");
        n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
        s.lookahead += n;

        /* Initialize the hash value now that we have some input: */
        Eif (s.lookahead + s.insert >= MIN_MATCH) {
          str = s.strstart - s.insert;
          s.ins_h = s.window[str];

          /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
    //#if MIN_MATCH != 3
    //        Call update_hash() MIN_MATCH-3 more times
    //#endif
          while (s.insert) {
            /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
            s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask;

            s.prev[str & s.w_mask] = s.head[s.ins_h];
            s.head[s.ins_h] = str;
            str++;
            s.insert--;
            if (s.lookahead + s.insert < MIN_MATCH) {
              break;
            }
          }
        }
        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
         * but this is not important since only literal bytes will be emitted.
         */

      } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);

      /* If the WIN_INIT bytes after the end of the current data have never been
       * written, then zero those bytes in order to avoid memory check reports of
       * the use of uninitialized (or uninitialised as Julian writes) bytes by
       * the longest match routines.  Update the high water mark for the next
       * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
       * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
       */
    //  if (s.high_water < s.window_size) {
    //    var curr = s.strstart + s.lookahead;
    //    var init = 0;
    //
    //    if (s.high_water < curr) {
    //      /* Previous high water mark below current data -- zero WIN_INIT
    //       * bytes or up to end of window, whichever is less.
    //       */
    //      init = s.window_size - curr;
    //      if (init > WIN_INIT)
    //        init = WIN_INIT;
    //      zmemzero(s->window + curr, (unsigned)init);
    //      s->high_water = curr + init;
    //    }
    //    else if (s->high_water < (ulg)curr + WIN_INIT) {
    //      /* High water mark at or above current data, but below current data
    //       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
    //       * to end of window, whichever is less.
    //       */
    //      init = (ulg)curr + WIN_INIT - s->high_water;
    //      if (init > s->window_size - s->high_water)
    //        init = s->window_size - s->high_water;
    //      zmemzero(s->window + s->high_water, (unsigned)init);
    //      s->high_water += init;
    //    }
    //  }
    //
    //  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
    //    "not enough room for search");
    }

    /* ===========================================================================
     * Copy without compression as much as possible from the input stream, return
     * the current block state.
     * This function does not insert new strings in the dictionary since
     * uncompressible data is probably not useful. This function is used
     * only for the level=0 compression option.
     * NOTE: this function should be optimized to avoid extra copying from
     * window to pending_buf.
     */
    function deflate_stored(s, flush) {
      /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
       * to pending_buf_size, and each stored block has a 5 byte header:
       */
      var max_block_size = 0xffff;

      if (max_block_size > s.pending_buf_size - 5) {
        max_block_size = s.pending_buf_size - 5;
      }

      /* Copy as much as possible from input to output: */
      for (;;) {
        /* Fill the window as much as possible: */
        if (s.lookahead <= 1) {

          //Assert(s->strstart < s->w_size+MAX_DIST(s) ||
          //  s->block_start >= (long)s->w_size, "slide too late");
    //      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
    //        s.block_start >= s.w_size)) {
    //        throw  new Error("slide too late");
    //      }

          fill_window(s);
          if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
            return BS_NEED_MORE;
          }

          if (s.lookahead === 0) {
            break;
          }
          /* flush the current block */
        }
        //Assert(s->block_start >= 0L, "block gone");
    //    if (s.block_start < 0) throw new Error("block gone");

        s.strstart += s.lookahead;
        s.lookahead = 0;

        /* Emit a stored block if pending_buf will be full: */
        var max_start = s.block_start + max_block_size;

        if (s.strstart === 0 || s.strstart >= max_start) {
          /* strstart == 0 is possible when wraparound on 16-bit machine */
          s.lookahead = s.strstart - max_start;
          s.strstart = max_start;
          /*** FLUSH_BLOCK(s, 0); ***/
          flush_block_only(s, false);
          if (s.strm.avail_out === 0) {
            return BS_NEED_MORE;
          }
          /***/

        }
        /* Flush if we may have to slide, otherwise block_start may become
         * negative and the data will be gone:
         */
        if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
          /*** FLUSH_BLOCK(s, 0); ***/
          flush_block_only(s, false);
          if (s.strm.avail_out === 0) {
            return BS_NEED_MORE;
          }
          /***/
        }
      }

      s.insert = 0;

      if (flush === Z_FINISH) {
        /*** FLUSH_BLOCK(s, 1); ***/
        flush_block_only(s, true);
        if (s.strm.avail_out === 0) {
          return BS_FINISH_STARTED;
        }
        /***/
        return BS_FINISH_DONE;
      }

      if (s.strstart > s.block_start) {
        /*** FLUSH_BLOCK(s, 0); ***/
        flush_block_only(s, false);
        if (s.strm.avail_out === 0) {
          return BS_NEED_MORE;
        }
        /***/
      }

      return BS_NEED_MORE;
    }

    /* ===========================================================================
     * Compress as much as possible from the input stream, return the current
     * block state.
     * This function does not perform lazy evaluation of matches and inserts
     * new strings in the dictionary only for unmatched strings or for short
     * matches. It is used only for the fast compression options.
     */
    function deflate_fast(s, flush) {
      var hash_head;        /* head of the hash chain */
      var bflush;           /* set if current block must be flushed */

      for (;;) {
        /* Make sure that we always have enough lookahead, except
         * at the end of the input file. We need MAX_MATCH bytes
         * for the next match, plus MIN_MATCH bytes to insert the
         * string following the next match.
         */
        if (s.lookahead < MIN_LOOKAHEAD) {
          fill_window(s);
          if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
            return BS_NEED_MORE;
          }
          if (s.lookahead === 0) {
            break; /* flush the current block */
          }
        }

        /* Insert the string window[strstart .. strstart+2] in the
         * dictionary, and set hash_head to the head of the hash chain:
         */
        hash_head = 0/*NIL*/;
        if (s.lookahead >= MIN_MATCH) {
          /*** INSERT_STRING(s, s.strstart, hash_head); ***/
          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
          s.head[s.ins_h] = s.strstart;
          /***/
        }

        /* Find the longest match, discarding those <= prev_length.
         * At this point we have always match_length < MIN_MATCH
         */
        if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
          /* To simplify the code, we prevent matches with the string
           * of window index 0 (in particular we have to avoid a match
           * of the string with itself at the start of the input file).
           */
          s.match_length = longest_match(s, hash_head);
          /* longest_match() sets match_start */
        }
        if (s.match_length >= MIN_MATCH) {
          // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only

          /*** _tr_tally_dist(s, s.strstart - s.match_start,
                         s.match_length - MIN_MATCH, bflush); ***/
          bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);

          s.lookahead -= s.match_length;

          /* Insert new strings in the hash table only if the match length
           * is not too large. This saves time but degrades compression.
           */
          if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
            s.match_length--; /* string at strstart already in table */
            do {
              s.strstart++;
              /*** INSERT_STRING(s, s.strstart, hash_head); ***/
              s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
              hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
              s.head[s.ins_h] = s.strstart;
              /***/
              /* strstart never exceeds WSIZE-MAX_MATCH, so there are
               * always MIN_MATCH bytes ahead.
               */
            } while (--s.match_length !== 0);
            s.strstart++;
          } else
          {
            s.strstart += s.match_length;
            s.match_length = 0;
            s.ins_h = s.window[s.strstart];
            /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
            s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;

    //#if MIN_MATCH != 3
    //                Call UPDATE_HASH() MIN_MATCH-3 more times
    //#endif
            /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
             * matter since it will be recomputed at next deflate call.
             */
          }
        } else {
          /* No match, output a literal byte */
          //Tracevv((stderr,"%c", s.window[s.strstart]));
          /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
          bflush = trees._tr_tally(s, 0, s.window[s.strstart]);

          s.lookahead--;
          s.strstart++;
        }
        if (bflush) {
          /*** FLUSH_BLOCK(s, 0); ***/
          flush_block_only(s, false);
          if (s.strm.avail_out === 0) {
            return BS_NEED_MORE;
          }
          /***/
        }
      }
      s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1);
      if (flush === Z_FINISH) {
        /*** FLUSH_BLOCK(s, 1); ***/
        flush_block_only(s, true);
        if (s.strm.avail_out === 0) {
          return BS_FINISH_STARTED;
        }
        /***/
        return BS_FINISH_DONE;
      }
      if (s.last_lit) {
        /*** FLUSH_BLOCK(s, 0); ***/
        flush_block_only(s, false);
        if (s.strm.avail_out === 0) {
          return BS_NEED_MORE;
        }
        /***/
      }
      return BS_BLOCK_DONE;
    }

    /* ===========================================================================
     * Same as above, but achieves better compression. We use a lazy
     * evaluation for matches: a match is finally adopted only if there is
     * no better match at the next window position.
     */
    function deflate_slow(s, flush) {
      var hash_head;          /* head of hash chain */
      var bflush;              /* set if current block must be flushed */

      var max_insert;

      /* Process the input block. */
      for (;;) {
        /* Make sure that we always have enough lookahead, except
         * at the end of the input file. We need MAX_MATCH bytes
         * for the next match, plus MIN_MATCH bytes to insert the
         * string following the next match.
         */
        Eif (s.lookahead < MIN_LOOKAHEAD) {
          fill_window(s);
          Iif (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
            return BS_NEED_MORE;
          }
          if (s.lookahead === 0) { break; } /* flush the current block */
        }

        /* Insert the string window[strstart .. strstart+2] in the
         * dictionary, and set hash_head to the head of the hash chain:
         */
        hash_head = 0/*NIL*/;
        if (s.lookahead >= MIN_MATCH) {
          /*** INSERT_STRING(s, s.strstart, hash_head); ***/
          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
          s.head[s.ins_h] = s.strstart;
          /***/
        }

        /* Find the longest match, discarding those <= prev_length.
         */
        s.prev_length = s.match_length;
        s.prev_match = s.match_start;
        s.match_length = MIN_MATCH-1;

        if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
            s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
          /* To simplify the code, we prevent matches with the string
           * of window index 0 (in particular we have to avoid a match
           * of the string with itself at the start of the input file).
           */
          s.match_length = longest_match(s, hash_head);
          /* longest_match() sets match_start */

          Iif (s.match_length <= 5 &&
             (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {

            /* If prev_match is also MIN_MATCH, match_start is garbage
             * but we will ignore the current match anyway.
             */
            s.match_length = MIN_MATCH-1;
          }
        }
        /* If there was a match at the previous step and the current
         * match is not better, output the previous match:
         */
        if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
          max_insert = s.strstart + s.lookahead - MIN_MATCH;
          /* Do not insert strings in hash table beyond this. */

          //check_match(s, s.strstart-1, s.prev_match, s.prev_length);

          /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
                         s.prev_length - MIN_MATCH, bflush);***/
          bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH);
          /* Insert in hash table all strings up to the end of the match.
           * strstart-1 and strstart are already inserted. If there is not
           * enough lookahead, the last two strings are not inserted in
           * the hash table.
           */
          s.lookahead -= s.prev_length-1;
          s.prev_length -= 2;
          do {
            Eif (++s.strstart <= max_insert) {
              /*** INSERT_STRING(s, s.strstart, hash_head); ***/
              s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
              hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
              s.head[s.ins_h] = s.strstart;
              /***/
            }
          } while (--s.prev_length !== 0);
          s.match_available = 0;
          s.match_length = MIN_MATCH-1;
          s.strstart++;

          Iif (bflush) {
            /*** FLUSH_BLOCK(s, 0); ***/
            flush_block_only(s, false);
            if (s.strm.avail_out === 0) {
              return BS_NEED_MORE;
            }
            /***/
          }

        } else if (s.match_available) {
          /* If there was no match at the previous position, output a
           * single literal. If there was a match but the current match
           * is longer, truncate the previous match to a single literal.
           */
          //Tracevv((stderr,"%c", s->window[s->strstart-1]));
          /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
          bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);

          Iif (bflush) {
            /*** FLUSH_BLOCK_ONLY(s, 0) ***/
            flush_block_only(s, false);
            /***/
          }
          s.strstart++;
          s.lookahead--;
          Iif (s.strm.avail_out === 0) {
            return BS_NEED_MORE;
          }
        } else {
          /* There is no previous match to compare with, wait for
           * the next step to decide.
           */
          s.match_available = 1;
          s.strstart++;
          s.lookahead--;
        }
      }
      //Assert (flush != Z_NO_FLUSH, "no flush?");
      Eif (s.match_available) {
        //Tracevv((stderr,"%c", s->window[s->strstart-1]));
        /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
        bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);

        s.match_available = 0;
      }
      s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1;
      Eif (flush === Z_FINISH) {
        /*** FLUSH_BLOCK(s, 1); ***/
        flush_block_only(s, true);
        Iif (s.strm.avail_out === 0) {
          return BS_FINISH_STARTED;
        }
        /***/
        return BS_FINISH_DONE;
      }
      if (s.last_lit) {
        /*** FLUSH_BLOCK(s, 0); ***/
        flush_block_only(s, false);
        if (s.strm.avail_out === 0) {
          return BS_NEED_MORE;
        }
        /***/
      }

      return BS_BLOCK_DONE;
    }

    /* ===========================================================================
     * For Z_RLE, simply look for runs of bytes, generate matches only of distance
     * one.  Do not maintain a hash table.  (It will be regenerated if this run of
     * deflate switches away from Z_RLE.)
     */
    function deflate_rle(s, flush) {
      var bflush;            /* set if current block must be flushed */
      var prev;              /* byte at distance one to match */
      var scan, strend;      /* scan goes up to strend for length of run */

      var _win = s.window;

      for (;;) {
        /* Make sure that we always have enough lookahead, except
         * at the end of the input file. We need MAX_MATCH bytes
         * for the longest run, plus one for the unrolled loop.
         */
        if (s.lookahead <= MAX_MATCH) {
          fill_window(s);
          if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {
            return BS_NEED_MORE;
          }
          if (s.lookahead === 0) { break; } /* flush the current block */
        }

        /* See how many times the previous byte repeats */
        s.match_length = 0;
        if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
          scan = s.strstart - 1;
          prev = _win[scan];
          if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
            strend = s.strstart + MAX_MATCH;
            do {
              /*jshint noempty:false*/
            } while (prev === _win[++scan] && prev === _win[++scan] &&
                     prev === _win[++scan] && prev === _win[++scan] &&
                     prev === _win[++scan] && prev === _win[++scan] &&
                     prev === _win[++scan] && prev === _win[++scan] &&
                     scan < strend);
            s.match_length = MAX_MATCH - (strend - scan);
            if (s.match_length > s.lookahead) {
              s.match_length = s.lookahead;
            }
          }
          //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
        }

        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
        if (s.match_length >= MIN_MATCH) {
          //check_match(s, s.strstart, s.strstart - 1, s.match_length);

          /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
          bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);

          s.lookahead -= s.match_length;
          s.strstart += s.match_length;
          s.match_length = 0;
        } else {
          /* No match, output a literal byte */
          //Tracevv((stderr,"%c", s->window[s->strstart]));
          /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
          bflush = trees._tr_tally(s, 0, s.window[s.strstart]);

          s.lookahead--;
          s.strstart++;
        }
        if (bflush) {
          /*** FLUSH_BLOCK(s, 0); ***/
          flush_block_only(s, false);
          if (s.strm.avail_out === 0) {
            return BS_NEED_MORE;
          }
          /***/
        }
      }
      s.insert = 0;
      if (flush === Z_FINISH) {
        /*** FLUSH_BLOCK(s, 1); ***/
        flush_block_only(s, true);
        if (s.strm.avail_out === 0) {
          return BS_FINISH_STARTED;
        }
        /***/
        return BS_FINISH_DONE;
      }
      if (s.last_lit) {
        /*** FLUSH_BLOCK(s, 0); ***/
        flush_block_only(s, false);
        if (s.strm.avail_out === 0) {
          return BS_NEED_MORE;
        }
        /***/
      }
      return BS_BLOCK_DONE;
    }

    /* ===========================================================================
     * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
     * (It will be regenerated if this run of deflate switches away from Huffman.)
     */
    function deflate_huff(s, flush) {
      var bflush;             /* set if current block must be flushed */

      for (;;) {
        /* Make sure that we have a literal to write. */
        if (s.lookahead === 0) {
          fill_window(s);
          if (s.lookahead === 0) {
            if (flush === Z_NO_FLUSH) {
              return BS_NEED_MORE;
            }
            break;      /* flush the current block */
          }
        }

        /* Output a literal byte */
        s.match_length = 0;
        //Tracevv((stderr,"%c", s->window[s->strstart]));
        /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
        bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
        s.lookahead--;
        s.strstart++;
        if (bflush) {
          /*** FLUSH_BLOCK(s, 0); ***/
          flush_block_only(s, false);
          if (s.strm.avail_out === 0) {
            return BS_NEED_MORE;
          }
          /***/
        }
      }
      s.insert = 0;
      if (flush === Z_FINISH) {
        /*** FLUSH_BLOCK(s, 1); ***/
        flush_block_only(s, true);
        if (s.strm.avail_out === 0) {
          return BS_FINISH_STARTED;
        }
        /***/
        return BS_FINISH_DONE;
      }
      if (s.last_lit) {
        /*** FLUSH_BLOCK(s, 0); ***/
        flush_block_only(s, false);
        if (s.strm.avail_out === 0) {
          return BS_NEED_MORE;
        }
        /***/
      }
      return BS_BLOCK_DONE;
    }

    /* Values for max_lazy_match, good_match and max_chain_length, depending on
     * the desired pack level (0..9). The values given below have been tuned to
     * exclude worst case performance for pathological files. Better values may be
     * found for specific files.
     */
    var Config = function (good_length, max_lazy, nice_length, max_chain, func) {
      this.good_length = good_length;
      this.max_lazy = max_lazy;
      this.nice_length = nice_length;
      this.max_chain = max_chain;
      this.func = func;
    };

    var configuration_table;

    configuration_table = [
      /*      good lazy nice chain */
      new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */
      new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */
      new Config(4, 5, 16, 8, deflate_fast),           /* 2 */
      new Config(4, 6, 32, 32, deflate_fast),          /* 3 */

      new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */
      new Config(8, 16, 32, 32, deflate_slow),         /* 5 */
      new Config(8, 16, 128, 128, deflate_slow),       /* 6 */
      new Config(8, 32, 128, 256, deflate_slow),       /* 7 */
      new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */
      new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */
    ];

    /* ===========================================================================
     * Initialize the "longest match" routines for a new zlib stream
     */
    function lm_init(s) {
      s.window_size = 2 * s.w_size;

      /*** CLEAR_HASH(s); ***/
      zero(s.head); // Fill with NIL (= 0);

      /* Set the default configuration parameters:
       */
      s.max_lazy_match = configuration_table[s.level].max_lazy;
      s.good_match = configuration_table[s.level].good_length;
      s.nice_match = configuration_table[s.level].nice_length;
      s.max_chain_length = configuration_table[s.level].max_chain;

      s.strstart = 0;
      s.block_start = 0;
      s.lookahead = 0;
      s.insert = 0;
      s.match_length = s.prev_length = MIN_MATCH - 1;
      s.match_available = 0;
      s.ins_h = 0;
    }

    function DeflateState() {
      this.strm = null;            /* pointer back to this zlib stream */
      this.status = 0;            /* as the name implies */
      this.pending_buf = null;      /* output still pending */
      this.pending_buf_size = 0;  /* size of pending_buf */
      this.pending_out = 0;       /* next pending byte to output to the stream */
      this.pending = 0;           /* nb of bytes in the pending buffer */
      this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
      this.gzhead = null;         /* gzip header information to write */
      this.gzindex = 0;           /* where in extra, name, or comment */
      this.method = Z_DEFLATED; /* can only be DEFLATED */
      this.last_flush = -1;   /* value of flush param for previous deflate call */

      this.w_size = 0;  /* LZ77 window size (32K by default) */
      this.w_bits = 0;  /* log2(w_size)  (8..16) */
      this.w_mask = 0;  /* w_size - 1 */

      this.window = null;
      /* Sliding window. Input bytes are read into the second half of the window,
       * and move to the first half later to keep a dictionary of at least wSize
       * bytes. With this organization, matches are limited to a distance of
       * wSize-MAX_MATCH bytes, but this ensures that IO is always
       * performed with a length multiple of the block size.
       */

      this.window_size = 0;
      /* Actual size of window: 2*wSize, except when the user input buffer
       * is directly used as sliding window.
       */

      this.prev = null;
      /* Link to older string with same hash index. To limit the size of this
       * array to 64K, this link is maintained only for the last 32K strings.
       * An index in this array is thus a window index modulo 32K.
       */

      this.head = null;   /* Heads of the hash chains or NIL. */

      this.ins_h = 0;       /* hash index of string to be inserted */
      this.hash_size = 0;   /* number of elements in hash table */
      this.hash_bits = 0;   /* log2(hash_size) */
      this.hash_mask = 0;   /* hash_size-1 */

      this.hash_shift = 0;
      /* Number of bits by which ins_h must be shifted at each input
       * step. It must be such that after MIN_MATCH steps, the oldest
       * byte no longer takes part in the hash key, that is:
       *   hash_shift * MIN_MATCH >= hash_bits
       */

      this.block_start = 0;
      /* Window position at the beginning of the current output block. Gets
       * negative when the window is moved backwards.
       */

      this.match_length = 0;      /* length of best match */
      this.prev_match = 0;        /* previous match */
      this.match_available = 0;   /* set if previous match exists */
      this.strstart = 0;          /* start of string to insert */
      this.match_start = 0;       /* start of matching string */
      this.lookahead = 0;         /* number of valid bytes ahead in window */

      this.prev_length = 0;
      /* Length of the best match at previous step. Matches not greater than this
       * are discarded. This is used in the lazy match evaluation.
       */

      this.max_chain_length = 0;
      /* To speed up deflation, hash chains are never searched beyond this
       * length.  A higher limit improves compression ratio but degrades the
       * speed.
       */

      this.max_lazy_match = 0;
      /* Attempt to find a better match only when the current match is strictly
       * smaller than this value. This mechanism is used only for compression
       * levels >= 4.
       */
      // That's alias to max_lazy_match, don't use directly
      //this.max_insert_length = 0;
      /* Insert new strings in the hash table only if the match length is not
       * greater than this length. This saves time but degrades compression.
       * max_insert_length is used only for compression levels <= 3.
       */

      this.level = 0;     /* compression level (1..9) */
      this.strategy = 0;  /* favor or force Huffman coding*/

      this.good_match = 0;
      /* Use a faster search when the previous match is longer than this */

      this.nice_match = 0; /* Stop searching when current match exceeds this */

                  /* used by trees.c: */

      /* Didn't use ct_data typedef below to suppress compiler warning */

      // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
      // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
      // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */

      // Use flat array of DOUBLE size, with interleaved fata,
      // because JS does not support effective
      this.dyn_ltree  = new utils.Buf16(HEAP_SIZE * 2);
      this.dyn_dtree  = new utils.Buf16((2*D_CODES+1) * 2);
      this.bl_tree    = new utils.Buf16((2*BL_CODES+1) * 2);
      zero(this.dyn_ltree);
      zero(this.dyn_dtree);
      zero(this.bl_tree);

      this.l_desc   = null;         /* desc. for literal tree */
      this.d_desc   = null;         /* desc. for distance tree */
      this.bl_desc  = null;         /* desc. for bit length tree */

      //ush bl_count[MAX_BITS+1];
      this.bl_count = new utils.Buf16(MAX_BITS+1);
      /* number of codes at each bit length for an optimal tree */

      //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
      this.heap = new utils.Buf16(2*L_CODES+1);  /* heap used to build the Huffman trees */
      zero(this.heap);

      this.heap_len = 0;               /* number of elements in the heap */
      this.heap_max = 0;               /* element of largest frequency */
      /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
       * The same heap array is used to build all trees.
       */

      this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1];
      zero(this.depth);
      /* Depth of each subtree used as tie breaker for trees of equal frequency
       */

      this.l_buf = 0;          /* buffer index for literals or lengths */

      this.lit_bufsize = 0;
      /* Size of match buffer for literals/lengths.  There are 4 reasons for
       * limiting lit_bufsize to 64K:
       *   - frequencies can be kept in 16 bit counters
       *   - if compression is not successful for the first block, all input
       *     data is still in the window so we can still emit a stored block even
       *     when input comes from standard input.  (This can also be done for
       *     all blocks if lit_bufsize is not greater than 32K.)
       *   - if compression is not successful for a file smaller than 64K, we can
       *     even emit a stored file instead of a stored block (saving 5 bytes).
       *     This is applicable only for zip (not gzip or zlib).
       *   - creating new Huffman trees less frequently may not provide fast
       *     adaptation to changes in the input data statistics. (Take for
       *     example a binary file with poorly compressible code followed by
       *     a highly compressible string table.) Smaller buffer sizes give
       *     fast adaptation but have of course the overhead of transmitting
       *     trees more frequently.
       *   - I can't count above 4
       */

      this.last_lit = 0;      /* running index in l_buf */

      this.d_buf = 0;
      /* Buffer index for distances. To simplify the code, d_buf and l_buf have
       * the same number of elements. To use different lengths, an extra flag
       * array would be necessary.
       */

      this.opt_len = 0;       /* bit length of current block with optimal trees */
      this.static_len = 0;    /* bit length of current block with static trees */
      this.matches = 0;       /* number of string matches in current block */
      this.insert = 0;        /* bytes at end of window left to insert */

      this.bi_buf = 0;
      /* Output buffer. bits are inserted starting at the bottom (least
       * significant bits).
       */
      this.bi_valid = 0;
      /* Number of valid bits in bi_buf.  All bits above the last valid bit
       * are always zero.
       */

      // Used for window memory init. We safely ignore it for JS. That makes
      // sense only for pointers and memory check tools.
      //this.high_water = 0;
      /* High water mark offset in window for initialized bytes -- bytes above
       * this are set to zero in order to avoid memory check warnings when
       * longest match routines access bytes past the input.  This is then
       * updated to the new high water mark.
       */
    }

    function deflateResetKeep(strm) {
      var s;

      Iif (!strm || !strm.state) {
        return err(strm, Z_STREAM_ERROR);
      }

      strm.total_in = strm.total_out = 0;
      strm.data_type = Z_UNKNOWN;

      s = strm.state;
      s.pending = 0;
      s.pending_out = 0;

      Iif (s.wrap < 0) {
        s.wrap = -s.wrap;
        /* was made negative by deflate(..., Z_FINISH); */
      }
      s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
      strm.adler = (s.wrap === 2) ?
        0  // crc32(0, Z_NULL, 0)
      :
        1; // adler32(0, Z_NULL, 0)
      s.last_flush = Z_NO_FLUSH;
      trees._tr_init(s);
      return Z_OK;
    }

    function deflateReset(strm) {
      var ret = deflateResetKeep(strm);
      Eif (ret === Z_OK) {
        lm_init(strm.state);
      }
      return ret;
    }

    function deflateSetHeader(strm, head) {
      if (!strm || !strm.state) { return Z_STREAM_ERROR; }
      if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
      strm.state.gzhead = head;
      return Z_OK;
    }

    function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
      Iif (!strm) { // === Z_NULL
        return Z_STREAM_ERROR;
      }
      var wrap = 1;

      Eif (level === Z_DEFAULT_COMPRESSION) {
        level = 6;
      }

      Iif (windowBits < 0) { /* suppress zlib wrapper */
        wrap = 0;
        windowBits = -windowBits;
      }

      else Iif (windowBits > 15) {
        wrap = 2;           /* write gzip wrapper instead */
        windowBits -= 16;
      }

      Iif (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
        strategy < 0 || strategy > Z_FIXED) {
        return err(strm, Z_STREAM_ERROR);
      }

      Iif (windowBits === 8) {
        windowBits = 9;
      }
      /* until 256-byte window bug fixed */

      var s = new DeflateState();

      strm.state = s;
      s.strm = strm;

      s.wrap = wrap;
      s.gzhead = null;
      s.w_bits = windowBits;
      s.w_size = 1 << s.w_bits;
      s.w_mask = s.w_size - 1;

      s.hash_bits = memLevel + 7;
      s.hash_size = 1 << s.hash_bits;
      s.hash_mask = s.hash_size - 1;
      s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);

      s.window = new utils.Buf8(s.w_size * 2);
      s.head = new utils.Buf16(s.hash_size);
      s.prev = new utils.Buf16(s.w_size);

      // Don't need mem init magic for JS.
      //s.high_water = 0;  /* nothing written to s->window yet */

      s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */

      s.pending_buf_size = s.lit_bufsize * 4;
      s.pending_buf = new utils.Buf8(s.pending_buf_size);

      s.d_buf = s.lit_bufsize >> 1;
      s.l_buf = (1 + 2) * s.lit_bufsize;

      s.level = level;
      s.strategy = strategy;
      s.method = method;

      return deflateReset(strm);
    }

    function deflateInit(strm, level) {
      return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
    }

    function deflate(strm, flush) {
      var old_flush, s;
      var beg, val; // for gzip header write only

      Iif (!strm || !strm.state ||
        flush > Z_BLOCK || flush < 0) {
        return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
      }

      s = strm.state;

      Iif (!strm.output ||
          (!strm.input && strm.avail_in !== 0) ||
          (s.status === FINISH_STATE && flush !== Z_FINISH)) {
        return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
      }

      s.strm = strm; /* just in case */
      old_flush = s.last_flush;
      s.last_flush = flush;

      /* Write the header */
      Eif (s.status === INIT_STATE) {

        Iif (s.wrap === 2) { // GZIP header
          strm.adler = 0;  //crc32(0L, Z_NULL, 0);
          put_byte(s, 31);
          put_byte(s, 139);
          put_byte(s, 8);
          if (!s.gzhead) { // s->gzhead == Z_NULL
            put_byte(s, 0);
            put_byte(s, 0);
            put_byte(s, 0);
            put_byte(s, 0);
            put_byte(s, 0);
            put_byte(s, s.level === 9 ? 2 :
                        (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
                         4 : 0));
            put_byte(s, OS_CODE);
            s.status = BUSY_STATE;
          }
          else {
            put_byte(s, (s.gzhead.text ? 1 : 0) +
                        (s.gzhead.hcrc ? 2 : 0) +
                        (!s.gzhead.extra ? 0 : 4) +
                        (!s.gzhead.name ? 0 : 8) +
                        (!s.gzhead.comment ? 0 : 16)
                    );
            put_byte(s, s.gzhead.time & 0xff);
            put_byte(s, (s.gzhead.time >> 8) & 0xff);
            put_byte(s, (s.gzhead.time >> 16) & 0xff);
            put_byte(s, (s.gzhead.time >> 24) & 0xff);
            put_byte(s, s.level === 9 ? 2 :
                        (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
                         4 : 0));
            put_byte(s, s.gzhead.os & 0xff);
            if (s.gzhead.extra && s.gzhead.extra.length) {
              put_byte(s, s.gzhead.extra.length & 0xff);
              put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
            }
            if (s.gzhead.hcrc) {
              strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
            }
            s.gzindex = 0;
            s.status = EXTRA_STATE;
          }
        }
        else // DEFLATE header
        {
          var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
          var level_flags = -1;

          Iif (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
            level_flags = 0;
          } else Iif (s.level < 6) {
            level_flags = 1;
          } else Eif (s.level === 6) {
            level_flags = 2;
          } else {
            level_flags = 3;
          }
          header |= (level_flags << 6);
          Iif (s.strstart !== 0) { header |= PRESET_DICT; }
          header += 31 - (header % 31);

          s.status = BUSY_STATE;
          putShortMSB(s, header);

          /* Save the adler32 of the preset dictionary: */
          Iif (s.strstart !== 0) {
            putShortMSB(s, strm.adler >>> 16);
            putShortMSB(s, strm.adler & 0xffff);
          }
          strm.adler = 1; // adler32(0L, Z_NULL, 0);
        }
      }

    //#ifdef GZIP
      Iif (s.status === EXTRA_STATE) {
        if (s.gzhead.extra/* != Z_NULL*/) {
          beg = s.pending;  /* start of bytes to update crc */

          while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
            if (s.pending === s.pending_buf_size) {
              if (s.gzhead.hcrc && s.pending > beg) {
                strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
              }
              flush_pending(strm);
              beg = s.pending;
              if (s.pending === s.pending_buf_size) {
                break;
              }
            }
            put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
            s.gzindex++;
          }
          if (s.gzhead.hcrc && s.pending > beg) {
            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
          }
          if (s.gzindex === s.gzhead.extra.length) {
            s.gzindex = 0;
            s.status = NAME_STATE;
          }
        }
        else {
          s.status = NAME_STATE;
        }
      }
      Iif (s.status === NAME_STATE) {
        if (s.gzhead.name/* != Z_NULL*/) {
          beg = s.pending;  /* start of bytes to update crc */
          //int val;

          do {
            if (s.pending === s.pending_buf_size) {
              if (s.gzhead.hcrc && s.pending > beg) {
                strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
              }
              flush_pending(strm);
              beg = s.pending;
              if (s.pending === s.pending_buf_size) {
                val = 1;
                break;
              }
            }
            // JS specific: little magic to add zero terminator to end of string
            if (s.gzindex < s.gzhead.name.length) {
              val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
            } else {
              val = 0;
            }
            put_byte(s, val);
          } while (val !== 0);

          if (s.gzhead.hcrc && s.pending > beg) {
            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
          }
          if (val === 0) {
            s.gzindex = 0;
            s.status = COMMENT_STATE;
          }
        }
        else {
          s.status = COMMENT_STATE;
        }
      }
      Iif (s.status === COMMENT_STATE) {
        if (s.gzhead.comment/* != Z_NULL*/) {
          beg = s.pending;  /* start of bytes to update crc */
          //int val;

          do {
            if (s.pending === s.pending_buf_size) {
              if (s.gzhead.hcrc && s.pending > beg) {
                strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
              }
              flush_pending(strm);
              beg = s.pending;
              if (s.pending === s.pending_buf_size) {
                val = 1;
                break;
              }
            }
            // JS specific: little magic to add zero terminator to end of string
            if (s.gzindex < s.gzhead.comment.length) {
              val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
            } else {
              val = 0;
            }
            put_byte(s, val);
          } while (val !== 0);

          if (s.gzhead.hcrc && s.pending > beg) {
            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
          }
          if (val === 0) {
            s.status = HCRC_STATE;
          }
        }
        else {
          s.status = HCRC_STATE;
        }
      }
      Iif (s.status === HCRC_STATE) {
        if (s.gzhead.hcrc) {
          if (s.pending + 2 > s.pending_buf_size) {
            flush_pending(strm);
          }
          if (s.pending + 2 <= s.pending_buf_size) {
            put_byte(s, strm.adler & 0xff);
            put_byte(s, (strm.adler >> 8) & 0xff);
            strm.adler = 0; //crc32(0L, Z_NULL, 0);
            s.status = BUSY_STATE;
          }
        }
        else {
          s.status = BUSY_STATE;
        }
      }
    //#endif

      /* Flush as much pending output as possible */
      Eif (s.pending !== 0) {
        flush_pending(strm);
        Iif (strm.avail_out === 0) {
          /* Since avail_out is 0, deflate will be called again with
           * more output space, but possibly with both pending and
           * avail_in equal to zero. There won't be anything to do,
           * but this is not an error situation so make sure we
           * return OK instead of BUF_ERROR at next call of deflate:
           */
          s.last_flush = -1;
          return Z_OK;
        }

        /* Make sure there is something to do and avoid duplicate consecutive
         * flushes. For repeated and useless calls with Z_FINISH, we keep
         * returning Z_STREAM_END instead of Z_BUF_ERROR.
         */
      } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
        flush !== Z_FINISH) {
        return err(strm, Z_BUF_ERROR);
      }

      /* User must not provide more input after the first FINISH: */
      Iif (s.status === FINISH_STATE && strm.avail_in !== 0) {
        return err(strm, Z_BUF_ERROR);
      }

      /* Start a new block or continue the current one.
       */
      Eif (strm.avail_in !== 0 || s.lookahead !== 0 ||
        (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
        var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
          (s.strategy === Z_RLE ? deflate_rle(s, flush) :
            configuration_table[s.level].func(s, flush));

        Eif (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
          s.status = FINISH_STATE;
        }
        Iif (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
          if (strm.avail_out === 0) {
            s.last_flush = -1;
            /* avoid BUF_ERROR next call, see above */
          }
          return Z_OK;
          /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
           * of deflate should use the same flush parameter to make sure
           * that the flush is complete. So we don't have to output an
           * empty block here, this will be done at next call. This also
           * ensures that for a very small output buffer, we emit at most
           * one empty block.
           */
        }
        Iif (bstate === BS_BLOCK_DONE) {
          if (flush === Z_PARTIAL_FLUSH) {
            trees._tr_align(s);
          }
          else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */

            trees._tr_stored_block(s, 0, 0, false);
            /* For a full flush, this empty block will be recognized
             * as a special marker by inflate_sync().
             */
            if (flush === Z_FULL_FLUSH) {
              /*** CLEAR_HASH(s); ***/             /* forget history */
              zero(s.head); // Fill with NIL (= 0);

              if (s.lookahead === 0) {
                s.strstart = 0;
                s.block_start = 0;
                s.insert = 0;
              }
            }
          }
          flush_pending(strm);
          if (strm.avail_out === 0) {
            s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
            return Z_OK;
          }
        }
      }
      //Assert(strm->avail_out > 0, "bug2");
      //if (strm.avail_out <= 0) { throw new Error("bug2");}

      Iif (flush !== Z_FINISH) { return Z_OK; }
      Iif (s.wrap <= 0) { return Z_STREAM_END; }

      /* Write the trailer */
      Iif (s.wrap === 2) {
        put_byte(s, strm.adler & 0xff);
        put_byte(s, (strm.adler >> 8) & 0xff);
        put_byte(s, (strm.adler >> 16) & 0xff);
        put_byte(s, (strm.adler >> 24) & 0xff);
        put_byte(s, strm.total_in & 0xff);
        put_byte(s, (strm.total_in >> 8) & 0xff);
        put_byte(s, (strm.total_in >> 16) & 0xff);
        put_byte(s, (strm.total_in >> 24) & 0xff);
      }
      else
      {
        putShortMSB(s, strm.adler >>> 16);
        putShortMSB(s, strm.adler & 0xffff);
      }

      flush_pending(strm);
      /* If avail_out is zero, the application will call deflate again
       * to flush the rest.
       */
      Eif (s.wrap > 0) { s.wrap = -s.wrap; }
      /* write the trailer only once! */
      return s.pending !== 0 ? Z_OK : Z_STREAM_END;
    }

    function deflateEnd(strm) {
      var status;

      Iif (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
        return Z_STREAM_ERROR;
      }

      status = strm.state.status;
      Iif (status !== INIT_STATE &&
        status !== EXTRA_STATE &&
        status !== NAME_STATE &&
        status !== COMMENT_STATE &&
        status !== HCRC_STATE &&
        status !== BUSY_STATE &&
        status !== FINISH_STATE
      ) {
        return err(strm, Z_STREAM_ERROR);
      }

      strm.state = null;

      return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
    }

    /* =========================================================================
     * Copy the source state to the destination state
     */
    //function deflateCopy(dest, source) {
    //
    //}

    exports.deflateInit = deflateInit;
    exports.deflateInit2 = deflateInit2;
    exports.deflateReset = deflateReset;
    exports.deflateResetKeep = deflateResetKeep;
    exports.deflateSetHeader = deflateSetHeader;
    exports.deflate = deflate;
    exports.deflateEnd = deflateEnd;
    exports.deflateInfo = 'pako deflate (from Nodeca project)';

    /* Not implemented
    exports.deflateBound = deflateBound;
    exports.deflateCopy = deflateCopy;
    exports.deflateSetDictionary = deflateSetDictionary;
    exports.deflateParams = deflateParams;
    exports.deflatePending = deflatePending;
    exports.deflatePrime = deflatePrime;
    exports.deflateTune = deflateTune;
    */

    },{"../utils/common":83,"./adler32":85,"./crc32":87,"./messages":93,"./trees":94}],89:[function(_dereq_,module,exports){
    'use strict';

    function GZheader() {
      /* true if compressed data believed to be text */
      this.text       = 0;
      /* modification time */
      this.time       = 0;
      /* extra flags (not used when writing a gzip file) */
      this.xflags     = 0;
      /* operating system */
      this.os         = 0;
      /* pointer to extra field or Z_NULL if none */
      this.extra      = null;
      /* extra field length (valid if extra != Z_NULL) */
      this.extra_len  = 0; // Actually, we don't need it in JS,
                           // but leave for few code modifications

      //
      // Setup limits is not necessary because in js we should not preallocate memory
      // for inflate use constant limit in 65536 bytes
      //

      /* space at extra (only when reading header) */
      // this.extra_max  = 0;
      /* pointer to zero-terminated file name or Z_NULL */
      this.name       = '';
      /* space at name (only when reading header) */
      // this.name_max   = 0;
      /* pointer to zero-terminated comment or Z_NULL */
      this.comment    = '';
      /* space at comment (only when reading header) */
      // this.comm_max   = 0;
      /* true if there was or will be a header crc */
      this.hcrc       = 0;
      /* true when done reading gzip header (not used when writing a gzip file) */
      this.done       = false;
    }

    module.exports = GZheader;

    },{}],90:[function(_dereq_,module,exports){
    'use strict';

    // See state defs from inflate.js
    var BAD = 30;       /* got a data error -- remain here until reset */
    var TYPE = 12;      /* i: waiting for type bits, including last-flag bit */

    /*
       Decode literal, length, and distance codes and write out the resulting
       literal and match bytes until either not enough input or output is
       available, an end-of-block is encountered, or a data error is encountered.
       When large enough input and output buffers are supplied to inflate(), for
       example, a 16K input buffer and a 64K output buffer, more than 95% of the
       inflate execution time is spent in this routine.

       Entry assumptions:

            state.mode === LEN
            strm.avail_in >= 6
            strm.avail_out >= 258
            start >= strm.avail_out
            state.bits < 8

       On return, state.mode is one of:

            LEN -- ran out of enough output space or enough available input
            TYPE -- reached end of block code, inflate() to interpret next block
            BAD -- error in block data

       Notes:

        - The maximum input bits used by a length/distance pair is 15 bits for the
          length code, 5 bits for the length extra, 15 bits for the distance code,
          and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
          Therefore if strm.avail_in >= 6, then there is enough input to avoid
          checking for available input while decoding.

        - The maximum bytes that a single length/distance pair can output is 258
          bytes, which is the maximum length that can be coded.  inflate_fast()
          requires strm.avail_out >= 258 for each loop to avoid checking for
          output space.
     */
    module.exports = function inflate_fast(strm, start) {
      var state;
      var _in;                    /* local strm.input */
      var last;                   /* have enough input while in < last */
      var _out;                   /* local strm.output */
      var beg;                    /* inflate()'s initial strm.output */
      var end;                    /* while out < end, enough space available */
    //#ifdef INFLATE_STRICT
      var dmax;                   /* maximum distance from zlib header */
    //#endif
      var wsize;                  /* window size or zero if not using window */
      var whave;                  /* valid bytes in the window */
      var wnext;                  /* window write index */
      // Use `s_window` instead `window`, avoid conflict with instrumentation tools
      var s_window;               /* allocated sliding window, if wsize != 0 */
      var hold;                   /* local strm.hold */
      var bits;                   /* local strm.bits */
      var lcode;                  /* local strm.lencode */
      var dcode;                  /* local strm.distcode */
      var lmask;                  /* mask for first level of length codes */
      var dmask;                  /* mask for first level of distance codes */
      var here;                   /* retrieved table entry */
      var op;                     /* code bits, operation, extra bits, or */
                                  /*  window position, window bytes to copy */
      var len;                    /* match length, unused bytes */
      var dist;                   /* match distance */
      var from;                   /* where to copy match from */
      var from_source;

      var input, output; // JS specific, because we have no pointers

      /* copy state to local variables */
      state = strm.state;
      //here = state.here;
      _in = strm.next_in;
      input = strm.input;
      last = _in + (strm.avail_in - 5);
      _out = strm.next_out;
      output = strm.output;
      beg = _out - (start - strm.avail_out);
      end = _out + (strm.avail_out - 257);
    //#ifdef INFLATE_STRICT
      dmax = state.dmax;
    //#endif
      wsize = state.wsize;
      whave = state.whave;
      wnext = state.wnext;
      s_window = state.window;
      hold = state.hold;
      bits = state.bits;
      lcode = state.lencode;
      dcode = state.distcode;
      lmask = (1 << state.lenbits) - 1;
      dmask = (1 << state.distbits) - 1;

      /* decode literals and length/distances until end-of-block or not enough
         input data or output space */

      top:
      do {
        if (bits < 15) {
          hold += input[_in++] << bits;
          bits += 8;
          hold += input[_in++] << bits;
          bits += 8;
        }

        here = lcode[hold & lmask];

        dolen:
        for (;;) { // Goto emulation
          op = here >>> 24/*here.bits*/;
          hold >>>= op;
          bits -= op;
          op = (here >>> 16) & 0xff/*here.op*/;
          if (op === 0) {                          /* literal */
            //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
            //        "inflate:         literal '%c'\n" :
            //        "inflate:         literal 0x%02x\n", here.val));
            output[_out++] = here & 0xffff/*here.val*/;
          }
          else if (op & 16) {                     /* length base */
            len = here & 0xffff/*here.val*/;
            op &= 15;                           /* number of extra bits */
            if (op) {
              if (bits < op) {
                hold += input[_in++] << bits;
                bits += 8;
              }
              len += hold & ((1 << op) - 1);
              hold >>>= op;
              bits -= op;
            }
            //Tracevv((stderr, "inflate:         length %u\n", len));
            if (bits < 15) {
              hold += input[_in++] << bits;
              bits += 8;
              hold += input[_in++] << bits;
              bits += 8;
            }
            here = dcode[hold & dmask];

            dodist:
            for (;;) { // goto emulation
              op = here >>> 24/*here.bits*/;
              hold >>>= op;
              bits -= op;
              op = (here >>> 16) & 0xff/*here.op*/;

              if (op & 16) {                      /* distance base */
                dist = here & 0xffff/*here.val*/;
                op &= 15;                       /* number of extra bits */
                if (bits < op) {
                  hold += input[_in++] << bits;
                  bits += 8;
                  if (bits < op) {
                    hold += input[_in++] << bits;
                    bits += 8;
                  }
                }
                dist += hold & ((1 << op) - 1);
    //#ifdef INFLATE_STRICT
                if (dist > dmax) {
                  strm.msg = 'invalid distance too far back';
                  state.mode = BAD;
                  break top;
                }
    //#endif
                hold >>>= op;
                bits -= op;
                //Tracevv((stderr, "inflate:         distance %u\n", dist));
                op = _out - beg;                /* max distance in output */
                if (dist > op) {                /* see if copy from window */
                  op = dist - op;               /* distance back in window */
                  if (op > whave) {
                    if (state.sane) {
                      strm.msg = 'invalid distance too far back';
                      state.mode = BAD;
                      break top;
                    }

    // (!) This block is disabled in zlib defailts,
    // don't enable it for binary compatibility
    //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
    //                if (len <= op - whave) {
    //                  do {
    //                    output[_out++] = 0;
    //                  } while (--len);
    //                  continue top;
    //                }
    //                len -= op - whave;
    //                do {
    //                  output[_out++] = 0;
    //                } while (--op > whave);
    //                if (op === 0) {
    //                  from = _out - dist;
    //                  do {
    //                    output[_out++] = output[from++];
    //                  } while (--len);
    //                  continue top;
    //                }
    //#endif
                  }
                  from = 0; // window index
                  from_source = s_window;
                  if (wnext === 0) {           /* very common case */
                    from += wsize - op;
                    if (op < len) {         /* some from window */
                      len -= op;
                      do {
                        output[_out++] = s_window[from++];
                      } while (--op);
                      from = _out - dist;  /* rest from output */
                      from_source = output;
                    }
                  }
                  else if (wnext < op) {      /* wrap around window */
                    from += wsize + wnext - op;
                    op -= wnext;
                    if (op < len) {         /* some from end of window */
                      len -= op;
                      do {
                        output[_out++] = s_window[from++];
                      } while (--op);
                      from = 0;
                      if (wnext < len) {  /* some from start of window */
                        op = wnext;
                        len -= op;
                        do {
                          output[_out++] = s_window[from++];
                        } while (--op);
                        from = _out - dist;      /* rest from output */
                        from_source = output;
                      }
                    }
                  }
                  else {                      /* contiguous in window */
                    from += wnext - op;
                    if (op < len) {         /* some from window */
                      len -= op;
                      do {
                        output[_out++] = s_window[from++];
                      } while (--op);
                      from = _out - dist;  /* rest from output */
                      from_source = output;
                    }
                  }
                  while (len > 2) {
                    output[_out++] = from_source[from++];
                    output[_out++] = from_source[from++];
                    output[_out++] = from_source[from++];
                    len -= 3;
                  }
                  if (len) {
                    output[_out++] = from_source[from++];
                    if (len > 1) {
                      output[_out++] = from_source[from++];
                    }
                  }
                }
                else {
                  from = _out - dist;          /* copy direct from output */
                  do {                        /* minimum length is three */
                    output[_out++] = output[from++];
                    output[_out++] = output[from++];
                    output[_out++] = output[from++];
                    len -= 3;
                  } while (len > 2);
                  if (len) {
                    output[_out++] = output[from++];
                    if (len > 1) {
                      output[_out++] = output[from++];
                    }
                  }
                }
              }
              else if ((op & 64) === 0) {          /* 2nd level distance code */
                here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
                continue dodist;
              }
              else {
                strm.msg = 'invalid distance code';
                state.mode = BAD;
                break top;
              }

              break; // need to emulate goto via "continue"
            }
          }
          else if ((op & 64) === 0) {              /* 2nd level length code */
            here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
            continue dolen;
          }
          else if (op & 32) {                     /* end-of-block */
            //Tracevv((stderr, "inflate:         end of block\n"));
            state.mode = TYPE;
            break top;
          }
          else {
            strm.msg = 'invalid literal/length code';
            state.mode = BAD;
            break top;
          }

          break; // need to emulate goto via "continue"
        }
      } while (_in < last && _out < end);

      /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
      len = bits >> 3;
      _in -= len;
      bits -= len << 3;
      hold &= (1 << bits) - 1;

      /* update state and return */
      strm.next_in = _in;
      strm.next_out = _out;
      strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
      strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
      state.hold = hold;
      state.bits = bits;
      return;
    };

    },{}],91:[function(_dereq_,module,exports){
    'use strict';

    var utils = _dereq_('../utils/common');
    var adler32 = _dereq_('./adler32');
    var crc32   = _dereq_('./crc32');
    var inflate_fast = _dereq_('./inffast');
    var inflate_table = _dereq_('./inftrees');

    var CODES = 0;
    var LENS = 1;
    var DISTS = 2;

    /* Public constants ==========================================================*/
    /* ===========================================================================*/

    /* Allowed flush values; see deflate() and inflate() below for details */
    //var Z_NO_FLUSH      = 0;
    //var Z_PARTIAL_FLUSH = 1;
    //var Z_SYNC_FLUSH    = 2;
    //var Z_FULL_FLUSH    = 3;
    var Z_FINISH        = 4;
    var Z_BLOCK         = 5;
    var Z_TREES         = 6;

    /* Return codes for the compression/decompression functions. Negative values
     * are errors, positive values are used for special but normal events.
     */
    var Z_OK            = 0;
    var Z_STREAM_END    = 1;
    var Z_NEED_DICT     = 2;
    //var Z_ERRNO         = -1;
    var Z_STREAM_ERROR  = -2;
    var Z_DATA_ERROR    = -3;
    var Z_MEM_ERROR     = -4;
    var Z_BUF_ERROR     = -5;
    //var Z_VERSION_ERROR = -6;

    /* The deflate compression method */
    var Z_DEFLATED  = 8;

    /* STATES ====================================================================*/
    /* ===========================================================================*/

    var    HEAD = 1;       /* i: waiting for magic header */
    var    FLAGS = 2;      /* i: waiting for method and flags (gzip) */
    var    TIME = 3;       /* i: waiting for modification time (gzip) */
    var    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */
    var    EXLEN = 5;      /* i: waiting for extra length (gzip) */
    var    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */
    var    NAME = 7;       /* i: waiting for end of file name (gzip) */
    var    COMMENT = 8;    /* i: waiting for end of comment (gzip) */
    var    HCRC = 9;       /* i: waiting for header crc (gzip) */
    var    DICTID = 10;    /* i: waiting for dictionary check value */
    var    DICT = 11;      /* waiting for inflateSetDictionary() call */
    var        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
    var        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */
    var        STORED = 14;    /* i: waiting for stored size (length and complement) */
    var        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */
    var        COPY = 16;      /* i/o: waiting for input or output to copy stored block */
    var        TABLE = 17;     /* i: waiting for dynamic block table lengths */
    var        LENLENS = 18;   /* i: waiting for code length code lengths */
    var        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */
    var            LEN_ = 20;      /* i: same as LEN below, but only first time in */
    var            LEN = 21;       /* i: waiting for length/lit/eob code */
    var            LENEXT = 22;    /* i: waiting for length extra bits */
    var            DIST = 23;      /* i: waiting for distance code */
    var            DISTEXT = 24;   /* i: waiting for distance extra bits */
    var            MATCH = 25;     /* o: waiting for output space to copy string */
    var            LIT = 26;       /* o: waiting for output space to write literal */
    var    CHECK = 27;     /* i: waiting for 32-bit check value */
    var    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */
    var    DONE = 29;      /* finished check, done -- remain here until reset */
    var    BAD = 30;       /* got a data error -- remain here until reset */
    var    MEM = 31;       /* got an inflate() memory error -- remain here until reset */
    var    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */

    /* ===========================================================================*/

    var ENOUGH_LENS = 852;
    var ENOUGH_DISTS = 592;
    //var ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);

    var MAX_WBITS = 15;
    /* 32K LZ77 window */
    var DEF_WBITS = MAX_WBITS;

    function ZSWAP32(q) {
      return  (((q >>> 24) & 0xff) +
              ((q >>> 8) & 0xff00) +
              ((q & 0xff00) << 8) +
              ((q & 0xff) << 24));
    }

    function InflateState() {
      this.mode = 0;             /* current inflate mode */
      this.last = false;          /* true if processing last block */
      this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
      this.havedict = false;      /* true if dictionary provided */
      this.flags = 0;             /* gzip header method and flags (0 if zlib) */
      this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */
      this.check = 0;             /* protected copy of check value */
      this.total = 0;             /* protected copy of output count */
      // TODO: may be {}
      this.head = null;           /* where to save gzip header information */

      /* sliding window */
      this.wbits = 0;             /* log base 2 of requested window size */
      this.wsize = 0;             /* window size or zero if not using window */
      this.whave = 0;             /* valid bytes in the window */
      this.wnext = 0;             /* window write index */
      this.window = null;         /* allocated sliding window, if needed */

      /* bit accumulator */
      this.hold = 0;              /* input bit accumulator */
      this.bits = 0;              /* number of bits in "in" */

      /* for string and stored block copying */
      this.length = 0;            /* literal or length of data to copy */
      this.offset = 0;            /* distance back to copy string from */

      /* for table and code decoding */
      this.extra = 0;             /* extra bits needed */

      /* fixed and dynamic code tables */
      this.lencode = null;          /* starting table for length/literal codes */
      this.distcode = null;         /* starting table for distance codes */
      this.lenbits = 0;           /* index bits for lencode */
      this.distbits = 0;          /* index bits for distcode */

      /* dynamic table building */
      this.ncode = 0;             /* number of code length code lengths */
      this.nlen = 0;              /* number of length code lengths */
      this.ndist = 0;             /* number of distance code lengths */
      this.have = 0;              /* number of code lengths in lens[] */
      this.next = null;              /* next available space in codes[] */

      this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
      this.work = new utils.Buf16(288); /* work area for code table building */

      /*
       because we don't have pointers in js, we use lencode and distcode directly
       as buffers so we don't need codes
      */
      //this.codes = new utils.Buf32(ENOUGH);       /* space for code tables */
      this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */
      this.distdyn = null;             /* dynamic table for distance codes (JS specific) */
      this.sane = 0;                   /* if false, allow invalid distance too far */
      this.back = 0;                   /* bits back of last unprocessed length/lit */
      this.was = 0;                    /* initial length of match */
    }

    function inflateResetKeep(strm) {
      var state;

      if (!strm || !strm.state) { return Z_STREAM_ERROR; }
      state = strm.state;
      strm.total_in = strm.total_out = state.total = 0;
      strm.msg = ''; /*Z_NULL*/
      if (state.wrap) {       /* to support ill-conceived Java test suite */
        strm.adler = state.wrap & 1;
      }
      state.mode = HEAD;
      state.last = 0;
      state.havedict = 0;
      state.dmax = 32768;
      state.head = null/*Z_NULL*/;
      state.hold = 0;
      state.bits = 0;
      //state.lencode = state.distcode = state.next = state.codes;
      state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
      state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);

      state.sane = 1;
      state.back = -1;
      //Tracev((stderr, "inflate: reset\n"));
      return Z_OK;
    }

    function inflateReset(strm) {
      var state;

      if (!strm || !strm.state) { return Z_STREAM_ERROR; }
      state = strm.state;
      state.wsize = 0;
      state.whave = 0;
      state.wnext = 0;
      return inflateResetKeep(strm);

    }

    function inflateReset2(strm, windowBits) {
      var wrap;
      var state;

      /* get the state */
      if (!strm || !strm.state) { return Z_STREAM_ERROR; }
      state = strm.state;

      /* extract wrap request from windowBits parameter */
      if (windowBits < 0) {
        wrap = 0;
        windowBits = -windowBits;
      }
      else {
        wrap = (windowBits >> 4) + 1;
        if (windowBits < 48) {
          windowBits &= 15;
        }
      }

      /* set number of window bits, free window if different */
      if (windowBits && (windowBits < 8 || windowBits > 15)) {
        return Z_STREAM_ERROR;
      }
      if (state.window !== null && state.wbits !== windowBits) {
        state.window = null;
      }

      /* update state and reset the rest of it */
      state.wrap = wrap;
      state.wbits = windowBits;
      return inflateReset(strm);
    }

    function inflateInit2(strm, windowBits) {
      var ret;
      var state;

      if (!strm) { return Z_STREAM_ERROR; }
      //strm.msg = Z_NULL;                 /* in case we return an error */

      state = new InflateState();

      //if (state === Z_NULL) return Z_MEM_ERROR;
      //Tracev((stderr, "inflate: allocated\n"));
      strm.state = state;
      state.window = null/*Z_NULL*/;
      ret = inflateReset2(strm, windowBits);
      if (ret !== Z_OK) {
        strm.state = null/*Z_NULL*/;
      }
      return ret;
    }

    function inflateInit(strm) {
      return inflateInit2(strm, DEF_WBITS);
    }

    /*
     Return state with length and distance decoding tables and index sizes set to
     fixed code decoding.  Normally this returns fixed tables from inffixed.h.
     If BUILDFIXED is defined, then instead this routine builds the tables the
     first time it's called, and returns those tables the first time and
     thereafter.  This reduces the size of the code by about 2K bytes, in
     exchange for a little execution time.  However, BUILDFIXED should not be
     used for threaded applications, since the rewriting of the tables and virgin
     may not be thread-safe.
     */
    var virgin = true;

    var lenfix, distfix; // We have no pointers in JS, so keep tables separate

    function fixedtables(state) {
      /* build fixed huffman tables if first call (may not be thread safe) */
      if (virgin) {
        var sym;

        lenfix = new utils.Buf32(512);
        distfix = new utils.Buf32(32);

        /* literal/length table */
        sym = 0;
        while (sym < 144) { state.lens[sym++] = 8; }
        while (sym < 256) { state.lens[sym++] = 9; }
        while (sym < 280) { state.lens[sym++] = 7; }
        while (sym < 288) { state.lens[sym++] = 8; }

        inflate_table(LENS,  state.lens, 0, 288, lenfix,   0, state.work, {bits: 9});

        /* distance table */
        sym = 0;
        while (sym < 32) { state.lens[sym++] = 5; }

        inflate_table(DISTS, state.lens, 0, 32,   distfix, 0, state.work, {bits: 5});

        /* do this just once */
        virgin = false;
      }

      state.lencode = lenfix;
      state.lenbits = 9;
      state.distcode = distfix;
      state.distbits = 5;
    }

    /*
     Update the window with the last wsize (normally 32K) bytes written before
     returning.  If window does not exist yet, create it.  This is only called
     when a window is already in use, or when output has been written during this
     inflate call, but the end of the deflate stream has not been reached yet.
     It is also called to create a window for dictionary data when a dictionary
     is loaded.

     Providing output buffers larger than 32K to inflate() should provide a speed
     advantage, since only the last 32K of output is copied to the sliding window
     upon return from inflate(), and since all distances after the first 32K of
     output will fall in the output data, making match copies simpler and faster.
     The advantage may be dependent on the size of the processor's data caches.
     */
    function updatewindow(strm, src, end, copy) {
      var dist;
      var state = strm.state;

      /* if it hasn't been done already, allocate space for the window */
      if (state.window === null) {
        state.wsize = 1 << state.wbits;
        state.wnext = 0;
        state.whave = 0;

        state.window = new utils.Buf8(state.wsize);
      }

      /* copy state->wsize or less output bytes into the circular window */
      if (copy >= state.wsize) {
        utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0);
        state.wnext = 0;
        state.whave = state.wsize;
      }
      else {
        dist = state.wsize - state.wnext;
        if (dist > copy) {
          dist = copy;
        }
        //zmemcpy(state->window + state->wnext, end - copy, dist);
        utils.arraySet(state.window,src, end - copy, dist, state.wnext);
        copy -= dist;
        if (copy) {
          //zmemcpy(state->window, end - copy, copy);
          utils.arraySet(state.window,src, end - copy, copy, 0);
          state.wnext = copy;
          state.whave = state.wsize;
        }
        else {
          state.wnext += dist;
          if (state.wnext === state.wsize) { state.wnext = 0; }
          if (state.whave < state.wsize) { state.whave += dist; }
        }
      }
      return 0;
    }

    function inflate(strm, flush) {
      var state;
      var input, output;          // input/output buffers
      var next;                   /* next input INDEX */
      var put;                    /* next output INDEX */
      var have, left;             /* available input and output */
      var hold;                   /* bit buffer */
      var bits;                   /* bits in bit buffer */
      var _in, _out;              /* save starting available input and output */
      var copy;                   /* number of stored or match bytes to copy */
      var from;                   /* where to copy match bytes from */
      var from_source;
      var here = 0;               /* current decoding table entry */
      var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
      //var last;                   /* parent table entry */
      var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
      var len;                    /* length to copy for repeats, bits to drop */
      var ret;                    /* return code */
      var hbuf = new utils.Buf8(4);    /* buffer for gzip header crc calculation */
      var opts;

      var n; // temporary var for NEED_BITS

      var order = /* permutation of code lengths */
        [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];

      if (!strm || !strm.state || !strm.output ||
          (!strm.input && strm.avail_in !== 0)) {
        return Z_STREAM_ERROR;
      }

      state = strm.state;
      if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */

      //--- LOAD() ---
      put = strm.next_out;
      output = strm.output;
      left = strm.avail_out;
      next = strm.next_in;
      input = strm.input;
      have = strm.avail_in;
      hold = state.hold;
      bits = state.bits;
      //---

      _in = have;
      _out = left;
      ret = Z_OK;

      inf_leave: // goto emulation
      for (;;) {
        switch (state.mode) {
        case HEAD:
          if (state.wrap === 0) {
            state.mode = TYPEDO;
            break;
          }
          //=== NEEDBITS(16);
          while (bits < 16) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */
            state.check = 0/*crc32(0L, Z_NULL, 0)*/;
            //=== CRC2(state.check, hold);
            hbuf[0] = hold & 0xff;
            hbuf[1] = (hold >>> 8) & 0xff;
            state.check = crc32(state.check, hbuf, 2, 0);
            //===//

            //=== INITBITS();
            hold = 0;
            bits = 0;
            //===//
            state.mode = FLAGS;
            break;
          }
          state.flags = 0;           /* expect zlib header */
          if (state.head) {
            state.head.done = false;
          }
          if (!(state.wrap & 1) ||   /* check if zlib header allowed */
            (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
            strm.msg = 'incorrect header check';
            state.mode = BAD;
            break;
          }
          if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
            strm.msg = 'unknown compression method';
            state.mode = BAD;
            break;
          }
          //--- DROPBITS(4) ---//
          hold >>>= 4;
          bits -= 4;
          //---//
          len = (hold & 0x0f)/*BITS(4)*/ + 8;
          if (state.wbits === 0) {
            state.wbits = len;
          }
          else if (len > state.wbits) {
            strm.msg = 'invalid window size';
            state.mode = BAD;
            break;
          }
          state.dmax = 1 << len;
          //Tracev((stderr, "inflate:   zlib header ok\n"));
          strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
          state.mode = hold & 0x200 ? DICTID : TYPE;
          //=== INITBITS();
          hold = 0;
          bits = 0;
          //===//
          break;
        case FLAGS:
          //=== NEEDBITS(16); */
          while (bits < 16) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          state.flags = hold;
          if ((state.flags & 0xff) !== Z_DEFLATED) {
            strm.msg = 'unknown compression method';
            state.mode = BAD;
            break;
          }
          if (state.flags & 0xe000) {
            strm.msg = 'unknown header flags set';
            state.mode = BAD;
            break;
          }
          if (state.head) {
            state.head.text = ((hold >> 8) & 1);
          }
          if (state.flags & 0x0200) {
            //=== CRC2(state.check, hold);
            hbuf[0] = hold & 0xff;
            hbuf[1] = (hold >>> 8) & 0xff;
            state.check = crc32(state.check, hbuf, 2, 0);
            //===//
          }
          //=== INITBITS();
          hold = 0;
          bits = 0;
          //===//
          state.mode = TIME;
          /* falls through */
        case TIME:
          //=== NEEDBITS(32); */
          while (bits < 32) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          if (state.head) {
            state.head.time = hold;
          }
          if (state.flags & 0x0200) {
            //=== CRC4(state.check, hold)
            hbuf[0] = hold & 0xff;
            hbuf[1] = (hold >>> 8) & 0xff;
            hbuf[2] = (hold >>> 16) & 0xff;
            hbuf[3] = (hold >>> 24) & 0xff;
            state.check = crc32(state.check, hbuf, 4, 0);
            //===
          }
          //=== INITBITS();
          hold = 0;
          bits = 0;
          //===//
          state.mode = OS;
          /* falls through */
        case OS:
          //=== NEEDBITS(16); */
          while (bits < 16) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          if (state.head) {
            state.head.xflags = (hold & 0xff);
            state.head.os = (hold >> 8);
          }
          if (state.flags & 0x0200) {
            //=== CRC2(state.check, hold);
            hbuf[0] = hold & 0xff;
            hbuf[1] = (hold >>> 8) & 0xff;
            state.check = crc32(state.check, hbuf, 2, 0);
            //===//
          }
          //=== INITBITS();
          hold = 0;
          bits = 0;
          //===//
          state.mode = EXLEN;
          /* falls through */
        case EXLEN:
          if (state.flags & 0x0400) {
            //=== NEEDBITS(16); */
            while (bits < 16) {
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
            }
            //===//
            state.length = hold;
            if (state.head) {
              state.head.extra_len = hold;
            }
            if (state.flags & 0x0200) {
              //=== CRC2(state.check, hold);
              hbuf[0] = hold & 0xff;
              hbuf[1] = (hold >>> 8) & 0xff;
              state.check = crc32(state.check, hbuf, 2, 0);
              //===//
            }
            //=== INITBITS();
            hold = 0;
            bits = 0;
            //===//
          }
          else if (state.head) {
            state.head.extra = null/*Z_NULL*/;
          }
          state.mode = EXTRA;
          /* falls through */
        case EXTRA:
          if (state.flags & 0x0400) {
            copy = state.length;
            if (copy > have) { copy = have; }
            if (copy) {
              if (state.head) {
                len = state.head.extra_len - state.length;
                if (!state.head.extra) {
                  // Use untyped array for more conveniend processing later
                  state.head.extra = new Array(state.head.extra_len);
                }
                utils.arraySet(
                  state.head.extra,
                  input,
                  next,
                  // extra field is limited to 65536 bytes
                  // - no need for additional size check
                  copy,
                  /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
                  len
                );
                //zmemcpy(state.head.extra + len, next,
                //        len + copy > state.head.extra_max ?
                //        state.head.extra_max - len : copy);
              }
              if (state.flags & 0x0200) {
                state.check = crc32(state.check, input, copy, next);
              }
              have -= copy;
              next += copy;
              state.length -= copy;
            }
            if (state.length) { break inf_leave; }
          }
          state.length = 0;
          state.mode = NAME;
          /* falls through */
        case NAME:
          if (state.flags & 0x0800) {
            if (have === 0) { break inf_leave; }
            copy = 0;
            do {
              // TODO: 2 or 1 bytes?
              len = input[next + copy++];
              /* use constant limit because in js we should not preallocate memory */
              if (state.head && len &&
                  (state.length < 65536 /*state.head.name_max*/)) {
                state.head.name += String.fromCharCode(len);
              }
            } while (len && copy < have);

            if (state.flags & 0x0200) {
              state.check = crc32(state.check, input, copy, next);
            }
            have -= copy;
            next += copy;
            if (len) { break inf_leave; }
          }
          else if (state.head) {
            state.head.name = null;
          }
          state.length = 0;
          state.mode = COMMENT;
          /* falls through */
        case COMMENT:
          if (state.flags & 0x1000) {
            if (have === 0) { break inf_leave; }
            copy = 0;
            do {
              len = input[next + copy++];
              /* use constant limit because in js we should not preallocate memory */
              if (state.head && len &&
                  (state.length < 65536 /*state.head.comm_max*/)) {
                state.head.comment += String.fromCharCode(len);
              }
            } while (len && copy < have);
            if (state.flags & 0x0200) {
              state.check = crc32(state.check, input, copy, next);
            }
            have -= copy;
            next += copy;
            if (len) { break inf_leave; }
          }
          else if (state.head) {
            state.head.comment = null;
          }
          state.mode = HCRC;
          /* falls through */
        case HCRC:
          if (state.flags & 0x0200) {
            //=== NEEDBITS(16); */
            while (bits < 16) {
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
            }
            //===//
            if (hold !== (state.check & 0xffff)) {
              strm.msg = 'header crc mismatch';
              state.mode = BAD;
              break;
            }
            //=== INITBITS();
            hold = 0;
            bits = 0;
            //===//
          }
          if (state.head) {
            state.head.hcrc = ((state.flags >> 9) & 1);
            state.head.done = true;
          }
          strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/;
          state.mode = TYPE;
          break;
        case DICTID:
          //=== NEEDBITS(32); */
          while (bits < 32) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          strm.adler = state.check = ZSWAP32(hold);
          //=== INITBITS();
          hold = 0;
          bits = 0;
          //===//
          state.mode = DICT;
          /* falls through */
        case DICT:
          if (state.havedict === 0) {
            //--- RESTORE() ---
            strm.next_out = put;
            strm.avail_out = left;
            strm.next_in = next;
            strm.avail_in = have;
            state.hold = hold;
            state.bits = bits;
            //---
            return Z_NEED_DICT;
          }
          strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
          state.mode = TYPE;
          /* falls through */
        case TYPE:
          if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
          /* falls through */
        case TYPEDO:
          if (state.last) {
            //--- BYTEBITS() ---//
            hold >>>= bits & 7;
            bits -= bits & 7;
            //---//
            state.mode = CHECK;
            break;
          }
          //=== NEEDBITS(3); */
          while (bits < 3) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          state.last = (hold & 0x01)/*BITS(1)*/;
          //--- DROPBITS(1) ---//
          hold >>>= 1;
          bits -= 1;
          //---//

          switch ((hold & 0x03)/*BITS(2)*/) {
          case 0:                             /* stored block */
            //Tracev((stderr, "inflate:     stored block%s\n",
            //        state.last ? " (last)" : ""));
            state.mode = STORED;
            break;
          case 1:                             /* fixed block */
            fixedtables(state);
            //Tracev((stderr, "inflate:     fixed codes block%s\n",
            //        state.last ? " (last)" : ""));
            state.mode = LEN_;             /* decode codes */
            if (flush === Z_TREES) {
              //--- DROPBITS(2) ---//
              hold >>>= 2;
              bits -= 2;
              //---//
              break inf_leave;
            }
            break;
          case 2:                             /* dynamic block */
            //Tracev((stderr, "inflate:     dynamic codes block%s\n",
            //        state.last ? " (last)" : ""));
            state.mode = TABLE;
            break;
          case 3:
            strm.msg = 'invalid block type';
            state.mode = BAD;
          }
          //--- DROPBITS(2) ---//
          hold >>>= 2;
          bits -= 2;
          //---//
          break;
        case STORED:
          //--- BYTEBITS() ---// /* go to byte boundary */
          hold >>>= bits & 7;
          bits -= bits & 7;
          //---//
          //=== NEEDBITS(32); */
          while (bits < 32) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
            strm.msg = 'invalid stored block lengths';
            state.mode = BAD;
            break;
          }
          state.length = hold & 0xffff;
          //Tracev((stderr, "inflate:       stored length %u\n",
          //        state.length));
          //=== INITBITS();
          hold = 0;
          bits = 0;
          //===//
          state.mode = COPY_;
          if (flush === Z_TREES) { break inf_leave; }
          /* falls through */
        case COPY_:
          state.mode = COPY;
          /* falls through */
        case COPY:
          copy = state.length;
          if (copy) {
            if (copy > have) { copy = have; }
            if (copy > left) { copy = left; }
            if (copy === 0) { break inf_leave; }
            //--- zmemcpy(put, next, copy); ---
            utils.arraySet(output, input, next, copy, put);
            //---//
            have -= copy;
            next += copy;
            left -= copy;
            put += copy;
            state.length -= copy;
            break;
          }
          //Tracev((stderr, "inflate:       stored end\n"));
          state.mode = TYPE;
          break;
        case TABLE:
          //=== NEEDBITS(14); */
          while (bits < 14) {
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
          }
          //===//
          state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
          //--- DROPBITS(5) ---//
          hold >>>= 5;
          bits -= 5;
          //---//
          state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
          //--- DROPBITS(5) ---//
          hold >>>= 5;
          bits -= 5;
          //---//
          state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
          //--- DROPBITS(4) ---//
          hold >>>= 4;
          bits -= 4;
          //---//
    //#ifndef PKZIP_BUG_WORKAROUND
          if (state.nlen > 286 || state.ndist > 30) {
            strm.msg = 'too many length or distance symbols';
            state.mode = BAD;
            break;
          }
    //#endif
          //Tracev((stderr, "inflate:       table sizes ok\n"));
          state.have = 0;
          state.mode = LENLENS;
          /* falls through */
        case LENLENS:
          while (state.have < state.ncode) {
            //=== NEEDBITS(3);
            while (bits < 3) {
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
            }
            //===//
            state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
            //--- DROPBITS(3) ---//
            hold >>>= 3;
            bits -= 3;
            //---//
          }
          while (state.have < 19) {
            state.lens[order[state.have++]] = 0;
          }
          // We have separate tables & no pointers. 2 commented lines below not needed.
          //state.next = state.codes;
          //state.lencode = state.next;
          // Switch to use dynamic table
          state.lencode = state.lendyn;
          state.lenbits = 7;

          opts = {bits: state.lenbits};
          ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
          state.lenbits = opts.bits;

          if (ret) {
            strm.msg = 'invalid code lengths set';
            state.mode = BAD;
            break;
          }
          //Tracev((stderr, "inflate:       code lengths ok\n"));
          state.have = 0;
          state.mode = CODELENS;
          /* falls through */
        case CODELENS:
          while (state.have < state.nlen + state.ndist) {
            for (;;) {
              here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
              here_bits = here >>> 24;
              here_op = (here >>> 16) & 0xff;
              here_val = here & 0xffff;

              if ((here_bits) <= bits) { break; }
              //--- PULLBYTE() ---//
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
              //---//
            }
            if (here_val < 16) {
              //--- DROPBITS(here.bits) ---//
              hold >>>= here_bits;
              bits -= here_bits;
              //---//
              state.lens[state.have++] = here_val;
            }
            else {
              if (here_val === 16) {
                //=== NEEDBITS(here.bits + 2);
                n = here_bits + 2;
                while (bits < n) {
                  if (have === 0) { break inf_leave; }
                  have--;
                  hold += input[next++] << bits;
                  bits += 8;
                }
                //===//
                //--- DROPBITS(here.bits) ---//
                hold >>>= here_bits;
                bits -= here_bits;
                //---//
                if (state.have === 0) {
                  strm.msg = 'invalid bit length repeat';
                  state.mode = BAD;
                  break;
                }
                len = state.lens[state.have - 1];
                copy = 3 + (hold & 0x03);//BITS(2);
                //--- DROPBITS(2) ---//
                hold >>>= 2;
                bits -= 2;
                //---//
              }
              else if (here_val === 17) {
                //=== NEEDBITS(here.bits + 3);
                n = here_bits + 3;
                while (bits < n) {
                  if (have === 0) { break inf_leave; }
                  have--;
                  hold += input[next++] << bits;
                  bits += 8;
                }
                //===//
                //--- DROPBITS(here.bits) ---//
                hold >>>= here_bits;
                bits -= here_bits;
                //---//
                len = 0;
                copy = 3 + (hold & 0x07);//BITS(3);
                //--- DROPBITS(3) ---//
                hold >>>= 3;
                bits -= 3;
                //---//
              }
              else {
                //=== NEEDBITS(here.bits + 7);
                n = here_bits + 7;
                while (bits < n) {
                  if (have === 0) { break inf_leave; }
                  have--;
                  hold += input[next++] << bits;
                  bits += 8;
                }
                //===//
                //--- DROPBITS(here.bits) ---//
                hold >>>= here_bits;
                bits -= here_bits;
                //---//
                len = 0;
                copy = 11 + (hold & 0x7f);//BITS(7);
                //--- DROPBITS(7) ---//
                hold >>>= 7;
                bits -= 7;
                //---//
              }
              if (state.have + copy > state.nlen + state.ndist) {
                strm.msg = 'invalid bit length repeat';
                state.mode = BAD;
                break;
              }
              while (copy--) {
                state.lens[state.have++] = len;
              }
            }
          }

          /* handle error breaks in while */
          if (state.mode === BAD) { break; }

          /* check for end-of-block code (better have one) */
          if (state.lens[256] === 0) {
            strm.msg = 'invalid code -- missing end-of-block';
            state.mode = BAD;
            break;
          }

          /* build code tables -- note: do not change the lenbits or distbits
             values here (9 and 6) without reading the comments in inftrees.h
             concerning the ENOUGH constants, which depend on those values */
          state.lenbits = 9;

          opts = {bits: state.lenbits};
          ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
          // We have separate tables & no pointers. 2 commented lines below not needed.
          // state.next_index = opts.table_index;
          state.lenbits = opts.bits;
          // state.lencode = state.next;

          if (ret) {
            strm.msg = 'invalid literal/lengths set';
            state.mode = BAD;
            break;
          }

          state.distbits = 6;
          //state.distcode.copy(state.codes);
          // Switch to use dynamic table
          state.distcode = state.distdyn;
          opts = {bits: state.distbits};
          ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
          // We have separate tables & no pointers. 2 commented lines below not needed.
          // state.next_index = opts.table_index;
          state.distbits = opts.bits;
          // state.distcode = state.next;

          if (ret) {
            strm.msg = 'invalid distances set';
            state.mode = BAD;
            break;
          }
          //Tracev((stderr, 'inflate:       codes ok\n'));
          state.mode = LEN_;
          if (flush === Z_TREES) { break inf_leave; }
          /* falls through */
        case LEN_:
          state.mode = LEN;
          /* falls through */
        case LEN:
          if (have >= 6 && left >= 258) {
            //--- RESTORE() ---
            strm.next_out = put;
            strm.avail_out = left;
            strm.next_in = next;
            strm.avail_in = have;
            state.hold = hold;
            state.bits = bits;
            //---
            inflate_fast(strm, _out);
            //--- LOAD() ---
            put = strm.next_out;
            output = strm.output;
            left = strm.avail_out;
            next = strm.next_in;
            input = strm.input;
            have = strm.avail_in;
            hold = state.hold;
            bits = state.bits;
            //---

            if (state.mode === TYPE) {
              state.back = -1;
            }
            break;
          }
          state.back = 0;
          for (;;) {
            here = state.lencode[hold & ((1 << state.lenbits) -1)];  /*BITS(state.lenbits)*/
            here_bits = here >>> 24;
            here_op = (here >>> 16) & 0xff;
            here_val = here & 0xffff;

            if (here_bits <= bits) { break; }
            //--- PULLBYTE() ---//
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
            //---//
          }
          if (here_op && (here_op & 0xf0) === 0) {
            last_bits = here_bits;
            last_op = here_op;
            last_val = here_val;
            for (;;) {
              here = state.lencode[last_val +
                      ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
              here_bits = here >>> 24;
              here_op = (here >>> 16) & 0xff;
              here_val = here & 0xffff;

              if ((last_bits + here_bits) <= bits) { break; }
              //--- PULLBYTE() ---//
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
              //---//
            }
            //--- DROPBITS(last.bits) ---//
            hold >>>= last_bits;
            bits -= last_bits;
            //---//
            state.back += last_bits;
          }
          //--- DROPBITS(here.bits) ---//
          hold >>>= here_bits;
          bits -= here_bits;
          //---//
          state.back += here_bits;
          state.length = here_val;
          if (here_op === 0) {
            //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
            //        "inflate:         literal '%c'\n" :
            //        "inflate:         literal 0x%02x\n", here.val));
            state.mode = LIT;
            break;
          }
          if (here_op & 32) {
            //Tracevv((stderr, "inflate:         end of block\n"));
            state.back = -1;
            state.mode = TYPE;
            break;
          }
          if (here_op & 64) {
            strm.msg = 'invalid literal/length code';
            state.mode = BAD;
            break;
          }
          state.extra = here_op & 15;
          state.mode = LENEXT;
          /* falls through */
        case LENEXT:
          if (state.extra) {
            //=== NEEDBITS(state.extra);
            n = state.extra;
            while (bits < n) {
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
            }
            //===//
            state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
            //--- DROPBITS(state.extra) ---//
            hold >>>= state.extra;
            bits -= state.extra;
            //---//
            state.back += state.extra;
          }
          //Tracevv((stderr, "inflate:         length %u\n", state.length));
          state.was = state.length;
          state.mode = DIST;
          /* falls through */
        case DIST:
          for (;;) {
            here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/
            here_bits = here >>> 24;
            here_op = (here >>> 16) & 0xff;
            here_val = here & 0xffff;

            if ((here_bits) <= bits) { break; }
            //--- PULLBYTE() ---//
            if (have === 0) { break inf_leave; }
            have--;
            hold += input[next++] << bits;
            bits += 8;
            //---//
          }
          if ((here_op & 0xf0) === 0) {
            last_bits = here_bits;
            last_op = here_op;
            last_val = here_val;
            for (;;) {
              here = state.distcode[last_val +
                      ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
              here_bits = here >>> 24;
              here_op = (here >>> 16) & 0xff;
              here_val = here & 0xffff;

              if ((last_bits + here_bits) <= bits) { break; }
              //--- PULLBYTE() ---//
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
              //---//
            }
            //--- DROPBITS(last.bits) ---//
            hold >>>= last_bits;
            bits -= last_bits;
            //---//
            state.back += last_bits;
          }
          //--- DROPBITS(here.bits) ---//
          hold >>>= here_bits;
          bits -= here_bits;
          //---//
          state.back += here_bits;
          if (here_op & 64) {
            strm.msg = 'invalid distance code';
            state.mode = BAD;
            break;
          }
          state.offset = here_val;
          state.extra = (here_op) & 15;
          state.mode = DISTEXT;
          /* falls through */
        case DISTEXT:
          if (state.extra) {
            //=== NEEDBITS(state.extra);
            n = state.extra;
            while (bits < n) {
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
            }
            //===//
            state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
            //--- DROPBITS(state.extra) ---//
            hold >>>= state.extra;
            bits -= state.extra;
            //---//
            state.back += state.extra;
          }
    //#ifdef INFLATE_STRICT
          if (state.offset > state.dmax) {
            strm.msg = 'invalid distance too far back';
            state.mode = BAD;
            break;
          }
    //#endif
          //Tracevv((stderr, "inflate:         distance %u\n", state.offset));
          state.mode = MATCH;
          /* falls through */
        case MATCH:
          if (left === 0) { break inf_leave; }
          copy = _out - left;
          if (state.offset > copy) {         /* copy from window */
            copy = state.offset - copy;
            if (copy > state.whave) {
              if (state.sane) {
                strm.msg = 'invalid distance too far back';
                state.mode = BAD;
                break;
              }
    // (!) This block is disabled in zlib defailts,
    // don't enable it for binary compatibility
    //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
    //          Trace((stderr, "inflate.c too far\n"));
    //          copy -= state.whave;
    //          if (copy > state.length) { copy = state.length; }
    //          if (copy > left) { copy = left; }
    //          left -= copy;
    //          state.length -= copy;
    //          do {
    //            output[put++] = 0;
    //          } while (--copy);
    //          if (state.length === 0) { state.mode = LEN; }
    //          break;
    //#endif
            }
            if (copy > state.wnext) {
              copy -= state.wnext;
              from = state.wsize - copy;
            }
            else {
              from = state.wnext - copy;
            }
            if (copy > state.length) { copy = state.length; }
            from_source = state.window;
          }
          else {                              /* copy from output */
            from_source = output;
            from = put - state.offset;
            copy = state.length;
          }
          if (copy > left) { copy = left; }
          left -= copy;
          state.length -= copy;
          do {
            output[put++] = from_source[from++];
          } while (--copy);
          if (state.length === 0) { state.mode = LEN; }
          break;
        case LIT:
          if (left === 0) { break inf_leave; }
          output[put++] = state.length;
          left--;
          state.mode = LEN;
          break;
        case CHECK:
          if (state.wrap) {
            //=== NEEDBITS(32);
            while (bits < 32) {
              if (have === 0) { break inf_leave; }
              have--;
              // Use '|' insdead of '+' to make sure that result is signed
              hold |= input[next++] << bits;
              bits += 8;
            }
            //===//
            _out -= left;
            strm.total_out += _out;
            state.total += _out;
            if (_out) {
              strm.adler = state.check =
                  /*UPDATE(state.check, put - _out, _out);*/
                  (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));

            }
            _out = left;
            // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too
            if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {
              strm.msg = 'incorrect data check';
              state.mode = BAD;
              break;
            }
            //=== INITBITS();
            hold = 0;
            bits = 0;
            //===//
            //Tracev((stderr, "inflate:   check matches trailer\n"));
          }
          state.mode = LENGTH;
          /* falls through */
        case LENGTH:
          if (state.wrap && state.flags) {
            //=== NEEDBITS(32);
            while (bits < 32) {
              if (have === 0) { break inf_leave; }
              have--;
              hold += input[next++] << bits;
              bits += 8;
            }
            //===//
            if (hold !== (state.total & 0xffffffff)) {
              strm.msg = 'incorrect length check';
              state.mode = BAD;
              break;
            }
            //=== INITBITS();
            hold = 0;
            bits = 0;
            //===//
            //Tracev((stderr, "inflate:   length matches trailer\n"));
          }
          state.mode = DONE;
          /* falls through */
        case DONE:
          ret = Z_STREAM_END;
          break inf_leave;
        case BAD:
          ret = Z_DATA_ERROR;
          break inf_leave;
        case MEM:
          return Z_MEM_ERROR;
        case SYNC:
          /* falls through */
        default:
          return Z_STREAM_ERROR;
        }
      }

      // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"

      /*
         Return from inflate(), updating the total counts and the check value.
         If there was no progress during the inflate() call, return a buffer
         error.  Call updatewindow() to create and/or update the window state.
         Note: a memory error from inflate() is non-recoverable.
       */

      //--- RESTORE() ---
      strm.next_out = put;
      strm.avail_out = left;
      strm.next_in = next;
      strm.avail_in = have;
      state.hold = hold;
      state.bits = bits;
      //---

      if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
                          (state.mode < CHECK || flush !== Z_FINISH))) {
        if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
          state.mode = MEM;
          return Z_MEM_ERROR;
        }
      }
      _in -= strm.avail_in;
      _out -= strm.avail_out;
      strm.total_in += _in;
      strm.total_out += _out;
      state.total += _out;
      if (state.wrap && _out) {
        strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
          (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
      }
      strm.data_type = state.bits + (state.last ? 64 : 0) +
                        (state.mode === TYPE ? 128 : 0) +
                        (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
      if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
        ret = Z_BUF_ERROR;
      }
      return ret;
    }

    function inflateEnd(strm) {

      if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
        return Z_STREAM_ERROR;
      }

      var state = strm.state;
      if (state.window) {
        state.window = null;
      }
      strm.state = null;
      return Z_OK;
    }

    function inflateGetHeader(strm, head) {
      var state;

      /* check state */
      if (!strm || !strm.state) { return Z_STREAM_ERROR; }
      state = strm.state;
      if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }

      /* save header structure */
      state.head = head;
      head.done = false;
      return Z_OK;
    }

    exports.inflateReset = inflateReset;
    exports.inflateReset2 = inflateReset2;
    exports.inflateResetKeep = inflateResetKeep;
    exports.inflateInit = inflateInit;
    exports.inflateInit2 = inflateInit2;
    exports.inflate = inflate;
    exports.inflateEnd = inflateEnd;
    exports.inflateGetHeader = inflateGetHeader;
    exports.inflateInfo = 'pako inflate (from Nodeca project)';

    /* Not implemented
    exports.inflateCopy = inflateCopy;
    exports.inflateGetDictionary = inflateGetDictionary;
    exports.inflateMark = inflateMark;
    exports.inflatePrime = inflatePrime;
    exports.inflateSetDictionary = inflateSetDictionary;
    exports.inflateSync = inflateSync;
    exports.inflateSyncPoint = inflateSyncPoint;
    exports.inflateUndermine = inflateUndermine;
    */

    },{"../utils/common":83,"./adler32":85,"./crc32":87,"./inffast":90,"./inftrees":92}],92:[function(_dereq_,module,exports){
    'use strict';

    var utils = _dereq_('../utils/common');

    var MAXBITS = 15;
    var ENOUGH_LENS = 852;
    var ENOUGH_DISTS = 592;
    //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);

    var CODES = 0;
    var LENS = 1;
    var DISTS = 2;

    var lbase = [ /* Length codes 257..285 base */
      3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
      35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
    ];

    var lext = [ /* Length codes 257..285 extra */
      16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
      19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
    ];

    var dbase = [ /* Distance codes 0..29 base */
      1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
      257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
      8193, 12289, 16385, 24577, 0, 0
    ];

    var dext = [ /* Distance codes 0..29 extra */
      16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
      23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
      28, 28, 29, 29, 64, 64
    ];

    module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
    {
      var bits = opts.bits;
          //here = opts.here; /* table entry for duplication */

      var len = 0;               /* a code's length in bits */
      var sym = 0;               /* index of code symbols */
      var min = 0, max = 0;          /* minimum and maximum code lengths */
      var root = 0;              /* number of index bits for root table */
      var curr = 0;              /* number of index bits for current table */
      var drop = 0;              /* code bits to drop for sub-table */
      var left = 0;                   /* number of prefix codes available */
      var used = 0;              /* code entries in table used */
      var huff = 0;              /* Huffman code */
      var incr;              /* for incrementing code, index */
      var fill;              /* index for replicating entries */
      var low;               /* low bits for current root entry */
      var mask;              /* mask for low root bits */
      var next;             /* next available space in table */
      var base = null;     /* base value table to use */
      var base_index = 0;
    //  var shoextra;    /* extra bits table to use */
      var end;                    /* use base and extra for symbol > end */
      var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];    /* number of codes of each length */
      var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];     /* offsets in table for each length */
      var extra = null;
      var extra_index = 0;

      var here_bits, here_op, here_val;

      /*
       Process a set of code lengths to create a canonical Huffman code.  The
       code lengths are lens[0..codes-1].  Each length corresponds to the
       symbols 0..codes-1.  The Huffman code is generated by first sorting the
       symbols by length from short to long, and retaining the symbol order
       for codes with equal lengths.  Then the code starts with all zero bits
       for the first code of the shortest length, and the codes are integer
       increments for the same length, and zeros are appended as the length
       increases.  For the deflate format, these bits are stored backwards
       from their more natural integer increment ordering, and so when the
       decoding tables are built in the large loop below, the integer codes
       are incremented backwards.

       This routine assumes, but does not check, that all of the entries in
       lens[] are in the range 0..MAXBITS.  The caller must assure this.
       1..MAXBITS is interpreted as that code length.  zero means that that
       symbol does not occur in this code.

       The codes are sorted by computing a count of codes for each length,
       creating from that a table of starting indices for each length in the
       sorted table, and then entering the symbols in order in the sorted
       table.  The sorted table is work[], with that space being provided by
       the caller.

       The length counts are used for other purposes as well, i.e. finding
       the minimum and maximum length codes, determining if there are any
       codes at all, checking for a valid set of lengths, and looking ahead
       at length counts to determine sub-table sizes when building the
       decoding tables.
       */

      /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
      for (len = 0; len <= MAXBITS; len++) {
        count[len] = 0;
      }
      for (sym = 0; sym < codes; sym++) {
        count[lens[lens_index + sym]]++;
      }

      /* bound code lengths, force root to be within code lengths */
      root = bits;
      for (max = MAXBITS; max >= 1; max--) {
        if (count[max] !== 0) { break; }
      }
      if (root > max) {
        root = max;
      }
      if (max === 0) {                     /* no symbols to code at all */
        //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */
        //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;
        //table.val[opts.table_index++] = 0;   //here.val = (var short)0;
        table[table_index++] = (1 << 24) | (64 << 16) | 0;

        //table.op[opts.table_index] = 64;
        //table.bits[opts.table_index] = 1;
        //table.val[opts.table_index++] = 0;
        table[table_index++] = (1 << 24) | (64 << 16) | 0;

        opts.bits = 1;
        return 0;     /* no symbols, but wait for decoding to report error */
      }
      for (min = 1; min < max; min++) {
        if (count[min] !== 0) { break; }
      }
      if (root < min) {
        root = min;
      }

      /* check for an over-subscribed or incomplete set of lengths */
      left = 1;
      for (len = 1; len <= MAXBITS; len++) {
        left <<= 1;
        left -= count[len];
        if (left < 0) {
          return -1;
        }        /* over-subscribed */
      }
      if (left > 0 && (type === CODES || max !== 1)) {
        return -1;                      /* incomplete set */
      }

      /* generate offsets into symbol table for each length for sorting */
      offs[1] = 0;
      for (len = 1; len < MAXBITS; len++) {
        offs[len + 1] = offs[len] + count[len];
      }

      /* sort symbols by length, by symbol order within each length */
      for (sym = 0; sym < codes; sym++) {
        if (lens[lens_index + sym] !== 0) {
          work[offs[lens[lens_index + sym]]++] = sym;
        }
      }

      /*
       Create and fill in decoding tables.  In this loop, the table being
       filled is at next and has curr index bits.  The code being used is huff
       with length len.  That code is converted to an index by dropping drop
       bits off of the bottom.  For codes where len is less than drop + curr,
       those top drop + curr - len bits are incremented through all values to
       fill the table with replicated entries.

       root is the number of index bits for the root table.  When len exceeds
       root, sub-tables are created pointed to by the root entry with an index
       of the low root bits of huff.  This is saved in low to check for when a
       new sub-table should be started.  drop is zero when the root table is
       being filled, and drop is root when sub-tables are being filled.

       When a new sub-table is needed, it is necessary to look ahead in the
       code lengths to determine what size sub-table is needed.  The length
       counts are used for this, and so count[] is decremented as codes are
       entered in the tables.

       used keeps track of how many table entries have been allocated from the
       provided *table space.  It is checked for LENS and DIST tables against
       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
       the initial root table size constants.  See the comments in inftrees.h
       for more information.

       sym increments through all symbols, and the loop terminates when
       all codes of length max, i.e. all codes, have been processed.  This
       routine permits incomplete codes, so another loop after this one fills
       in the rest of the decoding tables with invalid code markers.
       */

      /* set up for code type */
      // poor man optimization - use if-else instead of switch,
      // to avoid deopts in old v8
      if (type === CODES) {
        base = extra = work;    /* dummy value--not used */
        end = 19;

      } else if (type === LENS) {
        base = lbase;
        base_index -= 257;
        extra = lext;
        extra_index -= 257;
        end = 256;

      } else {                    /* DISTS */
        base = dbase;
        extra = dext;
        end = -1;
      }

      /* initialize opts for loop */
      huff = 0;                   /* starting code */
      sym = 0;                    /* starting code symbol */
      len = min;                  /* starting code length */
      next = table_index;              /* current table to fill in */
      curr = root;                /* current table index bits */
      drop = 0;                   /* current bits to drop from code for index */
      low = -1;                   /* trigger new sub-table when len > root */
      used = 1 << root;          /* use root table entries */
      mask = used - 1;            /* mask for comparing low */

      /* check available table space */
      if ((type === LENS && used > ENOUGH_LENS) ||
        (type === DISTS && used > ENOUGH_DISTS)) {
        return 1;
      }

      var i=0;
      /* process all codes and make table entries */
      for (;;) {
        i++;
        /* create table entry */
        here_bits = len - drop;
        if (work[sym] < end) {
          here_op = 0;
          here_val = work[sym];
        }
        else if (work[sym] > end) {
          here_op = extra[extra_index + work[sym]];
          here_val = base[base_index + work[sym]];
        }
        else {
          here_op = 32 + 64;         /* end of block */
          here_val = 0;
        }

        /* replicate for those indices with low len bits equal to huff */
        incr = 1 << (len - drop);
        fill = 1 << curr;
        min = fill;                 /* save offset to next table */
        do {
          fill -= incr;
          table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
        } while (fill !== 0);

        /* backwards increment the len-bit code huff */
        incr = 1 << (len - 1);
        while (huff & incr) {
          incr >>= 1;
        }
        if (incr !== 0) {
          huff &= incr - 1;
          huff += incr;
        } else {
          huff = 0;
        }

        /* go to next symbol, update count, len */
        sym++;
        if (--count[len] === 0) {
          if (len === max) { break; }
          len = lens[lens_index + work[sym]];
        }

        /* create new sub-table if needed */
        if (len > root && (huff & mask) !== low) {
          /* if first time, transition to sub-tables */
          if (drop === 0) {
            drop = root;
          }

          /* increment past last table */
          next += min;            /* here min is 1 << curr */

          /* determine length of next table */
          curr = len - drop;
          left = 1 << curr;
          while (curr + drop < max) {
            left -= count[curr + drop];
            if (left <= 0) { break; }
            curr++;
            left <<= 1;
          }

          /* check for enough space */
          used += 1 << curr;
          if ((type === LENS && used > ENOUGH_LENS) ||
            (type === DISTS && used > ENOUGH_DISTS)) {
            return 1;
          }

          /* point entry in root table to sub-table */
          low = huff & mask;
          /*table.op[low] = curr;
          table.bits[low] = root;
          table.val[low] = next - opts.table_index;*/
          table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
        }
      }

      /* fill in remaining table entry if code is incomplete (guaranteed to have
       at most one remaining entry, since if the code is incomplete, the
       maximum code length that was allowed to get this far is one bit) */
      if (huff !== 0) {
        //table.op[next + huff] = 64;            /* invalid code marker */
        //table.bits[next + huff] = len - drop;
        //table.val[next + huff] = 0;
        table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
      }

      /* set return parameters */
      //opts.table_index += used;
      opts.bits = root;
      return 0;
    };

    },{"../utils/common":83}],93:[function(_dereq_,module,exports){
    'use strict';

    module.exports = {
      '2':    'need dictionary',     /* Z_NEED_DICT       2  */
      '1':    'stream end',          /* Z_STREAM_END      1  */
      '0':    '',                    /* Z_OK              0  */
      '-1':   'file error',          /* Z_ERRNO         (-1) */
      '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */
      '-3':   'data error',          /* Z_DATA_ERROR    (-3) */
      '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */
      '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */
      '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */
    };

    },{}],94:[function(_dereq_,module,exports){
    'use strict';

    var utils = _dereq_('../utils/common');

    /* Public constants ==========================================================*/
    /* ===========================================================================*/

    //var Z_FILTERED          = 1;
    //var Z_HUFFMAN_ONLY      = 2;
    //var Z_RLE               = 3;
    var Z_FIXED               = 4;
    //var Z_DEFAULT_STRATEGY  = 0;

    /* Possible values of the data_type field (though see inflate()) */
    var Z_BINARY              = 0;
    var Z_TEXT                = 1;
    //var Z_ASCII             = 1; // = Z_TEXT
    var Z_UNKNOWN             = 2;

    /*============================================================================*/

    function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }

    // From zutil.h

    var STORED_BLOCK = 0;
    var STATIC_TREES = 1;
    var DYN_TREES    = 2;
    /* The three kinds of block type */

    var MIN_MATCH    = 3;
    var MAX_MATCH    = 258;
    /* The minimum and maximum match lengths */

    // From deflate.h
    /* ===========================================================================
     * Internal compression state.
     */

    var LENGTH_CODES  = 29;
    /* number of length codes, not counting the special END_BLOCK code */

    var LITERALS      = 256;
    /* number of literal bytes 0..255 */

    var L_CODES       = LITERALS + 1 + LENGTH_CODES;
    /* number of Literal or Length codes, including the END_BLOCK code */

    var D_CODES       = 30;
    /* number of distance codes */

    var BL_CODES      = 19;
    /* number of codes used to transfer the bit lengths */

    var HEAP_SIZE     = 2*L_CODES + 1;
    /* maximum heap size */

    var MAX_BITS      = 15;
    /* All codes must not exceed MAX_BITS bits */

    var Buf_size      = 16;
    /* size of bit buffer in bi_buf */

    /* ===========================================================================
     * Constants
     */

    var MAX_BL_BITS = 7;
    /* Bit length codes must not exceed MAX_BL_BITS bits */

    var END_BLOCK   = 256;
    /* end of block literal code */

    var REP_3_6     = 16;
    /* repeat previous bit length 3-6 times (2 bits of repeat count) */

    var REPZ_3_10   = 17;
    /* repeat a zero length 3-10 times  (3 bits of repeat count) */

    var REPZ_11_138 = 18;
    /* repeat a zero length 11-138 times  (7 bits of repeat count) */

    var extra_lbits =   /* extra bits for each length code */
      [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];

    var extra_dbits =   /* extra bits for each distance code */
      [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];

    var extra_blbits =  /* extra bits for each bit length code */
      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];

    var bl_order =
      [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
    /* The lengths of the bit length codes are sent in order of decreasing
     * probability, to avoid transmitting the lengths for unused bit length codes.
     */

    /* ===========================================================================
     * Local data. These are initialized only once.
     */

    // We pre-fill arrays with 0 to avoid uninitialized gaps

    var DIST_CODE_LEN = 512; /* see definition of array dist_code below */

    // !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1
    var static_ltree  = new Array((L_CODES+2) * 2);
    zero(static_ltree);
    /* The static literal tree. Since the bit lengths are imposed, there is no
     * need for the L_CODES extra codes used during heap construction. However
     * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
     * below).
     */

    var static_dtree  = new Array(D_CODES * 2);
    zero(static_dtree);
    /* The static distance tree. (Actually a trivial tree since all codes use
     * 5 bits.)
     */

    var _dist_code    = new Array(DIST_CODE_LEN);
    zero(_dist_code);
    /* Distance codes. The first 256 values correspond to the distances
     * 3 .. 258, the last 256 values correspond to the top 8 bits of
     * the 15 bit distances.
     */

    var _length_code  = new Array(MAX_MATCH-MIN_MATCH+1);
    zero(_length_code);
    /* length code for each normalized match length (0 == MIN_MATCH) */

    var base_length   = new Array(LENGTH_CODES);
    zero(base_length);
    /* First normalized length for each code (0 = MIN_MATCH) */

    var base_dist     = new Array(D_CODES);
    zero(base_dist);
    /* First normalized distance for each code (0 = distance of 1) */

    var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) {

      this.static_tree  = static_tree;  /* static tree or NULL */
      this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */
      this.extra_base   = extra_base;   /* base index for extra_bits */
      this.elems        = elems;        /* max number of elements in the tree */
      this.max_length   = max_length;   /* max bit length for the codes */

      // show if `static_tree` has data or dummy - needed for monomorphic objects
      this.has_stree    = static_tree && static_tree.length;
    };

    var static_l_desc;
    var static_d_desc;
    var static_bl_desc;

    var TreeDesc = function(dyn_tree, stat_desc) {
      this.dyn_tree = dyn_tree;     /* the dynamic tree */
      this.max_code = 0;            /* largest code with non zero frequency */
      this.stat_desc = stat_desc;   /* the corresponding static tree */
    };

    function d_code(dist) {
      return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
    }

    /* ===========================================================================
     * Output a short LSB first on the stream.
     * IN assertion: there is enough room in pendingBuf.
     */
    function put_short (s, w) {
    //    put_byte(s, (uch)((w) & 0xff));
    //    put_byte(s, (uch)((ush)(w) >> 8));
      s.pending_buf[s.pending++] = (w) & 0xff;
      s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
    }

    /* ===========================================================================
     * Send a value on a given number of bits.
     * IN assertion: length <= 16 and value fits in length bits.
     */
    function send_bits(s, value, length) {
      if (s.bi_valid > (Buf_size - length)) {
        s.bi_buf |= (value << s.bi_valid) & 0xffff;
        put_short(s, s.bi_buf);
        s.bi_buf = value >> (Buf_size - s.bi_valid);
        s.bi_valid += length - Buf_size;
      } else {
        s.bi_buf |= (value << s.bi_valid) & 0xffff;
        s.bi_valid += length;
      }
    }

    function send_code(s, c, tree) {
      send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/);
    }

    /* ===========================================================================
     * Reverse the first len bits of a code, using straightforward code (a faster
     * method would use a table)
     * IN assertion: 1 <= len <= 15
     */
    function bi_reverse(code, len) {
      var res = 0;
      do {
        res |= code & 1;
        code >>>= 1;
        res <<= 1;
      } while (--len > 0);
      return res >>> 1;
    }

    /* ===========================================================================
     * Flush the bit buffer, keeping at most 7 bits in it.
     */
    function bi_flush(s) {
      if (s.bi_valid === 16) {
        put_short(s, s.bi_buf);
        s.bi_buf = 0;
        s.bi_valid = 0;

      } else if (s.bi_valid >= 8) {
        s.pending_buf[s.pending++] = s.bi_buf & 0xff;
        s.bi_buf >>= 8;
        s.bi_valid -= 8;
      }
    }

    /* ===========================================================================
     * Compute the optimal bit lengths for a tree and update the total bit length
     * for the current block.
     * IN assertion: the fields freq and dad are set, heap[heap_max] and
     *    above are the tree nodes sorted by increasing frequency.
     * OUT assertions: the field len is set to the optimal bit length, the
     *     array bl_count contains the frequencies for each bit length.
     *     The length opt_len is updated; static_len is also updated if stree is
     *     not null.
     */
    function gen_bitlen(s, desc)
    //    deflate_state *s;
    //    tree_desc *desc;    /* the tree descriptor */
    {
      var tree            = desc.dyn_tree;
      var max_code        = desc.max_code;
      var stree           = desc.stat_desc.static_tree;
      var has_stree       = desc.stat_desc.has_stree;
      var extra           = desc.stat_desc.extra_bits;
      var base            = desc.stat_desc.extra_base;
      var max_length      = desc.stat_desc.max_length;
      var h;              /* heap index */
      var n, m;           /* iterate over the tree elements */
      var bits;           /* bit length */
      var xbits;          /* extra bits */
      var f;              /* frequency */
      var overflow = 0;   /* number of elements with bit length too large */

      for (bits = 0; bits <= MAX_BITS; bits++) {
        s.bl_count[bits] = 0;
      }

      /* In a first pass, compute the optimal bit lengths (which may
       * overflow in the case of the bit length tree).
       */
      tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */

      for (h = s.heap_max+1; h < HEAP_SIZE; h++) {
        n = s.heap[h];
        bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
        Iif (bits > max_length) {
          bits = max_length;
          overflow++;
        }
        tree[n*2 + 1]/*.Len*/ = bits;
        /* We overwrite tree[n].Dad which is no longer needed */

        if (n > max_code) { continue; } /* not a leaf node */

        s.bl_count[bits]++;
        xbits = 0;
        if (n >= base) {
          xbits = extra[n-base];
        }
        f = tree[n * 2]/*.Freq*/;
        s.opt_len += f * (bits + xbits);
        if (has_stree) {
          s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits);
        }
      }
      Eif (overflow === 0) { return; }

      // Trace((stderr,"\nbit length overflow\n"));
      /* This happens for example on obj2 and pic of the Calgary corpus */

      /* Find the first bit length which could increase: */
      do {
        bits = max_length-1;
        while (s.bl_count[bits] === 0) { bits--; }
        s.bl_count[bits]--;      /* move one leaf down the tree */
        s.bl_count[bits+1] += 2; /* move one overflow item as its brother */
        s.bl_count[max_length]--;
        /* The brother of the overflow item also moves one step up,
         * but this does not affect bl_count[max_length]
         */
        overflow -= 2;
      } while (overflow > 0);

      /* Now recompute all bit lengths, scanning in increasing frequency.
       * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
       * lengths instead of fixing only the wrong ones. This idea is taken
       * from 'ar' written by Haruhiko Okumura.)
       */
      for (bits = max_length; bits !== 0; bits--) {
        n = s.bl_count[bits];
        while (n !== 0) {
          m = s.heap[--h];
          if (m > max_code) { continue; }
          if (tree[m*2 + 1]/*.Len*/ !== bits) {
            // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
            s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/;
            tree[m*2 + 1]/*.Len*/ = bits;
          }
          n--;
        }
      }
    }

    /* ===========================================================================
     * Generate the codes for a given tree and bit counts (which need not be
     * optimal).
     * IN assertion: the array bl_count contains the bit length statistics for
     * the given tree and the field len is set for all tree elements.
     * OUT assertion: the field code is set for all tree elements of non
     *     zero code length.
     */
    function gen_codes(tree, max_code, bl_count)
    //    ct_data *tree;             /* the tree to decorate */
    //    int max_code;              /* largest code with non zero frequency */
    //    ushf *bl_count;            /* number of codes at each bit length */
    {
      var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */
      var code = 0;              /* running code value */
      var bits;                  /* bit index */
      var n;                     /* code index */

      /* The distribution counts are first used to generate the code values
       * without bit reversal.
       */
      for (bits = 1; bits <= MAX_BITS; bits++) {
        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
      }
      /* Check that the bit counts in bl_count are consistent. The last code
       * must be all ones.
       */
      //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
      //        "inconsistent bit counts");
      //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));

      for (n = 0;  n <= max_code; n++) {
        var len = tree[n*2 + 1]/*.Len*/;
        if (len === 0) { continue; }
        /* Now reverse the bits */
        tree[n*2]/*.Code*/ = bi_reverse(next_code[len]++, len);

        //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
        //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
      }
    }

    /* ===========================================================================
     * Initialize the various 'constant' tables.
     */
    function tr_static_init() {
      var n;        /* iterates over tree elements */
      var bits;     /* bit counter */
      var length;   /* length value */
      var code;     /* code value */
      var dist;     /* distance index */
      var bl_count = new Array(MAX_BITS+1);
      /* number of codes at each bit length for an optimal tree */

      // do check in _tr_init()
      //if (static_init_done) return;

      /* For some embedded targets, global variables are not initialized: */
    /*#ifdef NO_INIT_GLOBAL_POINTERS
      static_l_desc.static_tree = static_ltree;
      static_l_desc.extra_bits = extra_lbits;
      static_d_desc.static_tree = static_dtree;
      static_d_desc.extra_bits = extra_dbits;
      static_bl_desc.extra_bits = extra_blbits;
    #endif*/

      /* Initialize the mapping length (0..255) -> length code (0..28) */
      length = 0;
      for (code = 0; code < LENGTH_CODES-1; code++) {
        base_length[code] = length;
        for (n = 0; n < (1<<extra_lbits[code]); n++) {
          _length_code[length++] = code;
        }
      }
      //Assert (length == 256, "tr_static_init: length != 256");
      /* Note that the length 255 (match length 258) can be represented
       * in two different ways: code 284 + 5 bits or code 285, so we
       * overwrite length_code[255] to use the best encoding:
       */
      _length_code[length-1] = code;

      /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
      dist = 0;
      for (code = 0 ; code < 16; code++) {
        base_dist[code] = dist;
        for (n = 0; n < (1<<extra_dbits[code]); n++) {
          _dist_code[dist++] = code;
        }
      }
      //Assert (dist == 256, "tr_static_init: dist != 256");
      dist >>= 7; /* from now on, all distances are divided by 128 */
      for (; code < D_CODES; code++) {
        base_dist[code] = dist << 7;
        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
          _dist_code[256 + dist++] = code;
        }
      }
      //Assert (dist == 256, "tr_static_init: 256+dist != 512");

      /* Construct the codes of the static literal tree */
      for (bits = 0; bits <= MAX_BITS; bits++) {
        bl_count[bits] = 0;
      }

      n = 0;
      while (n <= 143) {
        static_ltree[n*2 + 1]/*.Len*/ = 8;
        n++;
        bl_count[8]++;
      }
      while (n <= 255) {
        static_ltree[n*2 + 1]/*.Len*/ = 9;
        n++;
        bl_count[9]++;
      }
      while (n <= 279) {
        static_ltree[n*2 + 1]/*.Len*/ = 7;
        n++;
        bl_count[7]++;
      }
      while (n <= 287) {
        static_ltree[n*2 + 1]/*.Len*/ = 8;
        n++;
        bl_count[8]++;
      }
      /* Codes 286 and 287 do not exist, but we must include them in the
       * tree construction to get a canonical Huffman tree (longest code
       * all ones)
       */
      gen_codes(static_ltree, L_CODES+1, bl_count);

      /* The static distance tree is trivial: */
      for (n = 0; n < D_CODES; n++) {
        static_dtree[n*2 + 1]/*.Len*/ = 5;
        static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5);
      }

      // Now data ready and we can init static trees
      static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS);
      static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);
      static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);

      //static_init_done = true;
    }

    /* ===========================================================================
     * Initialize a new block.
     */
    function init_block(s) {
      var n; /* iterates over tree elements */

      /* Initialize the trees. */
      for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; }
      for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; }
      for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; }

      s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1;
      s.opt_len = s.static_len = 0;
      s.last_lit = s.matches = 0;
    }

    /* ===========================================================================
     * Flush the bit buffer and align the output on a byte boundary
     */
    function bi_windup(s)
    {
      Eif (s.bi_valid > 8) {
        put_short(s, s.bi_buf);
      } else if (s.bi_valid > 0) {
        //put_byte(s, (Byte)s->bi_buf);
        s.pending_buf[s.pending++] = s.bi_buf;
      }
      s.bi_buf = 0;
      s.bi_valid = 0;
    }

    /* ===========================================================================
     * Copy a stored block, storing first the length and its
     * one's complement if requested.
     */
    function copy_block(s, buf, len, header)
    //DeflateState *s;
    //charf    *buf;    /* the input data */
    //unsigned len;     /* its length */
    //int      header;  /* true if block header must be written */
    {
      bi_windup(s);        /* align on byte boundary */

      if (header) {
        put_short(s, len);
        put_short(s, ~len);
      }
    //  while (len--) {
    //    put_byte(s, *buf++);
    //  }
      utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);
      s.pending += len;
    }

    /* ===========================================================================
     * Compares to subtrees, using the tree depth as tie breaker when
     * the subtrees have equal frequency. This minimizes the worst case length.
     */
    function smaller(tree, n, m, depth) {
      var _n2 = n*2;
      var _m2 = m*2;
      return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
             (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
    }

    /* ===========================================================================
     * Restore the heap property by moving down the tree starting at node k,
     * exchanging a node with the smallest of its two sons if necessary, stopping
     * when the heap property is re-established (each father smaller than its
     * two sons).
     */
    function pqdownheap(s, tree, k)
    //    deflate_state *s;
    //    ct_data *tree;  /* the tree to restore */
    //    int k;               /* node to move down */
    {
      var v = s.heap[k];
      var j = k << 1;  /* left son of k */
      while (j <= s.heap_len) {
        /* Set j to the smallest of the two sons: */
        if (j < s.heap_len &&
          smaller(tree, s.heap[j+1], s.heap[j], s.depth)) {
          j++;
        }
        /* Exit if v is smaller than both sons */
        if (smaller(tree, v, s.heap[j], s.depth)) { break; }

        /* Exchange v with the smallest son */
        s.heap[k] = s.heap[j];
        k = j;

        /* And continue down the tree, setting j to the left son of k */
        j <<= 1;
      }
      s.heap[k] = v;
    }

    // inlined manually
    // var SMALLEST = 1;

    /* ===========================================================================
     * Send the block data compressed using the given Huffman trees
     */
    function compress_block(s, ltree, dtree)
    //    deflate_state *s;
    //    const ct_data *ltree; /* literal tree */
    //    const ct_data *dtree; /* distance tree */
    {
      var dist;           /* distance of matched string */
      var lc;             /* match length or unmatched char (if dist == 0) */
      var lx = 0;         /* running index in l_buf */
      var code;           /* the code to send */
      var extra;          /* number of extra bits to send */

      Eif (s.last_lit !== 0) {
        do {
          dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]);
          lc = s.pending_buf[s.l_buf + lx];
          lx++;

          if (dist === 0) {
            send_code(s, lc, ltree); /* send a literal byte */
            //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
          } else {
            /* Here, lc is the match length - MIN_MATCH */
            code = _length_code[lc];
            send_code(s, code+LITERALS+1, ltree); /* send the length code */
            extra = extra_lbits[code];
            Iif (extra !== 0) {
              lc -= base_length[code];
              send_bits(s, lc, extra);       /* send the extra length bits */
            }
            dist--; /* dist is now the match distance - 1 */
            code = d_code(dist);
            //Assert (code < D_CODES, "bad d_code");

            send_code(s, code, dtree);       /* send the distance code */
            extra = extra_dbits[code];
            Eif (extra !== 0) {
              dist -= base_dist[code];
              send_bits(s, dist, extra);   /* send the extra distance bits */
            }
          } /* literal or match pair ? */

          /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
          //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
          //       "pendingBuf overflow");

        } while (lx < s.last_lit);
      }

      send_code(s, END_BLOCK, ltree);
    }

    /* ===========================================================================
     * Construct one Huffman tree and assigns the code bit strings and lengths.
     * Update the total bit length for the current block.
     * IN assertion: the field freq is set for all tree elements.
     * OUT assertions: the fields len and code are set to the optimal bit length
     *     and corresponding code. The length opt_len is updated; static_len is
     *     also updated if stree is not null. The field max_code is set.
     */
    function build_tree(s, desc)
    //    deflate_state *s;
    //    tree_desc *desc; /* the tree descriptor */
    {
      var tree     = desc.dyn_tree;
      var stree    = desc.stat_desc.static_tree;
      var has_stree = desc.stat_desc.has_stree;
      var elems    = desc.stat_desc.elems;
      var n, m;          /* iterate over heap elements */
      var max_code = -1; /* largest code with non zero frequency */
      var node;          /* new node being created */

      /* Construct the initial heap, with least frequent element in
       * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
       * heap[0] is not used.
       */
      s.heap_len = 0;
      s.heap_max = HEAP_SIZE;

      for (n = 0; n < elems; n++) {
        if (tree[n * 2]/*.Freq*/ !== 0) {
          s.heap[++s.heap_len] = max_code = n;
          s.depth[n] = 0;

        } else {
          tree[n*2 + 1]/*.Len*/ = 0;
        }
      }

      /* The pkzip format requires that at least one distance code exists,
       * and that at least one bit should be sent even if there is only one
       * possible code. So to avoid special checks later on we force at least
       * two codes of non zero frequency.
       */
      while (s.heap_len < 2) {
        node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
        tree[node * 2]/*.Freq*/ = 1;
        s.depth[node] = 0;
        s.opt_len--;

        Eif (has_stree) {
          s.static_len -= stree[node*2 + 1]/*.Len*/;
        }
        /* node is 0 or 1 so it does not have extra bits */
      }
      desc.max_code = max_code;

      /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
       * establish sub-heaps of increasing lengths:
       */
      for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }

      /* Construct the Huffman tree by repeatedly combining the least two
       * frequent nodes.
       */
      node = elems;              /* next internal node of the tree */
      do {
        //pqremove(s, tree, n);  /* n = node of least frequency */
        /*** pqremove ***/
        n = s.heap[1/*SMALLEST*/];
        s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
        pqdownheap(s, tree, 1/*SMALLEST*/);
        /***/

        m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */

        s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
        s.heap[--s.heap_max] = m;

        /* Create a new node father of n and m */
        tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
        s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
        tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node;

        /* and insert the new node in the heap */
        s.heap[1/*SMALLEST*/] = node++;
        pqdownheap(s, tree, 1/*SMALLEST*/);

      } while (s.heap_len >= 2);

      s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];

      /* At this point, the fields freq and dad are set. We can now
       * generate the bit lengths.
       */
      gen_bitlen(s, desc);

      /* The field len is now set, we can generate the bit codes */
      gen_codes(tree, max_code, s.bl_count);
    }

    /* ===========================================================================
     * Scan a literal or distance tree to determine the frequencies of the codes
     * in the bit length tree.
     */
    function scan_tree(s, tree, max_code)
    //    deflate_state *s;
    //    ct_data *tree;   /* the tree to be scanned */
    //    int max_code;    /* and its largest code of non zero frequency */
    {
      var n;                     /* iterates over all tree elements */
      var prevlen = -1;          /* last emitted length */
      var curlen;                /* length of current code */

      var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */

      var count = 0;             /* repeat count of the current code */
      var max_count = 7;         /* max repeat count */
      var min_count = 4;         /* min repeat count */

      if (nextlen === 0) {
        max_count = 138;
        min_count = 3;
      }
      tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */

      for (n = 0; n <= max_code; n++) {
        curlen = nextlen;
        nextlen = tree[(n+1)*2 + 1]/*.Len*/;

        if (++count < max_count && curlen === nextlen) {
          continue;

        } else if (count < min_count) {
          s.bl_tree[curlen * 2]/*.Freq*/ += count;

        } else Iif (curlen !== 0) {

          if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
          s.bl_tree[REP_3_6*2]/*.Freq*/++;

        } else if (count <= 10) {
          s.bl_tree[REPZ_3_10*2]/*.Freq*/++;

        } else {
          s.bl_tree[REPZ_11_138*2]/*.Freq*/++;
        }

        count = 0;
        prevlen = curlen;

        if (nextlen === 0) {
          max_count = 138;
          min_count = 3;

        } else Iif (curlen === nextlen) {
          max_count = 6;
          min_count = 3;

        } else {
          max_count = 7;
          min_count = 4;
        }
      }
    }

    /* ===========================================================================
     * Send a literal or distance tree in compressed form, using the codes in
     * bl_tree.
     */
    function send_tree(s, tree, max_code)
    //    deflate_state *s;
    //    ct_data *tree; /* the tree to be scanned */
    //    int max_code;       /* and its largest code of non zero frequency */
    {
      var n;                     /* iterates over all tree elements */
      var prevlen = -1;          /* last emitted length */
      var curlen;                /* length of current code */

      var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */

      var count = 0;             /* repeat count of the current code */
      var max_count = 7;         /* max repeat count */
      var min_count = 4;         /* min repeat count */

      /* tree[max_code+1].Len = -1; */  /* guard already set */
      if (nextlen === 0) {
        max_count = 138;
        min_count = 3;
      }

      for (n = 0; n <= max_code; n++) {
        curlen = nextlen;
        nextlen = tree[(n+1)*2 + 1]/*.Len*/;

        if (++count < max_count && curlen === nextlen) {
          continue;

        } else if (count < min_count) {
          do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);

        } else if (curlen !== 0) {
          if (curlen !== prevlen) {
            send_code(s, curlen, s.bl_tree);
            count--;
          }
          //Assert(count >= 3 && count <= 6, " 3_6?");
          send_code(s, REP_3_6, s.bl_tree);
          send_bits(s, count-3, 2);

        } else if (count <= 10) {
          send_code(s, REPZ_3_10, s.bl_tree);
          send_bits(s, count-3, 3);

        } else {
          send_code(s, REPZ_11_138, s.bl_tree);
          send_bits(s, count-11, 7);
        }

        count = 0;
        prevlen = curlen;
        if (nextlen === 0) {
          max_count = 138;
          min_count = 3;

        } else if (curlen === nextlen) {
          max_count = 6;
          min_count = 3;

        } else {
          max_count = 7;
          min_count = 4;
        }
      }
    }

    /* ===========================================================================
     * Construct the Huffman tree for the bit lengths and return the index in
     * bl_order of the last bit length code to send.
     */
    function build_bl_tree(s) {
      var max_blindex;  /* index of last bit length code of non zero freq */

      /* Determine the bit length frequencies for literal and distance trees */
      scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
      scan_tree(s, s.dyn_dtree, s.d_desc.max_code);

      /* Build the bit length tree: */
      build_tree(s, s.bl_desc);
      /* opt_len now includes the length of the tree representations, except
       * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
       */

      /* Determine the number of bit length codes to send. The pkzip format
       * requires that at least 4 bit length codes be sent. (appnote.txt says
       * 3 but the actual value used is 4.)
       */
      for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
        if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) {
          break;
        }
      }
      /* Update opt_len to include the bit length tree and counts */
      s.opt_len += 3*(max_blindex+1) + 5+5+4;
      //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
      //        s->opt_len, s->static_len));

      return max_blindex;
    }

    /* ===========================================================================
     * Send the header for a block using dynamic Huffman trees: the counts, the
     * lengths of the bit length codes, the literal tree and the distance tree.
     * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
     */
    function send_all_trees(s, lcodes, dcodes, blcodes)
    //    deflate_state *s;
    //    int lcodes, dcodes, blcodes; /* number of codes for each tree */
    {
      var rank;                    /* index in bl_order */

      //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
      //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
      //        "too many codes");
      //Tracev((stderr, "\nbl counts: "));
      send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
      send_bits(s, dcodes-1,   5);
      send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
      for (rank = 0; rank < blcodes; rank++) {
        //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
        send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3);
      }
      //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));

      send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */
      //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));

      send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */
      //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
    }

    /* ===========================================================================
     * Check if the data type is TEXT or BINARY, using the following algorithm:
     * - TEXT if the two conditions below are satisfied:
     *    a) There are no non-portable control characters belonging to the
     *       "black list" (0..6, 14..25, 28..31).
     *    b) There is at least one printable character belonging to the
     *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
     * - BINARY otherwise.
     * - The following partially-portable control characters form a
     *   "gray list" that is ignored in this detection algorithm:
     *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
     * IN assertion: the fields Freq of dyn_ltree are set.
     */
    function detect_data_type(s) {
      /* black_mask is the bit mask of black-listed bytes
       * set bits 0..6, 14..25, and 28..31
       * 0xf3ffc07f = binary 11110011111111111100000001111111
       */
      var black_mask = 0xf3ffc07f;
      var n;

      /* Check for non-textual ("black-listed") bytes. */
      for (n = 0; n <= 31; n++, black_mask >>>= 1) {
        Iif ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) {
          return Z_BINARY;
        }
      }

      /* Check for textual ("white-listed") bytes. */
      Iif (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
          s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
        return Z_TEXT;
      }
      for (n = 32; n < LITERALS; n++) {
        if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
          return Z_TEXT;
        }
      }

      /* There are no "black-listed" or "white-listed" bytes:
       * this stream either is empty or has tolerated ("gray-listed") bytes only.
       */
      return Z_BINARY;
    }

    var static_init_done = false;

    /* ===========================================================================
     * Initialize the tree data structures for a new zlib stream.
     */
    function _tr_init(s)
    {

      if (!static_init_done) {
        tr_static_init();
        static_init_done = true;
      }

      s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);
      s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);
      s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);

      s.bi_buf = 0;
      s.bi_valid = 0;

      /* Initialize the first block of the first file: */
      init_block(s);
    }

    /* ===========================================================================
     * Send a stored block
     */
    function _tr_stored_block(s, buf, stored_len, last)
    //DeflateState *s;
    //charf *buf;       /* input block */
    //ulg stored_len;   /* length of input block */
    //int last;         /* one if this is the last block for a file */
    {
      send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3);    /* send block type */
      copy_block(s, buf, stored_len, true); /* with header */
    }

    /* ===========================================================================
     * Send one empty static block to give enough lookahead for inflate.
     * This takes 10 bits, of which 7 may remain in the bit buffer.
     */
    function _tr_align(s) {
      send_bits(s, STATIC_TREES<<1, 3);
      send_code(s, END_BLOCK, static_ltree);
      bi_flush(s);
    }

    /* ===========================================================================
     * Determine the best encoding for the current block: dynamic trees, static
     * trees or store, and output the encoded block to the zip file.
     */
    function _tr_flush_block(s, buf, stored_len, last)
    //DeflateState *s;
    //charf *buf;       /* input block, or NULL if too old */
    //ulg stored_len;   /* length of input block */
    //int last;         /* one if this is the last block for a file */
    {
      var opt_lenb, static_lenb;  /* opt_len and static_len in bytes */
      var max_blindex = 0;        /* index of last bit length code of non zero freq */

      /* Build the Huffman trees unless a stored block is forced */
      Eif (s.level > 0) {

        /* Check if the file is binary or text */
        Eif (s.strm.data_type === Z_UNKNOWN) {
          s.strm.data_type = detect_data_type(s);
        }

        /* Construct the literal and distance trees */
        build_tree(s, s.l_desc);
        // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
        //        s->static_len));

        build_tree(s, s.d_desc);
        // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
        //        s->static_len));
        /* At this point, opt_len and static_len are the total bit lengths of
         * the compressed block data, excluding the tree representations.
         */

        /* Build the bit length tree for the above two trees, and get the index
         * in bl_order of the last bit length code to send.
         */
        max_blindex = build_bl_tree(s);

        /* Determine the best encoding. Compute the block lengths in bytes. */
        opt_lenb = (s.opt_len+3+7) >>> 3;
        static_lenb = (s.static_len+3+7) >>> 3;

        // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
        //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
        //        s->last_lit));

        Eif (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }

      } else {
        // Assert(buf != (char*)0, "lost buf");
        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
      }

      Iif ((stored_len+4 <= opt_lenb) && (buf !== -1)) {
        /* 4: two words for the lengths */

        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
         * Otherwise we can't have processed more than WSIZE input bytes since
         * the last block flush, because compression would have been
         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
         * transform a block into a stored block.
         */
        _tr_stored_block(s, buf, stored_len, last);

      } else Eif (s.strategy === Z_FIXED || static_lenb === opt_lenb) {

        send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3);
        compress_block(s, static_ltree, static_dtree);

      } else {
        send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3);
        send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1);
        compress_block(s, s.dyn_ltree, s.dyn_dtree);
      }
      // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
      /* The above check is made mod 2^32, for files larger than 512 MB
       * and uLong implemented on 32 bits.
       */
      init_block(s);

      Eif (last) {
        bi_windup(s);
      }
      // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
      //       s->compressed_len-7*last));
    }

    /* ===========================================================================
     * Save the match info and tally the frequency counts. Return true if
     * the current block must be flushed.
     */
    function _tr_tally(s, dist, lc)
    //    deflate_state *s;
    //    unsigned dist;  /* distance of matched string */
    //    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
    {
      //var out_length, in_length, dcode;

      s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;
      s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;

      s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
      s.last_lit++;

      if (dist === 0) {
        /* lc is the unmatched char */
        s.dyn_ltree[lc*2]/*.Freq*/++;
      } else {
        s.matches++;
        /* Here, lc is the match length - MIN_MATCH */
        dist--;             /* dist = match distance - 1 */
        //Assert((ush)dist < (ush)MAX_DIST(s) &&
        //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
        //       (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");

        s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++;
        s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
      }

    // (!) This block is disabled in zlib defailts,
    // don't enable it for binary compatibility

    //#ifdef TRUNCATE_BLOCK
    //  /* Try to guess if it is profitable to stop the current block here */
    //  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
    //    /* Compute an upper bound for the compressed length */
    //    out_length = s.last_lit*8;
    //    in_length = s.strstart - s.block_start;
    //
    //    for (dcode = 0; dcode < D_CODES; dcode++) {
    //      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
    //    }
    //    out_length >>>= 3;
    //    //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
    //    //       s->last_lit, in_length, out_length,
    //    //       100L - out_length*100L/in_length));
    //    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
    //      return true;
    //    }
    //  }
    //#endif

      return (s.last_lit === s.lit_bufsize-1);
      /* We avoid equality with lit_bufsize because of wraparound at 64K
       * on 16 bit machines and because stored blocks are restricted to
       * 64K-1 bytes.
       */
    }

    exports._tr_init  = _tr_init;
    exports._tr_stored_block = _tr_stored_block;
    exports._tr_flush_block  = _tr_flush_block;
    exports._tr_tally = _tr_tally;
    exports._tr_align = _tr_align;

    },{"../utils/common":83}],95:[function(_dereq_,module,exports){
    'use strict';

    function ZStream() {
      /* next input byte */
      this.input = null; // JS specific, because we have no pointers
      this.next_in = 0;
      /* number of bytes available at input */
      this.avail_in = 0;
      /* total number of input bytes read so far */
      this.total_in = 0;
      /* next output byte should be put there */
      this.output = null; // JS specific, because we have no pointers
      this.next_out = 0;
      /* remaining free space at output */
      this.avail_out = 0;
      /* total number of bytes output so far */
      this.total_out = 0;
      /* last error message, NULL if no error */
      this.msg = ''/*Z_NULL*/;
      /* not visible by applications */
      this.state = null;
      /* best guess about the data type: binary or text */
      this.data_type = 2/*Z_UNKNOWN*/;
      /* adler32 value of the uncompressed data */
      this.adler = 0;
    }

    module.exports = ZStream;

    },{}]},{},[1]);