Best JavaScript code snippet using puppeteer
hero_data.js
Source:hero_data.js  
1var heroes = [2  {3    "Initiator": 0,4    "Name": "Abaddon",5    "Disabler": 0,6    "Pusher": 1,7    "Durable": 3,8    "Jungler": 0,9    "Nuker": 1,10    "slug": "abaddon",11    "LaneSupport": 2,12    "Escape": 1,13    "Carry": 1,14    "Total": 11,15    "Support": 2,16    "Melee": 117  },18  {19    "Initiator": 1,20    "Name": "Alchemist",21    "Disabler": 1,22    "Pusher": 0,23    "Durable": 3,24    "Jungler": 0,25    "Nuker": 1,26    "slug": "alchemist",27    "LaneSupport": 0,28    "Escape": 0,29    "Carry": 3,30    "Total": 10,31    "Support": 1,32    "Melee": 133  },34  {35    "Initiator": 1,36    "Name": "Ancient Apparition",37    "Disabler": 1,38    "Pusher": 0,39    "Durable": 0,40    "Jungler": 0,41    "Nuker": 2,42    "slug": "ancient_apparition",43    "LaneSupport": 2,44    "Escape": 0,45    "Carry": 0,46    "Total": 8,47    "Support": 248  },49  {50    "Initiator": 0,51    "Name": "Anti-mage",52    "Disabler": 0,53    "Pusher": 2,54    "Durable": 1,55    "Jungler": 0,56    "Nuker": 1,57    "slug": "antimage",58    "LaneSupport": 0,59    "Escape": 3,60    "Carry": 3,61    "Total": 10,62    "Support": 0,63    "Melee": 164  },65  {66    "Initiator": 3,67    "Name": "Axe",68    "Disabler": 1,69    "Pusher": 1,70    "Durable": 3,71    "Jungler": 1,72    "Nuker": 1,73    "slug": "axe",74    "LaneSupport": 1,75    "Escape": 0,76    "Carry": 0,77    "Total": 11,78    "Support": 0,79    "Melee": 180  },81  {82    "Initiator": 0,83    "Name": "Bane",84    "Disabler": 3,85    "Pusher": 0,86    "Durable": 0,87    "Jungler": 0,88    "Nuker": 2,89    "slug": "bane",90    "LaneSupport": 3,91    "Escape": 0,92    "Carry": 0,93    "Total": 10,94    "Support": 295  },96  {97    "Initiator": 2,98    "Name": "Batrider",99    "Disabler": 2,100    "Pusher": 1,101    "Durable": 0,102    "Jungler": 1,103    "Nuker": 0,104    "slug": "batrider",105    "LaneSupport": 0,106    "Escape": 2,107    "Carry": 0,108    "Total": 8,109    "Support": 0110  },111  {112    "Initiator": 2,113    "Name": "Beastmaster",114    "Disabler": 2,115    "Pusher": 2,116    "Durable": 1,117    "Jungler": 1,118    "Nuker": 1,119    "slug": "beastmaster",120    "LaneSupport": 1,121    "Escape": 0,122    "Carry": 1,123    "Total": 13,124    "Support": 2,125    "Melee": 1126  },127  {128    "Initiator": 1,129    "Name": "Bloodseeker",130    "Disabler": 1,131    "Pusher": 0,132    "Durable": 1,133    "Jungler": 1,134    "Nuker": 2,135    "slug": "bloodseeker",136    "LaneSupport": 0,137    "Escape": 0,138    "Carry": 2,139    "Total": 8,140    "Support": 0,141    "Melee": 1142  },143  {144    "Initiator": 0,145    "Name": "Bounty Hunter",146    "Disabler": 0,147    "Pusher": 0,148    "Durable": 0,149    "Jungler": 0,150    "Nuker": 2,151    "slug": "bounty_hunter",152    "LaneSupport": 0,153    "Escape": 2,154    "Carry": 1,155    "Total": 6,156    "Support": 1,157    "Melee": 1158  },159  {160    "Initiator": 2,161    "Name": "Brewmaster",162    "Disabler": 2,163    "Pusher": 0,164    "Durable": 3,165    "Jungler": 0,166    "Nuker": 1,167    "slug": "brewmaster",168    "LaneSupport": 0,169    "Escape": 1,170    "Carry": 1,171    "Total": 10,172    "Support": 0,173    "Melee": 1174  },175  {176    "Initiator": 1,177    "Name": "Bristleback",178    "Disabler": 0,179    "Pusher": 1,180    "Durable": 3,181    "Jungler": 0,182    "Nuker": 0,183    "slug": "bristleback",184    "LaneSupport": 0,185    "Escape": 1,186    "Carry": 2,187    "Total": 9,188    "Support": 1,189    "Melee": 1190  },191  {192    "Initiator": 0,193    "Name": "Broodmother",194    "Disabler": 1,195    "Pusher": 3,196    "Durable": 1,197    "Jungler": 1,198    "Nuker": 1,199    "slug": "broodmother",200    "LaneSupport": 0,201    "Escape": 2,202    "Carry": 2,203    "Total": 11,204    "Support": 0,205    "Melee": 1206  },207  {208    "Initiator": 2,209    "Name": "Centaur Warrunner",210    "Disabler": 2,211    "Pusher": 1,212    "Durable": 2,213    "Jungler": 0,214    "Nuker": 2,215    "slug": "centaur",216    "LaneSupport": 1,217    "Escape": 1,218    "Carry": 0,219    "Total": 12,220    "Support": 1,221    "Melee": 1222  },223  {224    "Initiator": 0,225    "Name": "Chaos Knight",226    "Disabler": 2,227    "Pusher": 1,228    "Durable": 1,229    "Jungler": 0,230    "Nuker": 1,231    "slug": "chaos_knight",232    "LaneSupport": 0,233    "Escape": 0,234    "Carry": 3,235    "Total": 8,236    "Support": 0,237    "Melee": 1238  },239  {240    "Initiator": 0,241    "Name": "Chen",242    "Disabler": 1,243    "Pusher": 3,244    "Durable": 0,245    "Jungler": 3,246    "Nuker": 1,247    "slug": "chen",248    "LaneSupport": 0,249    "Escape": 0,250    "Carry": 0,251    "Total": 11,252    "Support": 3253  },254  {255    "Initiator": 0,256    "Name": "Clinkz",257    "Disabler": 0,258    "Pusher": 0,259    "Durable": 0,260    "Jungler": 0,261    "Nuker": 2,262    "slug": "clinkz",263    "LaneSupport": 0,264    "Escape": 3,265    "Carry": 2,266    "Total": 7,267    "Support": 0268  },269  {270    "Initiator": 3,271    "Name": "Clockwerk",272    "Disabler": 2,273    "Pusher": 1,274    "Durable": 2,275    "Jungler": 0,276    "Nuker": 1,277    "slug": "rattletrap",278    "LaneSupport": 1,279    "Escape": 1,280    "Carry": 0,281    "Total": 12,282    "Support": 1,283    "Melee": 1284  },285  {286    "Initiator": 0,287    "Name": "Crystal Maiden",288    "Disabler": 2,289    "Pusher": 1,290    "Durable": 0,291    "Jungler": 0,292    "Nuker": 3,293    "slug": "crystal_maiden",294    "LaneSupport": 3,295    "Escape": 0,296    "Carry": 0,297    "Total": 12,298    "Support": 3299  },300  {301    "Initiator": 2,302    "Name": "Dark Seer",303    "Disabler": 1,304    "Pusher": 2,305    "Durable": 1,306    "Jungler": 2,307    "Nuker": 1,308    "slug": "dark_seer",309    "LaneSupport": 1,310    "Escape": 1,311    "Carry": 0,312    "Total": 12,313    "Support": 1,314    "Melee": 1315  },316  {317    "Initiator": 1,318    "Name": "Dazzle",319    "Disabler": 1,320    "Pusher": 2,321    "Durable": 1,322    "Jungler": 0,323    "Nuker": 1,324    "slug": "dazzle",325    "LaneSupport": 3,326    "Escape": 0,327    "Carry": 0,328    "Total": 12,329    "Support": 3330  },331  {332    "Initiator": 1,333    "Name": "Death Prophet",334    "Disabler": 0,335    "Pusher": 3,336    "Durable": 2,337    "Jungler": 0,338    "Nuker": 2,339    "slug": "death_prophet",340    "LaneSupport": 1,341    "Escape": 0,342    "Carry": 2,343    "Total": 12,344    "Support": 1345  },346  {347    "Initiator": 2,348    "Name": "Disruptor",349    "Disabler": 2,350    "Pusher": 0,351    "Durable": 0,352    "Jungler": 0,353    "Nuker": 2,354    "slug": "disruptor",355    "LaneSupport": 2,356    "Escape": 0,357    "Carry": 0,358    "Total": 10,359    "Support": 2360  },361  {362    "Initiator": 0,363    "Name": "Doom",364    "Disabler": 2,365    "Pusher": 1,366    "Durable": 2,367    "Jungler": 2,368    "Nuker": 2,369    "slug": "doom_bringer",370    "LaneSupport": 0,371    "Escape": 1,372    "Carry": 2,373    "Total": 12,374    "Support": 0,375    "Melee": 1376  },377  {378    "Initiator": 0,379    "Name": "Dragon Knight",380    "Disabler": 2,381    "Pusher": 2,382    "Durable": 3,383    "Jungler": 0,384    "Nuker": 1,385    "slug": "dragon_knight",386    "LaneSupport": 0,387    "Escape": 0,388    "Carry": 3,389    "Total": 11,390    "Support": 0,391    "Melee": 1392  },393  {394    "Initiator": 0,395    "Name": "Drow Ranger",396    "Disabler": 1,397    "Pusher": 2,398    "Durable": 0,399    "Jungler": 0,400    "Nuker": 0,401    "slug": "drow_ranger",402    "LaneSupport": 0,403    "Escape": 0,404    "Carry": 3,405    "Total": 7,406    "Support": 1407  },408  {409    "Initiator": 2,410    "Name": "Earth Spirit",411    "Disabler": 1,412    "Pusher": 0,413    "Durable": 2,414    "Jungler": 0,415    "Nuker": 1,416    "slug": "earth_spirit",417    "LaneSupport": 1,418    "Escape": 3,419    "Carry": 0,420    "Total": 13,421    "Support": 2,422    "Melee": 1423  },424  {425    "Initiator": 3,426    "Name": "Earthshaker",427    "Disabler": 3,428    "Pusher": 0,429    "Durable": 1,430    "Jungler": 0,431    "Nuker": 3,432    "slug": "earthshaker",433    "LaneSupport": 1,434    "Escape": 0,435    "Carry": 0,436    "Total": 13,437    "Support": 2,438    "Melee": 1439  },440  {441    "Initiator": 3,442    "Name": "Elder Titan",443    "Disabler": 2,444    "Pusher": 0,445    "Durable": 2,446    "Jungler": 0,447    "Nuker": 1,448    "slug": "elder_titan",449    "LaneSupport": 0,450    "Escape": 0,451    "Carry": 1,452    "Total": 11,453    "Support": 2,454    "Melee": 1455  },456  {457    "Initiator": 2,458    "Name": "Ember Spirit",459    "Disabler": 1,460    "Pusher": 1,461    "Durable": 2,462    "Jungler": 0,463    "Nuker": 2,464    "slug": "ember_spirit",465    "LaneSupport": 0,466    "Escape": 2,467    "Carry": 2,468    "Total": 11,469    "Support": 0,470    "Melee": 1471  },472  {473    "Initiator": 0,474    "Name": "Enchantress",475    "Disabler": 1,476    "Pusher": 3,477    "Durable": 1,478    "Jungler": 3,479    "Nuker": 1,480    "slug": "enchantress",481    "LaneSupport": 2,482    "Escape": 0,483    "Carry": 2,484    "Total": 15,485    "Support": 2486  },487  {488    "Initiator": 3,489    "Name": "Enigma",490    "Disabler": 3,491    "Pusher": 2,492    "Durable": 0,493    "Jungler": 3,494    "Nuker": 0,495    "slug": "enigma",496    "LaneSupport": 0,497    "Escape": 0,498    "Carry": 0,499    "Total": 13,500    "Support": 2501  },502  {503    "Initiator": 2,504    "Name": "Faceless Void",505    "Disabler": 1,506    "Pusher": 0,507    "Durable": 2,508    "Jungler": 0,509    "Nuker": 0,510    "slug": "faceless_void",511    "LaneSupport": 0,512    "Escape": 1,513    "Carry": 3,514    "Total": 9,515    "Support": 0,516    "Melee": 1517  },518  {519    "Initiator": 2,520    "Name": "Gyrocopter",521    "Disabler": 1,522    "Pusher": 3,523    "Durable": 0,524    "Jungler": 0,525    "Nuker": 2,526    "slug": "gyrocopter",527    "LaneSupport": 0,528    "Escape": 0,529    "Carry": 3,530    "Total": 11,531    "Support": 0532  },533  {534    "Initiator": 1,535    "Name": "Huskar",536    "Disabler": 0,537    "Pusher": 0,538    "Durable": 3,539    "Jungler": 1,540    "Nuker": 1,541    "slug": "huskar",542    "LaneSupport": 0,543    "Escape": 0,544    "Carry": 2,545    "Total": 9,546    "Support": 1547  },548  {549    "Initiator": 1,550    "Name": "Invoker",551    "Disabler": 3,552    "Pusher": 2,553    "Durable": 0,554    "Jungler": 0,555    "Nuker": 3,556    "slug": "invoker",557    "LaneSupport": 0,558    "Escape": 2,559    "Carry": 2,560    "Total": 14,561    "Support": 1562  },563  {564    "Initiator": 2,565    "Name": "IO",566    "Disabler": 1,567    "Pusher": 0,568    "Durable": 0,569    "Jungler": 0,570    "Nuker": 1,571    "slug": "wisp",572    "LaneSupport": 3,573    "Escape": 2,574    "Carry": 0,575    "Total": 12,576    "Support": 3577  },578  {579    "Initiator": 0,580    "Name": "Jakiro",581    "Disabler": 1,582    "Pusher": 2,583    "Durable": 1,584    "Jungler": 0,585    "Nuker": 2,586    "slug": "jakiro",587    "LaneSupport": 2,588    "Escape": 0,589    "Carry": 0,590    "Total": 10,591    "Support": 2592  },593  {594    "Initiator": 1,595    "Name": "Juggernaut",596    "Disabler": 0,597    "Pusher": 2,598    "Durable": 1,599    "Jungler": 0,600    "Nuker": 1,601    "slug": "juggernaut",602    "LaneSupport": 1,603    "Escape": 1,604    "Carry": 2,605    "Total": 9,606    "Support": 0,607    "Melee": 1608  },609  {610    "Initiator": 0,611    "Name": "Keeper of the Light",612    "Disabler": 1,613    "Pusher": 3,614    "Durable": 0,615    "Jungler": 1,616    "Nuker": 2,617    "slug": "keeper_of_the_light",618    "LaneSupport": 3,619    "Escape": 0,620    "Carry": 0,621    "Total": 13,622    "Support": 3623  },624  {625    "Initiator": 1,626    "Name": "Kunkka",627    "Disabler": 2,628    "Pusher": 2,629    "Durable": 2,630    "Jungler": 1,631    "Nuker": 2,632    "slug": "kunkka",633    "LaneSupport": 0,634    "Escape": 0,635    "Carry": 2,636    "Total": 12,637    "Support": 0,638    "Melee": 1639  },640  {641    "Initiator": 0,642    "Name": "Leshrac",643    "Disabler": 1,644    "Pusher": 3,645    "Durable": 0,646    "Jungler": 0,647    "Nuker": 2,648    "slug": "leshrac",649    "LaneSupport": 1,650    "Escape": 0,651    "Carry": 2,652    "Total": 11,653    "Support": 2654  },655  {656    "Initiator": 0,657    "Name": "Lich",658    "Disabler": 0,659    "Pusher": 1,660    "Durable": 0,661    "Jungler": 0,662    "Nuker": 3,663    "slug": "lich",664    "LaneSupport": 3,665    "Escape": 0,666    "Carry": 0,667    "Total": 10,668    "Support": 3669  },670  {671    "Initiator": 1,672    "Name": "Lifestealer",673    "Disabler": 1,674    "Pusher": 0,675    "Durable": 3,676    "Jungler": 1,677    "Nuker": 0,678    "slug": "life_stealer",679    "LaneSupport": 0,680    "Escape": 1,681    "Carry": 2,682    "Total": 9,683    "Support": 0,684    "Melee": 1685  },686  {687    "Initiator": 0,688    "Name": "Lina",689    "Disabler": 1,690    "Pusher": 2,691    "Durable": 0,692    "Jungler": 0,693    "Nuker": 3,694    "slug": "lina",695    "LaneSupport": 1,696    "Escape": 0,697    "Carry": 0,698    "Total": 9,699    "Support": 2700  },701  {702    "Initiator": 0,703    "Name": "Lion",704    "Disabler": 3,705    "Pusher": 1,706    "Durable": 0,707    "Jungler": 0,708    "Nuker": 3,709    "slug": "lion",710    "LaneSupport": 1,711    "Escape": 0,712    "Carry": 0,713    "Total": 10,714    "Support": 2715  },716  {717    "Initiator": 3,718    "Name": "Legion Commander",719    "Disabler": 1,720    "Pusher": 0,721    "Durable": 2,722    "Jungler": 3,723    "Nuker": 1,724    "slug": "legion_commander",725    "LaneSupport": 0,726    "Escape": 1,727    "Carry": 2,728    "Total": 9,729    "Support": 1,730    "Melee": 1731  },732  {733    "Initiator": 0,734    "Name": "Lone Druid",735    "Disabler": 1,736    "Pusher": 3,737    "Durable": 2,738    "Jungler": 1,739    "Nuker": 0,740    "slug": "lone_druid",741    "LaneSupport": 0,742    "Escape": 0,743    "Carry": 3,744    "Total": 10,745    "Support": 0746  },747  {748    "Initiator": 1,749    "Name": "Luna",750    "Disabler": 0,751    "Pusher": 3,752    "Durable": 0,753    "Jungler": 0,754    "Nuker": 2,755    "slug": "luna",756    "LaneSupport": 1,757    "Escape": 0,758    "Carry": 3,759    "Total": 10,760    "Support": 0761  },762  {763    "Initiator": 0,764    "Name": "Lycanthrope",765    "Disabler": 0,766    "Pusher": 3,767    "Durable": 2,768    "Jungler": 2,769    "Nuker": 0,770    "slug": "lycan",771    "LaneSupport": 0,772    "Escape": 1,773    "Carry": 2,774    "Total": 11,775    "Support": 1,776    "Melee": 1777  },778  {779    "Initiator": 3,780    "Name": "Magnus",781    "Disabler": 3,782    "Pusher": 1,783    "Durable": 1,784    "Jungler": 0,785    "Nuker": 1,786    "slug": "magnataur",787    "LaneSupport": 0,788    "Escape": 1,789    "Carry": 1,790    "Total": 12,791    "Support": 1,792    "Melee": 1793  },794  {795    "Initiator": 1,796    "Name": "Medusa",797    "Disabler": 1,798    "Pusher": 2,799    "Durable": 2,800    "Jungler": 1,801    "Nuker": 1,802    "slug": "medusa",803    "LaneSupport": 0,804    "Escape": 0,805    "Carry": 3,806    "Total": 11,807    "Support": 0808  },809  {810    "Initiator": 1,811    "Name": "Meepo",812    "Disabler": 1,813    "Pusher": 2,814    "Durable": 0,815    "Jungler": 0,816    "Nuker": 2,817    "slug": "meepo",818    "LaneSupport": 0,819    "Escape": 2,820    "Carry": 2,821    "Total": 10,822    "Support": 0,823    "Melee": 1824  },825  {826    "Initiator": 1,827    "Name": "Mirana",828    "Disabler": 1,829    "Pusher": 1,830    "Durable": 0,831    "Jungler": 0,832    "Nuker": 1,833    "slug": "mirana",834    "LaneSupport": 0,835    "Escape": 2,836    "Carry": 2,837    "Total": 9,838    "Support": 1839  },840  {841    "Initiator": 0,842    "Name": "Morphling",843    "Disabler": 1,844    "Pusher": 2,845    "Durable": 2,846    "Jungler": 0,847    "Nuker": 1,848    "slug": "morphling",849    "LaneSupport": 0,850    "Escape": 3,851    "Carry": 3,852    "Total": 12,853    "Support": 0854  },855  {856    "Initiator": 3,857    "Name": "Naga Siren",858    "Disabler": 2,859    "Pusher": 3,860    "Durable": 0,861    "Jungler": 0,862    "Nuker": 0,863    "slug": "naga_siren",864    "LaneSupport": 2,865    "Escape": 1,866    "Carry": 2,867    "Total": 16,868    "Support": 2,869    "Melee": 1870  },871  {872    "Initiator": 0,873    "Name": "Nature's Prophet",874    "Disabler": 1,875    "Pusher": 3,876    "Durable": 0,877    "Jungler": 2,878    "Nuker": 1,879    "slug": "furion",880    "LaneSupport": 0,881    "Escape": 1,882    "Carry": 2,883    "Total": 10,884    "Support": 0885  },886  {887    "Initiator": 0,888    "Name": "Necrolyte",889    "Disabler": 0,890    "Pusher": 1,891    "Durable": 2,892    "Jungler": 0,893    "Nuker": 2,894    "slug": "necrolyte",895    "LaneSupport": 1,896    "Escape": 0,897    "Carry": 2,898    "Total": 9,899    "Support": 1900  },901  {902    "Initiator": 2,903    "Name": "Night Stalker",904    "Disabler": 1,905    "Pusher": 1,906    "Durable": 2,907    "Jungler": 0,908    "Nuker": 1,909    "slug": "night_stalker",910    "LaneSupport": 0,911    "Escape": 1,912    "Carry": 1,913    "Total": 9,914    "Support": 0,915    "Melee": 1916  },917  {918    "Initiator": 1,919    "Name": "Nyx Assassin",920    "Disabler": 2,921    "Pusher": 0,922    "Durable": 0,923    "Jungler": 0,924    "Nuker": 3,925    "slug": "nyx_assassin",926    "LaneSupport": 1,927    "Escape": 2,928    "Carry": 0,929    "Total": 11,930    "Support": 2,931    "Melee": 1932  },933  {934    "Initiator": 1,935    "Name": "Ogre Magi",936    "Disabler": 2,937    "Pusher": 0,938    "Durable": 1,939    "Jungler": 0,940    "Nuker": 3,941    "slug": "ogre_magi",942    "LaneSupport": 1,943    "Escape": 0,944    "Carry": 0,945    "Total": 11,946    "Support": 3,947    "Melee": 1948  },949  {950    "Initiator": 0,951    "Name": "Omniknight",952    "Disabler": 0,953    "Pusher": 0,954    "Durable": 2,955    "Jungler": 0,956    "Nuker": 1,957    "slug": "omniknight",958    "LaneSupport": 3,959    "Escape": 0,960    "Carry": 0,961    "Total": 9,962    "Support": 3,963    "Melee": 1964  },965    {966    "Initiator": 1,967    "Name": "Oracle",968    "Disabler": 1,969    "Pusher": 0,970    "Durable": 1,971    "Jungler": 0,972    "Nuker": 1,973    "slug": "oracle",974    "LaneSupport": 2,975    "Escape": 1,976    "Carry": 0,977    "Total": 9,978    "Support": 2979  },980  {981    "Initiator": 0,982    "Name": "Outworld Devourer",983    "Disabler": 1,984    "Pusher": 0,985    "Durable": 0,986    "Jungler": 0,987    "Nuker": 2,988    "slug": "obsidian_destroyer",989    "LaneSupport": 1,990    "Escape": 0,991    "Carry": 2,992    "Total": 7,993    "Support": 1994  },995  {996    "Initiator": 0,997    "Name": "Phantom Assassin",998    "Disabler": 0,999    "Pusher": 0,1000    "Durable": 1,1001    "Jungler": 0,1002    "Nuker": 1,1003    "slug": "phantom_assassin",1004    "LaneSupport": 0,1005    "Escape": 1,1006    "Carry": 3,1007    "Total": 6,1008    "Support": 0,1009    "Melee": 11010  },1011  {1012    "Initiator": 0,1013    "Name": "Phantom Lancer",1014    "Disabler": 0,1015    "Pusher": 3,1016    "Durable": 1,1017    "Jungler": 0,1018    "Nuker": 1,1019    "slug": "phantom_lancer",1020    "LaneSupport": 0,1021    "Escape": 2,1022    "Carry": 3,1023    "Total": 10,1024    "Support": 0,1025    "Melee": 11026  },1027  {1028    "Initiator": 1,1029    "Name": "Phoenix",1030    "Disabler": 1,1031    "Pusher": 0,1032    "Durable": 2,1033    "Jungler": 0,1034    "Nuker": 2,1035    "slug": "phoenix",1036    "LaneSupport": 2,1037    "Escape": 3,1038    "Carry": 0,1039    "Total": 14,1040    "Support": 21041  },1042  {1043    "Initiator": 3,1044    "Name": "Puck",1045    "Disabler": 2,1046    "Pusher": 1,1047    "Durable": 0,1048    "Jungler": 0,1049    "Nuker": 2,1050    "slug": "puck",1051    "LaneSupport": 0,1052    "Escape": 3,1053    "Carry": 0,1054    "Total": 11,1055    "Support": 01056  },1057  {1058    "Initiator": 1,1059    "Name": "Pudge",1060    "Disabler": 2,1061    "Pusher": 0,1062    "Durable": 3,1063    "Jungler": 1,1064    "Nuker": 2,1065    "slug": "pudge",1066    "LaneSupport": 0,1067    "Escape": 0,1068    "Carry": 0,1069    "Total": 9,1070    "Support": 0,1071    "Melee": 11072  },1073  {1074    "Initiator": 1,1075    "Name": "Pugna",1076    "Disabler": 1,1077    "Pusher": 2,1078    "Durable": 0,1079    "Jungler": 0,1080    "Nuker": 2,1081    "slug": "pugna",1082    "LaneSupport": 0,1083    "Escape": 0,1084    "Carry": 0,1085    "Total": 8,1086    "Support": 21087  },1088  {1089    "Initiator": 1,1090    "Name": "Queen of Pain",1091    "Disabler": 0,1092    "Pusher": 1,1093    "Durable": 0,1094    "Jungler": 0,1095    "Nuker": 3,1096    "slug": "queenofpain",1097    "LaneSupport": 0,1098    "Escape": 3,1099    "Carry": 1,1100    "Total": 9,1101    "Support": 01102  },1103  {1104    "Initiator": 1,1105    "Name": "Razor",1106    "Disabler": 0,1107    "Pusher": 1,1108    "Durable": 2,1109    "Jungler": 0,1110    "Nuker": 2,1111    "slug": "razor",1112    "LaneSupport": 0,1113    "Escape": 0,1114    "Carry": 2,1115    "Total": 8,1116    "Support": 01117  },1118  {1119    "Initiator": 1,1120    "Name": "Riki",1121    "Disabler": 1,1122    "Pusher": 0,1123    "Durable": 0,1124    "Jungler": 0,1125    "Nuker": 0,1126    "slug": "riki",1127    "LaneSupport": 0,1128    "Escape": 2,1129    "Carry": 3,1130    "Total": 7,1131    "Support": 0,1132    "Melee": 11133  },1134  {1135    "Initiator": 1,1136    "Name": "Rubick",1137    "Disabler": 2,1138    "Pusher": 0,1139    "Durable": 0,1140    "Jungler": 0,1141    "Nuker": 2,1142    "slug": "rubick",1143    "LaneSupport": 3,1144    "Escape": 0,1145    "Carry": 0,1146    "Total": 11,1147    "Support": 31148  },1149  {1150    "Initiator": 3,1151    "Name": "Sand King",1152    "Disabler": 1,1153    "Pusher": 2,1154    "Durable": 0,1155    "Jungler": 0,1156    "Nuker": 2,1157    "slug": "sand_king",1158    "LaneSupport": 2,1159    "Escape": 2,1160    "Carry": 0,1161    "Total": 14,1162    "Support": 2,1163    "Melee": 11164  },1165  {1166    "Initiator": 2,1167    "Name": "Shadow Demon",1168    "Disabler": 2,1169    "Pusher": 0,1170    "Durable": 0,1171    "Jungler": 0,1172    "Nuker": 2,1173    "slug": "shadow_demon",1174    "LaneSupport": 1,1175    "Escape": 0,1176    "Carry": 0,1177    "Total": 10,1178    "Support": 31179  },1180  {1181    "Initiator": 2,1182    "Name": "Shadow Fiend",1183    "Disabler": 0,1184    "Pusher": 2,1185    "Durable": 0,1186    "Jungler": 0,1187    "Nuker": 3,1188    "slug": "nevermore",1189    "LaneSupport": 0,1190    "Escape": 0,1191    "Carry": 3,1192    "Total": 10,1193    "Support": 01194  },1195  {1196    "Initiator": 1,1197    "Name": "Shadow Shaman",1198    "Disabler": 3,1199    "Pusher": 3,1200    "Durable": 0,1201    "Jungler": 0,1202    "Nuker": 1,1203    "slug": "shadow_shaman",1204    "LaneSupport": 2,1205    "Escape": 0,1206    "Carry": 0,1207    "Total": 13,1208    "Support": 31209  },1210  {1211    "Initiator": 2,1212    "Name": "Silencer",1213    "Disabler": 2,1214    "Pusher": 0,1215    "Durable": 0,1216    "Jungler": 0,1217    "Nuker": 0,1218    "slug": "silencer",1219    "LaneSupport": 1,1220    "Escape": 0,1221    "Carry": 1,1222    "Total": 8,1223    "Support": 21224  },1225  {1226    "Initiator": 0,1227    "Name": "Wraith King",1228    "Search": "Skeleton King Wraith King",1229    "Disabler": 2,1230    "Pusher": 1,1231    "Durable": 3,1232    "Jungler": 0,1233    "Nuker": 1,1234    "slug": "skeleton_king",1235    "LaneSupport": 0,1236    "Escape": 0,1237    "Carry": 3,1238    "Total": 10,1239    "Support": 0,1240    "Melee": 11241  },1242  {1243    "Initiator": 0,1244    "Name": "Skywrath Mage",1245    "Disabler": 1,1246    "Pusher": 0,1247    "Durable": 0,1248    "Jungler": 0,1249    "Nuker": 3,1250    "slug": "skywrath_mage",1251    "LaneSupport": 2,1252    "Escape": 0,1253    "Carry": 1,1254    "Total": 9,1255    "Support": 21256  },1257  {1258    "Initiator": 1,1259    "Name": "Slardar",1260    "Disabler": 1,1261    "Pusher": 0,1262    "Durable": 2,1263    "Jungler": 0,1264    "Nuker": 0,1265    "slug": "slardar",1266    "LaneSupport": 1,1267    "Escape": 1,1268    "Carry": 2,1269    "Total": 8,1270    "Support": 0,1271    "Melee": 11272  },1273  {1274    "Initiator": 1,1275    "Name": "Slark",1276    "Disabler": 1,1277    "Pusher": 0,1278    "Durable": 0,1279    "Jungler": 0,1280    "Nuker": 2,1281    "slug": "slark",1282    "LaneSupport": 0,1283    "Escape": 3,1284    "Carry": 2,1285    "Total": 9,1286    "Support": 0,1287    "Melee": 11288  },1289  {1290    "Initiator": 0,1291    "Name": "Sniper",1292    "Disabler": 1,1293    "Pusher": 2,1294    "Durable": 0,1295    "Jungler": 0,1296    "Nuker": 1,1297    "slug": "sniper",1298    "LaneSupport": 0,1299    "Escape": 0,1300    "Carry": 2,1301    "Total": 6,1302    "Support": 01303  },1304  {1305    "Initiator": 1,1306    "Name": "Spectre",1307    "Disabler": 0,1308    "Pusher": 1,1309    "Durable": 3,1310    "Jungler": 0,1311    "Nuker": 0,1312    "slug": "spectre",1313    "LaneSupport": 0,1314    "Escape": 3,1315    "Carry": 3,1316    "Total": 11,1317    "Support": 0,1318    "Melee": 11319  },1320  {1321    "Initiator": 2,1322    "Name": "Spirit Breaker",1323    "Disabler": 1,1324    "Pusher": 0,1325    "Durable": 2,1326    "Jungler": 0,1327    "Nuker": 1,1328    "slug": "spirit_breaker",1329    "LaneSupport": 0,1330    "Escape": 2,1331    "Carry": 1,1332    "Total": 10,1333    "Support": 1,1334    "Melee": 11335  },1336  {1337    "Initiator": 2,1338    "Name": "Storm Spirit",1339    "Disabler": 1,1340    "Pusher": 0,1341    "Durable": 0,1342    "Jungler": 0,1343    "Nuker": 2,1344    "slug": "storm_spirit",1345    "LaneSupport": 0,1346    "Escape": 3,1347    "Carry": 2,1348    "Total": 10,1349    "Support": 01350  },1351  {1352    "Initiator": 1,1353    "Name": "Sven",1354    "Disabler": 2,1355    "Pusher": 2,1356    "Durable": 1,1357    "Jungler": 0,1358    "Nuker": 1,1359    "slug": "sven",1360    "LaneSupport": 0,1361    "Escape": 1,1362    "Carry": 3,1363    "Total": 12,1364    "Support": 1,1365    "Melee": 11366  },1367    {1368    "Initiator": 1,1369    "Name": "Techies",1370    "Disabler": 1,1371    "Pusher": 2,1372    "Durable": 0,1373    "Jungler": 1,1374    "Nuker": 3,1375    "slug": "techies",1376    "LaneSupport": 0,1377    "Escape": 0,1378    "Carry": 0,1379    "Total": 8,1380    "Support": 01381  },1382  {1383    "Initiator": 1,1384    "Name": "Templar Assassin",1385    "Disabler": 0,1386    "Pusher": 1,1387    "Durable": 1,1388    "Jungler": 0,1389    "Nuker": 1,1390    "slug": "templar_assassin",1391    "LaneSupport": 0,1392    "Escape": 1,1393    "Carry": 2,1394    "Total": 7,1395    "Support": 01396  },1397  {1398    "Initiator": 0,1399    "Name": "Terrorblade",1400    "Disabler": 1,1401    "Pusher": 1,1402    "Durable": 1,1403    "Jungler": 0,1404    "Nuker": 2,1405    "slug": "terrorblade",1406    "LaneSupport": 0,1407    "Escape": 0,1408    "Carry": 3,1409    "Total": 8,1410    "Support": 0,1411    "Melee": 11412  },1413  {1414    "Initiator": 3,1415    "Name": "Tidehunter",1416    "Disabler": 2,1417    "Pusher": 0,1418    "Durable": 2,1419    "Jungler": 0,1420    "Nuker": 1,1421    "slug": "tidehunter",1422    "LaneSupport": 2,1423    "Escape": 0,1424    "Carry": 0,1425    "Total": 12,1426    "Support": 2,1427    "Melee": 11428  },1429  {1430    "Initiator": 1,1431    "Name": "Timbersaw",1432    "Disabler": 0,1433    "Pusher": 1,1434    "Durable": 3,1435    "Jungler": 0,1436    "Nuker": 3,1437    "slug": "shredder",1438    "LaneSupport": 0,1439    "Escape": 3,1440    "Carry": 1,1441    "Total": 12,1442    "Support": 0,1443    "Melee": 11444  },1445  {1446    "Initiator": 0,1447    "Name": "Tinker",1448    "Disabler": 1,1449    "Pusher": 3,1450    "Durable": 0,1451    "Jungler": 1,1452    "Nuker": 3,1453    "slug": "tinker",1454    "LaneSupport": 0,1455    "Escape": 0,1456    "Carry": 2,1457    "Total": 10,1458    "Support": 01459  },1460  {1461    "Initiator": 2,1462    "Name": "Tiny",1463    "Disabler": 2,1464    "Pusher": 1,1465    "Durable": 2,1466    "Jungler": 0,1467    "Nuker": 3,1468    "slug": "tiny",1469    "LaneSupport": 0,1470    "Escape": 0,1471    "Carry": 2,1472    "Total": 12,1473    "Support": 0,1474    "Melee": 11475  },1476  {1477    "Initiator": 2,1478    "Name": "Treant Protector",1479    "Disabler": 2,1480    "Pusher": 0,1481    "Durable": 2,1482    "Jungler": 0,1483    "Nuker": 0,1484    "slug": "treant",1485    "LaneSupport": 2,1486    "Escape": 1,1487    "Carry": 0,1488    "Total": 12,1489    "Support": 3,1490    "Melee": 11491  },1492  {1493    "Initiator": 0,1494    "Name": "Troll Warlord",1495    "Disabler": 1,1496    "Pusher": 3,1497    "Durable": 0,1498    "Jungler": 1,1499    "Nuker": 1,1500    "slug": "troll_warlord",1501    "LaneSupport": 0,1502    "Escape": 0,1503    "Carry": 2,1504    "Total": 8,1505    "Support": 01506  },1507  {1508    "Initiator": 2,1509    "Name": "Tusk",1510    "Disabler": 1,1511    "Pusher": 0,1512    "Durable": 1,1513    "Jungler": 0,1514    "Nuker": 2,1515    "slug": "tusk",1516    "LaneSupport": 0,1517    "Escape": 0,1518    "Carry": 1,1519    "Total": 7,1520    "Support": 0,1521    "Melee": 11522  },1523  {1524    "Initiator": 2,1525    "Name": "Undying",1526    "Disabler": 0,1527    "Pusher": 1,1528    "Durable": 3,1529    "Jungler": 0,1530    "Nuker": 2,1531    "slug": "undying",1532    "LaneSupport": 3,1533    "Escape": 0,1534    "Carry": 0,1535    "Total": 12,1536    "Support": 1,1537    "Melee": 11538  },1539  {1540    "Initiator": 1,1541    "Name": "Ursa",1542    "Disabler": 0,1543    "Pusher": 0,1544    "Durable": 2,1545    "Jungler": 1,1546    "Nuker": 1,1547    "slug": "ursa",1548    "LaneSupport": 0,1549    "Escape": 0,1550    "Carry": 3,1551    "Total": 8,1552    "Support": 0,1553    "Melee": 11554  },1555  {1556    "Initiator": 2,1557    "Name": "Vengeful Spirit",1558    "Disabler": 2,1559    "Pusher": 0,1560    "Durable": 0,1561    "Jungler": 0,1562    "Nuker": 1,1563    "slug": "vengefulspirit",1564    "LaneSupport": 2,1565    "Escape": 1,1566    "Carry": 1,1567    "Total": 11,1568    "Support": 21569  },1570  {1571    "Initiator": 1,1572    "Name": "Venomancer",1573    "Disabler": 0,1574    "Pusher": 2,1575    "Durable": 0,1576    "Jungler": 0,1577    "Nuker": 2,1578    "slug": "venomancer",1579    "LaneSupport": 3,1580    "Escape": 0,1581    "Carry": 1,1582    "Total": 12,1583    "Support": 31584  },1585  {1586    "Initiator": 1,1587    "Name": "Viper",1588    "Disabler": 1,1589    "Pusher": 0,1590    "Durable": 1,1591    "Jungler": 0,1592    "Nuker": 2,1593    "slug": "viper",1594    "LaneSupport": 0,1595    "Escape": 0,1596    "Carry": 2,1597    "Total": 7,1598    "Support": 01599  },1600  {1601    "Initiator": 0,1602    "Name": "Visage",1603    "Disabler": 2,1604    "Pusher": 1,1605    "Durable": 2,1606    "Jungler": 0,1607    "Nuker": 3,1608    "slug": "visage",1609    "LaneSupport": 3,1610    "Escape": 1,1611    "Carry": 0,1612    "Total": 14,1613    "Support": 21614  },1615  {1616    "Initiator": 3,1617    "Name": "Warlock",1618    "Disabler": 1,1619    "Pusher": 1,1620    "Durable": 0,1621    "Jungler": 0,1622    "Nuker": 2,1623    "slug": "warlock",1624    "LaneSupport": 3,1625    "Escape": 0,1626    "Carry": 0,1627    "Total": 12,1628    "Support": 21629  },1630  {1631    "Initiator": 0,1632    "Name": "Weaver",1633    "Disabler": 0,1634    "Pusher": 1,1635    "Durable": 2,1636    "Jungler": 0,1637    "Nuker": 0,1638    "slug": "weaver",1639    "LaneSupport": 0,1640    "Escape": 3,1641    "Carry": 3,1642    "Total": 9,1643    "Support": 01644  },1645  {1646    "Initiator": 0,1647    "Name": "Windrunner",1648    "Disabler": 1,1649    "Pusher": 2,1650    "Durable": 1,1651    "Jungler": 0,1652    "Nuker": 1,1653    "slug": "windrunner",1654    "LaneSupport": 2,1655    "Escape": 2,1656    "Carry": 1,1657    "Total": 12,1658    "Support": 21659  },1660    {1661    "Initiator": 2,1662    "Name": "Winter Wyvern",1663    "Disabler": 3,1664    "Pusher": 1,1665    "Durable": 0,1666    "Jungler": 0,1667    "Nuker": 1,1668    "slug": "winter_wyvern",1669    "LaneSupport": 2,1670    "Escape": 0,1671    "Carry": 0,1672    "Total": 11,1673    "Support": 21674  },1675  {1676    "Initiator": 1,1677    "Name": "Witch Doctor",1678    "Disabler": 1,1679    "Pusher": 1,1680    "Durable": 0,1681    "Jungler": 0,1682    "Nuker": 2,1683    "slug": "witch_doctor",1684    "LaneSupport": 2,1685    "Escape": 0,1686    "Carry": 0,1687    "Total": 9,1688    "Support": 21689  },1690  {1691    "Initiator": 1,1692    "Name": "Zeus",1693    "Disabler": 0,1694    "Pusher": 1,1695    "Durable": 0,1696    "Jungler": 0,1697    "Nuker": 3,1698    "slug": "zuus",1699    "LaneSupport": 1,1700    "Escape": 0,1701    "Carry": 0,1702    "Total": 7,1703    "Support": 11704  }...stream.spec.js
Source:stream.spec.js  
1/* eslint-env mocha */2'use strict'3const { expect } = require('aegir/utils/chai')4const pipe = require('it-pipe')5const { randomBytes } = require('iso-random-stream')6const randomInt = require('random-int')7const { tap, take, collect, consume, map } = require('streaming-iterables')8const defer = require('p-defer')9const uint8ArrayConcat = require('uint8arrays/concat')10const cborg = require('cborg')11const createStream = require('../src/stream')12const { MessageTypes, MessageTypeNames } = require('../src/message-types')13function randomInput (min = 1, max = 100) {14  return Promise.all(15    Array.from(Array(randomInt(min, max)), () => randomBytes(randomInt(1, 128)))16  )17}18function expectMsgType (actual, expected) {19  expect(MessageTypeNames[actual]).to.equal(MessageTypeNames[expected])20}21const infiniteRandom = {22  [Symbol.iterator]: function * () {23    while (true) yield randomBytes(randomInt(1, 128))24  }25}26const msgToBuffer = msg => cborg.encode(msg)27const bufferToMessage = buf => cborg.decode(buf)28describe('stream', () => {29  it('should initiate stream with NEW_STREAM message', async () => {30    const msgs = []31    const mockSend = msg => msgs.push(msg)32    const id = randomInt(1000)33    const stream = createStream({ id, send: mockSend })34    const input = await randomInput()35    await pipe(input, stream)36    expect(msgs[0].id).to.equal(id)37    expectMsgType(msgs[0].type, MessageTypes.NEW_STREAM)38    expect(msgs[0].data).to.deep.equal(id.toString())39  })40  it('should initiate named stream with NEW_STREAM message', async () => {41    const msgs = []42    const mockSend = msg => msgs.push(msg)43    const id = randomInt(1000)44    const name = `STREAM${Date.now()}`45    const stream = createStream({ id, name, send: mockSend })46    const input = await randomInput()47    await pipe(input, stream)48    expect(msgs[0].id).to.equal(id)49    expectMsgType(msgs[0].type, MessageTypes.NEW_STREAM)50    expect(msgs[0].data).to.deep.equal(name)51  })52  it('should end a stream when it is aborted', async () => {53    const msgs = []54    const mockSend = msg => msgs.push(msg)55    const id = randomInt(1000)56    const name = `STREAM${Date.now()}`57    const deferred = defer()58    const stream = createStream({ id, name, onEnd: deferred.resolve, send: mockSend })59    const error = new Error('boom')60    stream.abort(error)61    const err = await deferred.promise62    expect(err).to.equal(error)63  })64  it('should end a stream when it is reset', async () => {65    const msgs = []66    const mockSend = msg => msgs.push(msg)67    const id = randomInt(1000)68    const name = `STREAM${Date.now()}`69    const deferred = defer()70    const stream = createStream({ id, name, onEnd: deferred.resolve, send: mockSend })71    stream.reset()72    const err = await deferred.promise73    expect(err).to.exist()74    expect(err).to.have.property('code', 'ERR_MPLEX_STREAM_RESET')75  })76  it('should send data with MESSAGE_INITIATOR messages if stream initiator', async () => {77    const msgs = []78    const mockSend = msg => msgs.push(msg)79    const id = randomInt(1000)80    const name = id.toString()81    const stream = createStream({ id, name, send: mockSend, type: 'initiator' })82    const input = await randomInput()83    await pipe(input, stream)84    // First and last should be NEW_STREAM and CLOSE85    const dataMsgs = msgs.slice(1, -1)86    expect(dataMsgs).have.length(input.length)87    dataMsgs.forEach((msg, i) => {88      expect(msg.id).to.equal(id)89      expectMsgType(msg.type, MessageTypes.MESSAGE_INITIATOR)90      expect(msg.data).to.deep.equal(input[i])91    })92  })93  it('should send data with MESSAGE_RECEIVER messages if stream receiver', async () => {94    const msgs = []95    const mockSend = msg => msgs.push(msg)96    const id = randomInt(1000)97    const name = id.toString()98    const stream = createStream({ id, name, send: mockSend, type: 'receiver' })99    const input = await randomInput()100    await pipe(input, stream)101    // Last should be CLOSE102    const dataMsgs = msgs.slice(0, -1)103    expect(dataMsgs).have.length(input.length)104    dataMsgs.forEach((msg, i) => {105      expect(msg.id).to.equal(id)106      expectMsgType(msg.type, MessageTypes.MESSAGE_RECEIVER)107      expect(msg.data).to.deep.equal(input[i])108    })109  })110  it('should close stream with CLOSE_INITIATOR message if stream initiator', async () => {111    const msgs = []112    const mockSend = msg => msgs.push(msg)113    const id = randomInt(1000)114    const name = id.toString()115    const stream = createStream({ id, name, send: mockSend, type: 'initiator' })116    const input = await randomInput()117    await pipe(input, stream)118    const closeMsg = msgs[msgs.length - 1]119    expect(closeMsg.id).to.equal(id)120    expectMsgType(closeMsg.type, MessageTypes.CLOSE_INITIATOR)121    expect(closeMsg.data).to.not.exist()122  })123  it('should close stream with CLOSE_RECEIVER message if stream receiver', async () => {124    const msgs = []125    const mockSend = msg => msgs.push(msg)126    const id = randomInt(1000)127    const name = id.toString()128    const stream = createStream({ id, name, send: mockSend, type: 'receiver' })129    const input = await randomInput()130    await pipe(input, stream)131    const closeMsg = msgs[msgs.length - 1]132    expect(closeMsg.id).to.equal(id)133    expectMsgType(closeMsg.type, MessageTypes.CLOSE_RECEIVER)134    expect(closeMsg.data).to.not.exist()135  })136  it('should reset stream on error with RESET_INITIATOR message if stream initiator', async () => {137    const msgs = []138    const mockSend = msg => msgs.push(msg)139    const id = randomInt(1000)140    const name = id.toString()141    const stream = createStream({ id, name, send: mockSend, type: 'initiator' })142    const error = new Error(`Boom ${Date.now()}`)143    const input = {144      [Symbol.iterator]: function * () {145        for (let i = 0; i < randomInt(1, 10); i++) {146          yield randomBytes(randomInt(1, 128))147        }148        throw error149      }150    }151    await pipe(input, stream)152    const resetMsg = msgs[msgs.length - 1]153    expect(resetMsg.id).to.equal(id)154    expectMsgType(resetMsg.type, MessageTypes.RESET_INITIATOR)155    expect(resetMsg.data).to.not.exist()156  })157  it('should reset stream on error with RESET_RECEIVER message if stream receiver', async () => {158    const msgs = []159    const mockSend = msg => msgs.push(msg)160    const id = randomInt(1000)161    const name = id.toString()162    const stream = createStream({ id, name, send: mockSend, type: 'receiver' })163    const error = new Error(`Boom ${Date.now()}`)164    const input = {165      [Symbol.iterator]: function * () {166        for (let i = 0; i < randomInt(1, 10); i++) {167          yield randomBytes(randomInt(1, 128))168        }169        throw error170      }171    }172    await pipe(input, stream)173    const resetMsg = msgs[msgs.length - 1]174    expect(resetMsg.id).to.equal(id)175    expectMsgType(resetMsg.type, MessageTypes.RESET_RECEIVER)176    expect(resetMsg.data).to.not.exist()177  })178  it('should close for reading (remote close)', async () => {179    const mockInitiatorSend = msg => receiver.source.push(msg)180    const mockReceiverSend = msg => initiator.source.push(msg)181    const id = randomInt(1000)182    const name = id.toString()183    const initiator = createStream({ id, name, send: mockInitiatorSend, type: 'initiator' })184    const receiver = createStream({ id, name, send: mockReceiverSend, type: 'receiver' })185    // echo back (on the other side this will be { type: MESSAGE, data: msg })186    pipe(187      receiver,188      map(msg => {189        // when the initiator sends a CLOSE message, we call close190        if (msg.type === MessageTypes.CLOSE_INITIATOR) {191          receiver.close()192        }193        return msgToBuffer(msg)194      }),195      receiver196    )197    const input = await randomInput()198    const msgs = await pipe(199      input,200      initiator,201      tap(msg => {202        // when the receiver sends a CLOSE message, we call close203        if (msg.type === MessageTypes.CLOSE_RECEIVER) {204          initiator.close()205        }206        if (msg.data) {207          msg.data = bufferToMessage(msg.data)208        }209      }),210      collect211    )212    // NEW_STREAM should have been echoed back to us213    expectMsgType(msgs[0].type, MessageTypes.MESSAGE_RECEIVER)214    expectMsgType(msgs[0].data.type, MessageTypes.NEW_STREAM)215    // check the receiver echoed back all our data messages216    expect(msgs.slice(1, -2).length).to.equal(input.length)217    msgs.slice(1, -2).forEach((msg, i) => {218      expectMsgType(msg.data.type, MessageTypes.MESSAGE_INITIATOR)219      expect(msg.data.data).to.deep.equal(input[i])220    })221    // ...and echoed back the close message222    expectMsgType(msgs[msgs.length - 2].type, MessageTypes.MESSAGE_RECEIVER)223    expectMsgType(msgs[msgs.length - 2].data.type, MessageTypes.CLOSE_INITIATOR)224    // ...and finally sent a close message225    const closeMsg = msgs[msgs.length - 1]226    expectMsgType(closeMsg.type, MessageTypes.CLOSE_RECEIVER)227    expect(closeMsg.data).to.not.exist()228  })229  it('should close for reading and writing (abort on local error)', async () => {230    const mockInitiatorSend = msg => receiver.source.push(msg)231    const mockReceiverSend = msg => initiator.source.push(msg)232    const id = randomInt(1000)233    const name = id.toString()234    const initiator = createStream({ id, name, send: mockInitiatorSend, type: 'initiator' })235    const receiver = createStream({ id, name, send: mockReceiverSend, type: 'receiver' })236    // echo back (on the other side this will be { type: MESSAGE, data: msg })237    pipe(238      receiver,239      map(msg => {240        // when the initiator sends a RESET message, we call reset241        if (msg.type === MessageTypes.RESET_INITIATOR) {242          receiver.reset()243        }244        return msgToBuffer(msg)245      }),246      receiver247    )248    const input = infiniteRandom249    const error = new Error(`Boom ${Date.now()}`)250    const maxMsgs = randomInt(1, 10)251    const generatedMsgs = []252    const msgs = []253    try {254      let i = 0255      await pipe(256        input,257        tap(msg => generatedMsgs.push(msg)),258        initiator,259        tap(msg => {260          if (msg.data) {261            msg.data = bufferToMessage(msg.data)262          }263          msgs.push(msg)264          if (i++ >= maxMsgs) {265            initiator.abort(error)266          }267        }),268        consume269      )270    } catch (err) {271      expect(err.message).to.equal(error.message)272      // NEW_STREAM should have been echoed back to us273      expectMsgType(msgs[0].type, MessageTypes.MESSAGE_RECEIVER)274      expectMsgType(msgs[0].data.type, MessageTypes.NEW_STREAM)275      expect(msgs).to.have.length(generatedMsgs.length)276      // check the receiver echoed back all our data messages, and nothing else277      msgs.slice(1).forEach((msg, i) => {278        expectMsgType(msg.data.type, MessageTypes.MESSAGE_INITIATOR)279        expect(msg.data.data).to.deep.equal(generatedMsgs[i])280      })281    }282  })283  it('should close for reading and writing (abort on remote error)', async () => {284    const mockInitiatorSend = msg => receiver.source.push(msg)285    const mockReceiverSend = msg => initiator.source.push(msg)286    const id = randomInt(1000)287    const name = id.toString()288    const initiator = createStream({ id, name, send: mockInitiatorSend, type: 'initiator' })289    const receiver = createStream({ id, name, send: mockReceiverSend, type: 'receiver' })290    const error = new Error(`Boom ${Date.now()}`)291    const maxMsgs = randomInt(1, 10)292    let i = 0293    // echo back (on the other side this will be { type: MESSAGE, data: msg })294    pipe(295      receiver,296      map(msg => {297        if (i++ >= maxMsgs) receiver.abort(error)298        return msgToBuffer(msg)299      }),300      receiver301    )302    const input = infiniteRandom303    const generatedMsgs = []304    const msgs = []305    try {306      await pipe(307        input,308        tap(msg => generatedMsgs.push(msg)),309        initiator,310        tap(msg => msgs.push(msg)),311        tap(msg => {312          // when the receiver sends a RESET message, we call reset313          if (msg.type === MessageTypes.RESET_RECEIVER) {314            initiator.reset()315          }316          if (msg.data) {317            msg.data = bufferToMessage(msg.data)318          }319        }),320        consume321      )322    } catch (err) {323      expect(err.message).to.equal('stream reset')324      // NEW_STREAM should have been echoed back to us325      expectMsgType(msgs[0].type, MessageTypes.MESSAGE_RECEIVER)326      expectMsgType(msgs[0].data.type, MessageTypes.NEW_STREAM)327      // because the receiver errored we might not have received all our data messages328      expect(msgs.length - 2).to.be.lte(generatedMsgs.length)329      // check the receiver echoed back some/all our data messages330      msgs.slice(1, -1).forEach((msg, i) => {331        expectMsgType(msg.data.type, MessageTypes.MESSAGE_INITIATOR)332        expect(msg.data.data).to.deep.equal(generatedMsgs[i])333      })334      // ...and finally a RESET message335      expectMsgType(msgs[msgs.length - 1].type, MessageTypes.RESET_RECEIVER)336    }337  })338  it('should close immediately for reading and writing (reset on local error)', async () => {339    const mockInitiatorSend = msg => receiver.source.push(msg)340    const mockReceiverSend = msg => initiator.source.push(msg)341    const id = randomInt(1000)342    const name = id.toString()343    const initiator = createStream({ id, name, send: mockInitiatorSend, type: 'initiator' })344    const receiver = createStream({ id, name, send: mockReceiverSend, type: 'receiver' })345    // echo back (on the other side this will be { type: MESSAGE, data: msg })346    pipe(347      receiver,348      map(msg => {349        // when the initiator sends a RESET message, we call reset350        if (msg.type === MessageTypes.RESET_INITIATOR) {351          receiver.reset()352        }353        return msgToBuffer(msg)354      }),355      receiver356    )357    const input = infiniteRandom358    const error = new Error(`Boom ${Date.now()}`)359    const maxMsgs = randomInt(1, 10)360    const generatedMsgs = []361    const msgs = []362    try {363      let i = 0364      await pipe(365        input,366        tap(msg => generatedMsgs.push(msg)),367        tap(msg => { if (i++ >= maxMsgs) throw error }),368        initiator,369        tap(msg => {370          if (msg.data) {371            msg.data = bufferToMessage(msg.data)372          }373          msgs.push(msg)374        }),375        consume376      )377    } catch (err) {378      expect(err.message).to.equal(error.message)379      // NEW_STREAM should have been echoed back to us380      expectMsgType(msgs[0].type, MessageTypes.MESSAGE_RECEIVER)381      expectMsgType(msgs[0].data.type, MessageTypes.NEW_STREAM)382      // because we errored locally we might not receive all the echo messages383      // from the receiver before our source stream is ended384      expect(msgs.length - 1).to.be.lte(generatedMsgs.length)385      // check the receiver echoed back some/all our data messages, and nothing else386      msgs.slice(1).forEach((msg, i) => {387        expectMsgType(msg.data.type, MessageTypes.MESSAGE_INITIATOR)388        expect(msg.data.data).to.deep.equal(generatedMsgs[i])389      })390    }391  })392  it('should close immediately for reading and writing (reset on remote error)', async () => {393    const mockInitiatorSend = msg => receiver.source.push(msg)394    const mockReceiverSend = msg => initiator.source.push(msg)395    const id = randomInt(1000)396    const name = id.toString()397    const initiator = createStream({ id, name, send: mockInitiatorSend, type: 'initiator' })398    const receiver = createStream({ id, name, send: mockReceiverSend, type: 'receiver' })399    const error = new Error(`Boom ${Date.now()}`)400    const maxMsgs = randomInt(1, 10)401    let i = 0402    // echo back (on the other side this will be { type: MESSAGE, data: msg })403    pipe(404      receiver,405      map(msg => {406        if (i++ >= maxMsgs) throw error407        return msgToBuffer(msg)408      }),409      receiver410    )411    const input = infiniteRandom412    const generatedMsgs = []413    const msgs = []414    try {415      await pipe(416        input,417        tap(msg => generatedMsgs.push(msg)),418        initiator,419        tap(msg => msgs.push(msg)),420        tap(msg => {421          // when the receiver sends a RESET message, we call reset422          if (msg.type === MessageTypes.RESET_RECEIVER) {423            initiator.reset()424          }425          if (msg.data) {426            msg.data = bufferToMessage(msg.data)427          }428        }),429        consume430      )431    } catch (err) {432      expect(err.message).to.equal('stream reset')433      // NEW_STREAM should have been echoed back to us434      expectMsgType(msgs[0].type, MessageTypes.MESSAGE_RECEIVER)435      expectMsgType(msgs[0].data.type, MessageTypes.NEW_STREAM)436      // because we errored locally we might not receive all the echo messages437      // from the receiver before our source stream is ended438      expect(msgs.length - 2).to.be.lte(generatedMsgs.length)439      // check the receiver echoed back some/all our data messages440      msgs.slice(1, -1).forEach((msg, i) => {441        expectMsgType(msg.data.type, MessageTypes.MESSAGE_INITIATOR)442        expect(msg.data.data).to.deep.equal(generatedMsgs[i])443      })444      // ...and finally a RESET message445      expectMsgType(msgs[msgs.length - 1].type, MessageTypes.RESET_RECEIVER)446    }447  })448  it('should call onEnd only when both sides have closed', async () => {449    const send = msg => stream.source.push(msg)450    const id = randomInt(1000)451    const name = id.toString()452    const deferred = defer()453    const onEnd = err => err ? deferred.reject(err) : deferred.resolve()454    const stream = createStream({ id, name, send, onEnd })455    const input = await randomInput()456    pipe(input, stream, take(randomInt(1, input.length)), consume)457    await deferred.promise458  })459  it('should call onEnd with error for local error', async () => {460    const send = msg => stream.source.push(msg)461    const id = randomInt(1000)462    const name = id.toString()463    const deferred = defer()464    const onEnd = err => err ? deferred.reject(err) : deferred.resolve()465    const stream = createStream({ id, name, send, onEnd })466    const error = new Error(`Boom ${Date.now()}`)467    const maxMsgs = randomInt(1, 10)468    let i = 0469    pipe(infiniteRandom, tap(msg => { if (i++ >= maxMsgs) throw error }), stream)470    try {471      await deferred.promise472    } catch (err) {473      return expect(err.message).to.equal(error.message)474    }475    throw new Error('did not call onEnd with error')476  })477  it('should split writes larger than max message size', async () => {478    const send = msg => {479      if (msg.type === MessageTypes.CLOSE_INITIATOR) {480        stream.source.end()481      } else if (msg.type === MessageTypes.MESSAGE_INITIATOR) {482        stream.source.push(msg)483      }484    }485    const id = randomInt(1000)486    const name = id.toString()487    const maxMsgSize = 5488    const stream = createStream({ id, name, send, maxMsgSize })489    const bigMessage = await randomBytes(12)490    const dataMessages = await pipe([bigMessage], stream, collect)491    expect(dataMessages.length).to.equal(3)492    expect(dataMessages[0].data.length).to.equal(maxMsgSize)493    expect(dataMessages[1].data.length).to.equal(maxMsgSize)494    expect(dataMessages[2].data.length).to.equal(2)495    expect(uint8ArrayConcat(dataMessages.map(m => m.data.slice()))).to.deep.equal(bigMessage)496  })...jquery.spine.framework.js
Source:jquery.spine.framework.js  
1/** 2@ Author :chuzhisheng 3@ Date : 2015-8-14 4@ Version : 1.0 5*/6(function(){7	var Spine, Framework, Model, Class, Controller, Util, Page,moduleKeywords,8	indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },9	hasProp = {}.hasOwnProperty,10	extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };11	Date.prototype.format = function (format) {  12	    var configure = {"M+": this.getMonth() + 1, "d+": this.getDate(), "H+": this.getHours(), "h+": this.getHours(), "m+": this.getMinutes(), "s+": this.getSeconds(), "q+": Math.floor((this.getMonth() + 3) / 3), "S": this.getMilliseconds() };13	    if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));14	    for (var k in configure)15	    if (new RegExp("(" + k + ")").test(format)) format = format.replace(RegExp.$1, (RegExp.$1.length == 1) ? (configure[k]) : (("00" + configure[k]).substr(("" + configure[k]).length)));16	    return format;17	};18	Spine = this.Spine;19	/**20	 * 客æ·ç«¯æ°æ®æ¨¡åï¼å®ç°æ°æ®æä¹
å21	 */22	Model = Spine.Model.sub();23	24	/**25	 * 客æ·ç«¯ä¸å¡æ§å¶å¨ï¼å®ç°ä¸å¡é»è¾å°è£
26	 */27	Controller = Spine.Controller.sub();28	/**29	 * 客æ·ç«¯æ°æ®æ¨¡åï¼å®ç°æ°æ®æä¹
å30	 */31	Class = Spine.Model.sub(Spine.Log);32	/**33	 * 客æ·ç«¯å·¥å
·å¯¹è±¡ï¼å°è£
客æ·ç«¯å¸¸ç¨æ¹æ³34	 */35	Util = Spine.Controller.sub();36	/**37	 * 客æ·ç«¯åå§å¨å¯¹è±¡ï¼é¡µé¢å è½½å®æ¯åæ§è¡38	 */39	Initiator = Spine.Controller.sub({40		//æé å¨41		init: function(options){42			var i, events, fun;43			events = this.events = this.events||[];44			for(i in options){45				fun = options[i];46				if(fun instanceof Function){47					events[i] = fun;48				}49			}50			this.trace = this.constructor.trace;51			this.logPrefix = this.constructor.logPrefix;52			this.url = this.constructor.url;53		},54		add: function(options){55			events = this.events = this.events||[];56			for(i in options){57				fun = options[i];58				if(fun instanceof Function){59					events[i] = fun;60				}61			}62		},63		//è¿è¡åå§å64		run: function(){65			var _self = this;66			var i, events, fun;67			events = this.events = this.events||[];68			success = this.success = this.success||[];69			failure = this.failure = this.failure||[];70			$(function(){71				for(i in events){72					fun = events[i];73					if(fun instanceof Function){74						try{75							fun();76						}catch (e) {77							if(_self.trace&&window.console){78							window.console.log(i+" å è½½å¤±è´¥! "+ e.message);79							window.console.log("å¼å¸¸å½æ°ï¼ "+fun);80							}81							failure[i] = fun;82							continue;83						}84					}85					success[i] = fun;86					if(_self.trace&&window.console){87					window.console.log(i+" å è½½æå!");88					}89				}90			});91		}92	});93	94	var trim = function(){$("input").each(function(){$(this).val($(this).val().trim());})};95	96	/**97	 * 项ç®é¡µé¢å¯¹è±¡98	 */99	Page = Spine.Controller.sub({100		config: function(context, suffix){101			this.context = context;102			this.suffix = suffix;103			this.url = window.location.pathname.replace("." + suffix, "");104		},105		func: function(options){106			for(var i in options){107				this[i] = options[i]108			}109		},110		/**111		 * 页é¢å è½½112		 * Page.ready({113		 * 		"å è½½è¯´æ"ï¼function(){}114		 * })115		 */116		ready: function(initiatorOptons){117			var initiator = new Initiator();118			initiator.add(initiatorOptons);119			initiator.run();120		},121		/**122		 *æ§å¶å¨ajaxè¯·æ±æ¹æ³123		 * formOptions(表ååæ°é) { 124		 * 		id: 表åid,125		 * 		action: actionè·¯å¾,126		 * 		method: æ¹æ³è·¯å¾,127		 * 		success: function(data){128		 * 			æåè¿åæ§è¡çé»è¾ï¼data为Jsonæ ¼å¼129		 * 		},130		  * 		params(urlåæ°é): {131		 * 			屿§ï¼å¼132		 * 		}133		 * 	}134		 */135		ajax:function(formOptions){136			trim();137			var _self = this, suffix = this.suffix, param="?";138			var i, formId, action, method, params, error, success, url, datas;139			140			formId = formOptions["id"];141			action = formOptions["action"]?"../"+formOptions["action"]+"/":"";142			method = formOptions["method"] || "";143			params = formOptions["params"];144			for(i in params){145				param += i+"="+params[i]+"&";146			}147			param = param.substring(0, param.length-1);148			149			url = action + method + "." + suffix + param;150			datas = $("#" + formId).serialize();151			error = formOptions["error"];152			error = error && error instanceof Function ? error : function(request, status, error){153				_self.initiator.log(url+" AJax请æ±å¤±è´¥");154			};155			success = formOptions["success"];156			success = success && success instanceof Function ? success : function(result){157				_self.initiator.log(url+" AJaxè¯·æ±æå");158			};159			$.ajax({160				type:	"post",161				dataType:	"json",162				url:	url, 163				data:	datas,    164				async:	false,165				error:	error,166			    success: success167			});168		},169		/**170		 * submit页é¢è¡¨åæäº¤171		 * formOptions {@ 表ååæ°é} { 172		 * 		id: 表åid ï¼173		 * 		actionï¼actionè·¯å¾ï¼174		 * 		methodï¼ æ¹æ³è·¯å¾ï¼175		 * 		params {@ urlåæ°é}{176		 * 			屿§ï¼å¼177		 * 		}178		 * 	}179		 * 180		 */181		submit: function(formOptions){182			var suffix = this.suffix;183			var errorMesseges, form, action, method, i, params, validate;184			form = formOptions["form"]?$("#"+formOptions["form"]):$("form").eq(0);185			action = formOptions["action"]?"../" + formOptions["action"]+"/":"";186			method = formOptions["method"]||"";187			params = formOptions["params"]||{};188			form.attr("action",action + method + "." + suffix + "?" + $.param(params));189			if(this.__submitValidate__()){190				form.submit();191			}192		},193		/**194		 * submit页é¢è¡¨åæäº¤195		 * 		callback æ ¡éªå½æ° {Function}196		 */197		validate: function(callback){198			var _callbacks, _i, pass = true;199			_callbacks = this._submitCallbacks = this._submitCallbacks || [];200			_errorMessages = this._errorMessages = this._errorMessages || [];201			if(callback){202				//æ¯å¦éå¤203				for(_i in _callbacks){204					if(callback == _callbacks[_i]);205					return void(0);206				}207				_callbacks.push(callback);208			}else{209				return this.__submitValidate__();210			}211		},212		/**213		 * addErroræ·»å é误信æ¯214		 * message é误信æ¯{String}215		 */216		addError: function(message){217			var _errorMessages;218			_errorMessages = this._errorMessages = this._errorMessages || [];219			_errorMessages.push(message);220		},221		/**222		 * error é¡µé¢æäº¤ä¸éè¿æ§è¡é»è¾223		 * 		callback æ ¡éªå½æ° {Function}224		 */225		error: function(callback){226			var _errorMessages;227			_errorMessages = this._errorMessages = this._errorMessages || [];228			if(callback instanceof Function){229				this._error = callback;230			}else if(this._error instanceof Function){231				this._error(_errorMessages);232				this._errorMessages = [];233			}234		},235		__submitValidate__: function(){236			var _callbacks, _errorMessages, _i, pass = true;237			_callbacks = this._submitCallbacks = this._submitCallbacks || [];238			_errorMessages = this._errorMessages = this._errorMessages || [];239			//æ¯å¦éå¤240			for(_i in _callbacks){241				if(_callbacks[_i] instanceof Function){242					var result = _callbacks[_i].apply(this,arguments);243					if(typeof result !="undefined"){244						pass &= result;245					}246					if(!pass){247						this.error();248						return false;249					};250				}251			}252			if(_errorMessages.length > 0){253				this.error();254				return false;255			}256			return true;257		}258	});259	260	moduleKeywords = ['included', 'extended'];261	/**262	 * 客æ·ç«¯æ°æ®æ¨¡å对象å
·æçéææ¹æ³263	 */264	Model.extend({265		/**266		 *æ°æ®æ¨¡åajaxè¯·æ±æ¹æ³267		 * formOptions(表ååæ°é) { 268		 * 		id: 表åid,269		 * 		action: actionè·¯å¾,270		 * 		method: æ¹æ³è·¯å¾,271		 * 		success: function(model){272		 * 			æåè¿åæ§è¡çé»è¾ï¼model为客æ·ç«¯æ°æ®æ¨¡å对象273		 * 		},274		 * 		params(urlåæ°é): {275		 * 			屿§ï¼å¼276		 * 		}277		 * 	}278		 */279		config: function(context, suffix){280			this.context = context;281			this.suffix = suffix;282		},283		ajax: function(formOptions){284			trim();285			var _self = this,suffix = this.suffix, param="?";286			287			formOptions.action = formOptions.action||_self.className;288			289			var i, formId, action, method, params, error, success, url, datas;290			291			formId = formOptions["id"];292			action = formOptions["action"]?"../"+formOptions["action"]+"/":"";293			method = formOptions["method"] || "";294			params = formOptions["params"];295			error = formOptions["error"];296			error = error && error instanceof Function ? error : function(request, status, error){297				_self.initiator.log(url+"请æ±å¤±è´¥");298			};299			success = function(result){300				formOptions["success"](_self.fromJSON(result));301			};302			success = success && success instanceof Function ? success : function(result){303				_self.initiator.log(url+"è¯·æ±æå");304			};305			for(i in params){306				param += i+"="+params[i]+"&";307			}308			param = param.substring(0, param.length-1);309			url = action + method + "." + suffix + param;310			datas = $("#" + formId).serialize();311			$.ajax({312				type:	"post",313				dataType:	"json",314				url:	url, 315				data:	datas,    316				async:	false,317				error:	error,318			    success: success319			});320		}321	});322	323	324	/**325	 * 项ç®å¯¹è±¡326	 */327	Framework = this.Framework = Class.sub({328		config: function(context, suffix){329			this.context = context;330			this.suffix = suffix;331			this.Page.config(context, suffix);332			this.Model.config(context, suffix);333		},334		//项ç®åå§å335		init: function(projectOptions){336			for(var i in projectOptions){337				if(!this[i]){338					this[i] = projectOptions[i];339				}340			}341			//Initiator.app =  ""342			//Initiator.suffix = this.suffix || /.(*)+/343			Initiator.url = window.location.pathname;344			Initiator.logPrefix = new Date().format("yyyy-MM-dd HH:mm:ss")+" (" + Initiator.url + ")";345			Initiator.trace = this.debug || false;346			this.initiator = new Initiator();347			this.Page.initiator = new Initiator();348			this.Model.initiator = new Initiator();349			//console.clear();350		},351		ready: function(initiatorOptions){352			var initiator = this.initiator;353			initiator.add(initiatorOptions);354			initiator.run();355		},356		plugin: function(projectOptions){357			for(var i in projectOptions){358				if(!this[i]){359					this[i] = projectOptions[i];360					this.initiator.log(i+"ç»ä»¶å è½½æå");361				}else{362					this.initiator.log(i+"ç»ä»¶å·²ç»åå¨ï¼å è½½å¤±è´¥");363				}364			}365		},366		extend:function(obj){367			var key, ref, value;368		      if (!obj) {369		        throw new Error('extend(obj) requires obj');370		      }371		      for (key in obj) {372		        value = obj[key];373		        if (indexOf.call(moduleKeywords, key) < 0) {374		          this[key] = value;375		        }376		      }377		      if ((ref = obj.extended) != null) {378		        ref.apply(this);379		      }380		      return this;381		},382		Model: Model.sub(),383		Class: Class.sub(),384		Controller: Controller.sub(),385		Util: Util.sub(),386		Initiator: Initiator.sub(),387		Page: new Page()388	});389	390	Framework.configure("notFind","suffix");391	392	Controller.create = Controller.sub = Model.create = Model.sub = Class.create = Class.sub = Util.create = Util.sub = function(instances, statics) {393	    Result = (function(superClass) {394	      extend(Result, superClass);395396	      function Result() {397	        return Result.__super__.constructor.apply(this, arguments);398	      }399400	      return Result;401402	    })(this);403	    if (instances) {404	      Result.include(instances);405	    }406	    if (statics) {407	      Result.extend(statics);408	    }409	    if (typeof Result.unbind === "function") {410	      Result.unbind();411	    }412	    return Result;413	};
...trackers.js
Source:trackers.js  
1_trackers = { // sets up our tracker object that we reference the webrequests against to find out if the webrequest is a tracker2    'Amazon Associates': {3      type: 'Advertising',4      _url: 'https://c.amazon-adsystem.com/',5      enabled: false,6      initiator: ''7    },8    'Google Publisher Tags': {9      type: 'Advertising',10      _url: 'https://www.googletagservices.com/tag/',11      enabled: false,12      initiator: ''13    },14    'NetRatings SiteCensus': {15      type: 'Advertising',16      _url: 'https://cdn-gl.imrworldwide.com/',17      enabled: false,18      initiator: ''19    },20    'Google IMA': {21      type: 'Advertising',22      _url: 'https://imasdk.googleapis.com/',23      enabled: false,24      initiator: ''25    },26    'Google Analytics': {27      type: 'Site Analytics',28      _url: 'https://www.google-analytics.com',29      enabled: false,30      initiator: ''31    },32    'ScoreCard Research Beacon': {33      type: 'Site Analytics',34      _url: 'https://sb.scorecardresearch.com',35      enabled: false,36      initiator: ''37    },38    'Adobe Audience Manager': {39      type: 'Advertising',40      _url: 'https://dpm.demdex.net/',41      enabled: false,42      initiator: ''43    },44    'Adobe Test & Target': {45      type: 'Advertising',46      _url: 'https://assets.adobedtm.com/',47      enabled: false,48      initiator: ''49    },50    'Twitter Advertising': {51      type: 'Advertising',52      _url: 'https://static.ads-twitter.com/',53      enabled: false,54      initiator: ''55    },56    'DoubleClick Floodlight': {57      type: 'Advertising',58      _url: 'https://2987979.fls.doubleclick.net/',59      enabled: false,60      initiator: ''61    },62    'Facebook Custom Audience': {63      type: 'Advertising',64      _url: 'https://www.facebook.com/tr/',65      enabled: false,66      initiator: ''67    },68    'Facebook Business': {69      type: 'Advertising',70      _url: 'https:www.facebook.com/tr/',71      enabled: false,72      initiator: ''73    },74    TouchCommerce: {75      type: 'Customer Interaction',76      _url: 'https://mediaeastv3.inq.com/media/',77      enabled: false,78      initiator: ''79    },80    'Adobe Dynamic Tag Management': {81      type: 'Essential',82      _url: 'https://assets.adobedtm.com',83      enabled: false,84      initiator: ''85    },86    'Google Tag Manager': {87      type: 'Essential',88      _url: 'https://www.googletagmanager.com/',89      enabled: false,90      initiator: ''91    },92    'LinkedIn Analyticis': {93      type: 'Site Analytics',94      _url: 'https://snap.licdn.com/li.lms-analytics/',95      enabled: false,96      initiator: ''97    },98    'SiteImprove Analytics': {99      type: 'Site Analytics',100      _url: 'https://siteimproveanalytics.com/',101      enabled: false,102      initiator: ''103    },104    'Facebook Connect': {105      type: 'Social Media',106      _url: 'https://connect.facebook.net/',107      enabled: false,108      initiator: ''109    },110    'Google Adsense': {111      type: 'Advertising',112      _url: 'https://pagead2.googlesyndication.com/',113      enabled: false,114      initiator: ''115    },116    'Advertising com': {117      type: 'Advertising',118      _url: 'https://tag.sp.advertising.com/',119      enabled: false,120      initiator: ''121    },122    ADTECH: {123      type: 'Site Analytics',124      _url: 'https://aka-cdn.adtechus.com/',125      enabled: false,126      initiator: ''127    },128    DoubleClick: {129      type: 'Advertising',130      _url: 'https://cm.g.doubleclick.net/',131      enabled: false,132      initiator: ''133    },134    AppNexus: {135      type: 'Advertising',136      _url: 'https://secure.adnxs.com/',137      enabled: false,138      initiator: ''139    },140    Tynt: {141      type: 'Advertising',142      _url: 'https://de.tynt.com/',143      enabled: false,144      initiator: ''145    },146    Captify: {147      type: 'Advertising',148      _url: 'https://s.cpx.to/',149      enabled: false,150      initiator: ''151    },152    '33Across': {153      type: 'Advertising',154      _url: 'https://cms-xch.33across.com/',155      enabled: false,156      initiator: ''157    },158    gumgum: {159      type: 'Advertising',160      _url: 'https://rtb.gumgum.com',161      enabled: false,162      initiator: ''163    },164    PubMatic: {165      type: 'Advertising',166      _url: 'https://image4.pubmatic.com/',167      enabled: false,168      initiator: ''169    },170    'Rhythmone Beacon': {171      type: 'Advertising',172      _url: 'https://sync.1rx.io/',173      enabled: false,174      initiator: ''175    },176    'CPX Interactive': {177      type: 'Advertising',178      _url: 'https://cookie.brealtime.com',179      enabled: false,180      initiator: ''181    },182    Drawbridge: {183      type: 'Advertising',184      _url: 'https://p.adsymptotic.com/',185      enabled: false,186      initiator: ''187    },188    MediaMath: {189      type: 'Advertising',190      _url: 'https://sync.mathtag.com',191      enabled: false,192      initiator: ''193    },194    'Yahoo Ad Exchange': {195      type: 'Advertising',196      _url: 'https://ads.yahoo.com/',197      enabled: false,198      initiator: ''199    },200    SiteScout: {201      type: 'Advertising',202      _url: 'https://pixel-sync.sitescout.com',203      enabled: false,204      initiator: ''205    },206    Criteo: {207      type: 'Advertising',208      _url: 'https://dis.criteo.com/',209      enabled: false,210      initiator: ''211    },212    'Simpli fi': {213      type: 'Advertising',214      _url: 'https://um.simpli.fi/',215      enabled: false,216      initiator: ''217    },218    Beeswax: {219      type: 'Advertising',220      _url: 'https://match.prod.bidr.io/',221      enabled: false,222      initiator: ''223    },224    LiveRamp: {225      type: 'Advertising',226      _url: 'https://idsync.rlcdn.com/',227      enabled: false,228      initiator: ''229    },230    'Turn Inc': {231      type: 'Advertising',232      _url: 'https://ad.turn.com',233      enabled: false,234      initiator: ''235    },236    TradeDesk: {237      type: 'Advertising',238      _url: 'https://match.adsrvr.org/',239      enabled: false,240      initiator: ''241    },242    'Yahoo Ad Manager Plus': {243      type: 'Advertising',244      _url: 'https://pr-bh.ybp.yahoo.com/',245      enabled: false,246      initiator: ''247    },248    Quantcast: {249      type: 'Advertising',250      _url: 'https://pixel.quantserve.com/',251      enabled: false,252      initiator: ''253    },254    DataXu: {255      type: 'Advertising',256      _url: 'https://pm.w55c.net/',257      enabled: false,258      initiator: ''259    },260    Dotomi: {261      type: 'Advertising',262      _url: 'https://pubmatic-match.dotomi.com',263      enabled: false,264      initiator: ''265    },266    RUN: {267      type: 'Advertising',268      _url: 'https://match.rundsp.com/',269      enabled: false,270      initiator: ''271    },272    'eyeReturn Marketing': {273      type: 'Advertising',274      _url: 'https://cm.eyereturn.com/',275      enabled: false,276      initiator: ''277    },278    'MaxPoint Interactive': {279      type: 'Advertising',280      _url: 'https://pmp.mxptint.net/',281      enabled: false,282      initiator: ''283    },284    Adform: {285      type: 'Advertising',286      _url: 'https://c1.adform.net/s',287      enabled: false,288      initiator: ''289    },290    Netmining: {291      type: 'Advertising',292      _url: 'https://pubmatic2waycm-atl.netmng.com/',293      enabled: false,294      initiator: ''295    },296    BidSwitch: {297      type: 'Advertising',298      _url: 'https://x.bidswitch.net/',299      enabled: false,300      initiator: ''301    },302    OwnerIQ: {303      type: 'Advertising',304      _url: 'https://px.owneriq.net/',305      enabled: false,306      initiator: ''307    },308    'Tribal Fusion': {309      type: 'Advertising',310      _url: 'https://a.tribalfusion.com/',311      enabled: false,312      initiator: ''313    },314    Taboola: {315      type: 'Advertising',316      _url: 'https://match.taboola.com/',317      enabled: false,318      initiator: ''319    },320    AdGear: {321      type: 'Advertising',322      _url: 'https://cm.adgrx.com/',323      enabled: false,324      initiator: ''325    },326    PulsePoint: {327      type: 'Advertising',328      _url: 'https://bh.contextweb.com',329      enabled: false,330      initiator: ''331    },332    Platform161: {333      type: 'Advertising',334      _url: 'https://ads.creative-serving.com',335      enabled: false,336      initiator: ''337    },338    'SMART AdServer': {339      type: 'Advertising',340      _url: 'https://rtb-csync.smartadserver.com/',341      enabled: false,342      initiator: ''343    },344    GetIntent: {345      type: 'Advertising',346      _url: 'https://px.adhigh.net/',347      enabled: false,348      initiator: ''349    },350    RadiumOne: {351      type: 'Advertising',352      _url: 'https://rp.gwallet.com/',353      enabled: false,354      initiator: ''355    },356    Tapad: {357      type: 'Advertising',358      _url: 'https://pixel.tapad.com/',359      enabled: false,360      initiator: ''361    },362    Logicad: {363      type: 'Advertising',364      _url: 'https://cr-pall.ladsp.com/',365      enabled: false,366      initiator: ''367    },368    Zemanta: {369      type: 'Customer Interaction',370      _url: 'https://b1sync.zemanta.com/',371      enabled: false,372      initiator: ''373    },374    'GA Audiences': {375      type: 'Site Analytics',376      _url: 'https://www.google.com/ads/ga-audiences',377      enabled: false,378      initiator: ''379    }...rsa-jwt-needham-schroeder.js
Source:rsa-jwt-needham-schroeder.js  
1const crypto = require('crypto');2// eslint-disable-next-line3const jwt = require('jsonwebtoken');4// eslint-disable-next-line5const { generateKeyPair } = require('crypto');6const aud = 'https://element-did.com';7const getAuthKey = didDoc =>8  didDoc.publicKey.find(k => k.id === `${didDoc.id}#auth`);9const generateKey = () =>10  new Promise((resolve, reject) => {11    generateKeyPair(12      'rsa',13      {14        modulusLength: 4096,15        publicKeyEncoding: {16          type: 'spki',17          format: 'pem',18        },19        privateKeyEncoding: {20          type: 'pkcs8',21          format: 'pem',22          // cipher: 'aes-256-cbc',23          // passphrase: 'top secret',24        },25      },26      (err, publicKey, privateKey) => {27        // Handle errors and use the generated key pair.28        if (err) {29          return reject(err);30        }31        return resolve({ publicKey, privateKey });32      }33    );34  });35const createM0 = async ({36  resolve,37  initiatorDid,38  responderDid,39  initiatorPrivateKey,40}) => {41  const initiatorDidDoc = await resolve(initiatorDid);42  const responderDidDoc = await resolve(responderDid);43  const initiatorAuthKey = getAuthKey(initiatorDidDoc);44  const responderDidAuthKey = getAuthKey(responderDidDoc);45  const Na = crypto.randomBytes(32).toString('hex');46  const dataBuffer = Buffer.from(47    JSON.stringify({48      Na,49    })50  );51  const token = jwt.sign(52    {53      protocolMessage: 'm0',54      from: initiatorAuthKey.id,55      to: responderDidAuthKey.id,56      message: crypto57        .publicEncrypt(responderDidAuthKey.publicKeyPem, dataBuffer)58        .toString('base64'),59    },60    initiatorPrivateKey,61    {62      issuer: initiatorDid,63      subject: responderDid,64      audience: aud,65      expiresIn: '1h',66      algorithm: 'RS256',67    }68  );69  return {70    m0: token,71    Na,72  };73};74const createM1 = async ({75  resolve,76  m0,77  initiatorDid,78  responderDid,79  responderPrivateKey,80}) => {81  const decoded = jwt.decode(m0);82  if (decoded.protocolMessage !== 'm0') {83    throw new Error(`Wrong protocolMessage ${decoded.protocolMessage}`);84  }85  if (initiatorDid !== decoded.iss) {86    throw new Error('initiatorDid must be iss for m0');87  }88  if (responderDid !== decoded.sub) {89    throw new Error('responderDid must be sub for m0');90  }91  const initiatorDidDoc = await resolve(initiatorDid);92  const responderDidDoc = await resolve(responderDid);93  const initiatorAuthKey = getAuthKey(initiatorDidDoc);94  const responderDidAuthKey = getAuthKey(responderDidDoc);95  const verified = jwt.verify(m0, initiatorAuthKey.publicKeyPem, {96    issuer: initiatorDid,97    subject: responderDid,98    audience: aud,99    expiresIn: '1hr',100    algorithm: ['RS256'],101  });102  const decrypted = JSON.parse(103    crypto104      .privateDecrypt(105        responderPrivateKey,106        Buffer.from(verified.message, 'base64')107      )108      .toString()109  );110  if (!decrypted.Na) {111    throw new Error('Na must be present in m0.message');112  }113  const Nb = crypto.randomBytes(32).toString('hex');114  const dataBuffer = Buffer.from(115    JSON.stringify({116      Nb,117      Na: decrypted.Na,118      did: responderDid,119    })120  );121  const m1 = jwt.sign(122    {123      from: responderDidAuthKey.id,124      to: initiatorAuthKey.id,125      protocolMessage: 'm1',126      message: crypto127        .publicEncrypt(initiatorAuthKey.publicKeyPem, dataBuffer)128        .toString('base64'),129    },130    responderPrivateKey,131    {132      issuer: responderDid,133      subject: initiatorDid,134      audience: aud,135      expiresIn: '1h',136      algorithm: 'RS256',137    }138  );139  return {140    Nb,141    m1,142  };143};144const createM2 = async ({145  resolve,146  m1,147  initiatorDid,148  responderDid,149  initiatorPrivateKey,150  Na,151}) => {152  const decoded = jwt.decode(m1);153  if (decoded.protocolMessage !== 'm1') {154    throw new Error(`Wrong protocolMessage ${decoded.protocolMessage}`);155  }156  if (responderDid !== decoded.iss) {157    throw new Error('responderDid must be iss for m1');158  }159  if (initiatorDid !== decoded.sub) {160    throw new Error('initiatorDid must be sub for m1');161  }162  const initiatorDidDoc = await resolve(initiatorDid);163  const responderDidDoc = await resolve(responderDid);164  const initiatorAuthKey = getAuthKey(initiatorDidDoc);165  const responderDidAuthKey = getAuthKey(responderDidDoc);166  // Note that we use the resolver to verify the issuer key.167  const verified = jwt.verify(m1, responderDidAuthKey.publicKeyPem, {168    issuer: responderDid,169    subject: initiatorDid,170    audience: aud,171    expiresIn: '1hr',172    algorithm: ['RS256'],173  });174  const decrypted = JSON.parse(175    crypto176      .privateDecrypt(177        initiatorPrivateKey,178        Buffer.from(verified.message, 'base64')179      )180      .toString()181  );182  if (decrypted.Na !== Na) {183    throw new Error('m1 contained incorrect Na.');184  }185  if (!decrypted.Nb) {186    throw new Error('m1 did not contain Nb.');187  }188  if (decrypted.did !== responderDid) {189    throw new Error('m1 message.did must be responderDid.');190  }191  // Alice has authenticated Bob.192  const dataBuffer = Buffer.from(193    JSON.stringify({194      Nb: decrypted.Nb,195    })196  );197  const m2 = jwt.sign(198    {199      from: initiatorAuthKey.id,200      to: responderDidAuthKey.id,201      protocolMessage: 'm2',202      message: crypto203        .publicEncrypt(responderDidAuthKey.publicKeyPem, dataBuffer)204        .toString('base64'),205    },206    initiatorPrivateKey,207    {208      issuer: initiatorDid,209      subject: responderDid,210      audience: aud,211      expiresIn: '1h',212      algorithm: 'RS256',213    }214  );215  return {216    m2,217    Na: decrypted.Na,218    Nb: decrypted.Nb,219  };220};221const verifyM2 = async ({222  m2,223  resolve,224  initiatorDid,225  responderDid,226  responderPrivateKey,227  Nb,228}) => {229  const decoded = jwt.decode(m2);230  if (decoded.protocolMessage !== 'm2') {231    throw new Error(`Wrong protocolMessage ${decoded.protocolMessage}`);232  }233  if (initiatorDid !== decoded.iss) {234    throw new Error('initiatorDid must be iss for m2');235  }236  if (responderDid !== decoded.sub) {237    throw new Error('responderDid must be sub for m2');238  }239  const initiatorDidDoc = await resolve(decoded.iss);240  const initiatorAuthKey = getAuthKey(initiatorDidDoc);241  const verified = jwt.verify(m2, initiatorAuthKey.publicKeyPem, {242    issuer: initiatorDid,243    subject: responderDid,244    audience: aud,245    expiresIn: '1hr',246    algorithm: ['RS256'],247  });248  const decrypted = JSON.parse(249    crypto250      .privateDecrypt(251        responderPrivateKey,252        Buffer.from(verified.message, 'base64')253      )254      .toString()255  );256  if (decrypted.Nb !== Nb) {257    throw new Error('m2 contained incorrect Nb.');258  }259  return true;260};261module.exports = {262  generateKey,263  createM0,264  createM1,265  createM2,266  verifyM2,...videoSignallingServer.js
Source:videoSignallingServer.js  
1self.sessions = {};2var initiatorTag = "initiator";3var receiverTag = "receiver";4var sessionIdTag = "sessionId";5var storedMessagesTag = "storedMessages";6self.addEventListener("connect",function(e){7	var port = e.ports[0];8	port.onmessage = function(rawMsg){9		var msg = rawMsg.data;10		if (sessionIdTag in msg){11			var sessionId = msg.sessionId;12			if (!(sessionId in self.sessions)){13				self.sessions[sessionId] = {14					id:sessionId15				};16			}17			var session = sessions[sessionId];18			if (initiatorTag in session && session[initiatorTag].userId == msg.userId){19				//you're the pre-existing initiator20				if (receiverTag in session){21					session[receiverTag].port.postMessage(msg);22				} else {23					session[initiatorTag][storedMessagesTag].push(msg);24				}25			} else if (receiverTag in session && session[receiverTag].userId == msg.userId){26				//you're the pre-existing receiver27				if (initiatorTag in session){28					session[initiatorTag].port.postMessage(msg);29				} else {30					session[receiverTag][storedMessages].push(msg);31				}32			} else if (!(initiatorTag in session)){33				//you're the new initiator34				session[initiatorTag] = {35					userId:msg.userId,36					port:port,37					storedMessages:[]38				};39				sessions[sessionId] = session;40				port.postMessage({41					"connect":sessionId,42					"isCaller":true43				});44				if (receiverTag in session && storedMessagesTag in session.receiver){45					//playback any stored messages from the receiver 46					var currentMessage = session[receiverTag][storedMessagesTag].shift();47					while (currentMessage != undefined){48						port.postMessage(currentMessage);49						currentMessage = session[receiverTag][storedMessagesTag].shift();50					}51				}52			} else if (!(receiverTag in session)){53				//you're the new recipient54				session[receiverTag] = {55					userId:msg.userId,56					port:port,57					storedMessage:[]58				};59				sessions[sessionId] = session;60				port.postMessage({61					"connect":sessionId,62					"isCaller":false63				});64				if (initiatorTag in session && storedMessagesTag in session.initiator){65					//playback any stored messages from the initiator66					//67					var currentMessage = session[initiatorTag][storedMessagesTag].shift();68					while (currentMessage != undefined){69						port.postMessage(currentMessage);70						currentMessage = session[initiatorTag][storedMessagesTag].shift();71					}72				}73			} else {74				port.postMessage({75					error:"too many people in this session"76				});77				port.close();78			}79		}80	};...avPeerMgr.js
Source:avPeerMgr.js  
1class AVPeerMgr {2  constructor(userId,3              targetUserId,4              initiator = false) {5    this.userId = userId;6    this.targetUserId = targetUserId;7    this.self = (this.userId === this.targetUserId);8    this.initiator = initiator;9    this.sdpInvite = undefined;10    this.sdpResponse = undefined;11    this.peerObjInitiator = undefined;12    this.peerObjResponder = undefined;13    this.stream = undefined;14  }15  getUserId() {16    return this.userId;17  }18  getTargetId() {19    return this.targetUserId;20  }21  setInitiator(isInitiator) {22    this.initiator = isInitiator;23  }24  isInitiator() {25    return this.initiator;26  }27  isSelf() {28    return this.self;29  }30  setPeerObjInitiator(aPeerObj) {31    this.peerObjInitiator = aPeerObj;32  }33  getPeerObjInitiator() {34    return this.peerObjInitiator;35  }36  setPeerObjResponder(aPeerObj) {37    this.peerObjResponder = aPeerObj;38  }39  getPeerObjResponder() {40    return this.peerObjResponder;41  }42  setPeerObj(aPeerObj) {43    if (this.initiator) {44      this.peerObjInitiator = aPeerObj;45    } else {46      this.peerObjResponder = aPeerObj;47    }48  }49  setSdpInvite(anSdpObj) {50    this.sdpInvite = anSdpObj;51  }52  getSdpInvite() {53    return this.sdpInvite;54  }55  setSdpResponse(anSdpObj) {56    this.sdpResponse = anSdpObj;57  }58  getSdpResponse() {59    return this.sdpResponse;60  }61  setStream(aStream) {62    this.stream = aStream;63  }64  close() {65    if (this.stream) {66      const vidTracks = this.stream.getVideoTracks();67      if (vidTracks && (vidTracks.length > 0)) {68        for (const vidTrack of vidTracks) {69          vidTrack.stop();70        }71      }72      const audTracks = this.stream.getAudioTracks();73      if (audTracks && (audTracks.length > 0)) {74        for (const audTrack of audTracks) {75          audTrack.stop();76        }77      }78    }79    if (this.peerObjInitiator) {80      this.peerObjInitiator.destroy();81    }82    if (this.peerObjResponder) {83      this.peerObjResponder.destroy();84    }85  }86}...EEconTradeResponse.js
Source:EEconTradeResponse.js  
1/**2 * @enum EEconTradeResponse3 */4module.exports = {5	"Accepted": 0,6	"Declined": 1,7	"TradeBannedInitiator": 2,8	"TradeBannedTarget": 3,9	"TargetAlreadyTrading": 4,10	"Disabled": 5,11	"NotLoggedIn": 6,12	"Cancel": 7,13	"TooSoon": 8,14	"TooSoonPenalty": 9,15	"ConnectionFailed": 10,16	"AlreadyTrading": 11,17	"AlreadyHasTradeRequest": 12,18	"NoResponse": 13,19	"CyberCafeInitiator": 14,20	"CyberCafeTarget": 15,21	"SchoolLabInitiator": 16,22	"SchoolLabTarget": 16,23	"InitiatorBlockedTarget": 18,24	"InitiatorNeedsVerifiedEmail": 20,25	"InitiatorNeedsSteamGuard": 21,26	"TargetAccountCannotTrade": 22,27	"InitiatorSteamGuardDuration": 23,28	"InitiatorPasswordResetProbation": 24,29	"InitiatorNewDeviceCooldown": 25,30	"InitiatorSentInvalidCookie": 26,31	"NeedsEmailConfirmation": 27,32	"InitiatorRecentEmailChange": 28,33	"NeedsMobileConfirmation": 29,34	"TradingHoldForClearedTradeOffersInitiator": 30,35	"WouldExceedMaxAssetCount": 31,36	"OKToDeliver": 50,37	// Value-to-name mapping for convenience38	"0": "Accepted",39	"1": "Declined",40	"2": "TradeBannedInitiator",41	"3": "TradeBannedTarget",42	"4": "TargetAlreadyTrading",43	"5": "Disabled",44	"6": "NotLoggedIn",45	"7": "Cancel",46	"8": "TooSoon",47	"9": "TooSoonPenalty",48	"10": "ConnectionFailed",49	"11": "AlreadyTrading",50	"12": "AlreadyHasTradeRequest",51	"13": "NoResponse",52	"14": "CyberCafeInitiator",53	"15": "CyberCafeTarget",54	"16": "SchoolLabTarget",55	"18": "InitiatorBlockedTarget",56	"20": "InitiatorNeedsVerifiedEmail",57	"21": "InitiatorNeedsSteamGuard",58	"22": "TargetAccountCannotTrade",59	"23": "InitiatorSteamGuardDuration",60	"24": "InitiatorPasswordResetProbation",61	"25": "InitiatorNewDeviceCooldown",62	"26": "InitiatorSentInvalidCookie",63	"27": "NeedsEmailConfirmation",64	"28": "InitiatorRecentEmailChange",65	"29": "NeedsMobileConfirmation",66	"30": "TradingHoldForClearedTradeOffersInitiator",67	"31": "WouldExceedMaxAssetCount",68	"50": "OKToDeliver",...Using AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch({headless: false});4  const page = await browser.newPage();5  await page.screenshot({path: 'google.png'});6  await browser.close();7})();8const puppeteer = require('puppeteer-core');9(async () => {10  const browser = await puppeteer.launch({11  });12  const page = await browser.newPage();13  await page.screenshot({path: 'google.png'});14  await browser.close();15})();16const puppeteer = require('puppeteer');17(async () => {18  const browser = await puppeteer.launch({executablePath: '/path/to/Chromium'});19  const page = await browser.newPage();20  await page.screenshot({path: 'google.png'});21  await browser.close();22})();23const puppeteer = require('puppeteer');24(async () => {25  const browser = await puppeteer.launch({executablePath: '/path/to/Chromium'});26  const page = await browser.newPage();27  await page.screenshot({path: 'google.png'});28  await browser.close();29})();30const puppeteer = require('puppeteer');31(async () => {32  const browser = await puppeteer.launch({executablePath: '/path/to/Chromium'});33  const page = await browser.newPage();34  await page.screenshot({path: 'google.png'});35  await browser.close();36})();37const puppeteer = require('puppeteer');38(async () => {39  const browser = await puppeteer.launch({executablePath: '/path/to/Chromium'});40  const page = await browser.newPage();41  await page.screenshot({path: 'google.png'});42  await browser.close();43})();Using AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch({4  });5  const page = await browser.newPage();6  await page.screenshot({path: 'example.png'});7  await browser.close();8})();9#0 0x55f0e7d7c6e9 base::debug::CollectStackTrace()10#1 0x55f0e7b8e3c3 base::debug::StackTrace::StackTrace()11#2 0x55f0e7b8e5f5 logging::LogMessage::~LogMessage()12#3 0x55f0e7b8e6c5 logging::LogMessage::~LogMessage()13#4 0x55f0e7b8e6f2 LOG(FATAL)14#5 0x55f0e7b8e6f2 logging::LogMessageFatal::~LogMessageFatal()15#6 0x55f0e7b8e6f2 logging::LogMessageFatal::~LogMessageFatal()Using AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch({4  });5  const page = await browser.newPage();6  await page.screenshot({path: 'example.png'});7  await browser.close();8})();9const puppeteer = require('puppeteer');10(async () => {11  const browser = await puppeteer.launch({12  });13  const page = await browser.newPage();14  await page.screenshot({path: 'example.png'});15  await browser.close();16})();17const puppeteer = require('puppeteer');18(async () => {19  const browser = await puppeteer.launch({20  });21  const page = await browser.newPage();22  await page.screenshot({path: 'example.png'});23  await browser.close();24})();25const puppeteer = require('puppeteer');26(async () => {27  const browser = await puppeteer.launch({28  });29  const page = await browser.newPage();30  await page.screenshot({path: 'example.png'});31  await browser.close();32})();33const puppeteer = require('puppeteer');34(async () => {35  const browser = await puppeteer.launch({36  });37  const page = await browser.newPage();38  await page.screenshot({path: 'example.png'});39  await browser.close();40})();Using AI Code Generation
1const puppeteer = require('puppeteer');2const devices = require('puppeteer/DeviceDescriptors');3const iPhone = devices['iPhone 6'];4(async () => {5    const browser = await puppeteer.launch({headless: false});6    const page = await browser.newPage();7    await page.emulate(iPhone);8    await page.screenshot({path: 'google.png'});9    await browser.close();10})();11Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome or Chromium. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium. Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome or ChromiumUsing AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch({headless: false});4  const page = await browser.newPage();5  await page.screenshot({path: 'google.png'});6  await browser.close();7})();8const puppeteer = require('puppeteer');9(async () => {10  const browser = await puppeteer.launch({headless: true});11  const page = await browser.newPage();12  await page.screenshot({path: 'google.png'});13  await browser.close();14})();Using AI Code Generation
1(async () => {2  const browser = await puppeteer.launch({3  });4  const page = await browser.newPage();5  await page.screenshot({ path: 'example.png' });6  await browser.close();7})();Using AI Code Generation
1const puppeteer = require("puppeteer");2(async () => {3  const browser = await puppeteer.launch({4  });5  const page = await browser.newPage();6  await page.waitForTimeout(2000);7  await browser.close();8})();9{10  "scripts": {11  },12  "dependencies": {13  }14}15const puppeteer = require("puppeteer");16(async () => {17  const browser = await puppeteer.launch({18  });19  const page = await browser.newPage();20  await page.waitForTimeout(2000);21  await browser.close();22})();23const puppeteer = require("puppeteer");24(async () => {25  const browser = await puppeteer.launch({26  });27  const page = await browser.newPage();28  await page.waitForTimeout(2000);29  await browser.close();30})();31const puppeteer = require("puppeteer");32(async () => {33  const browser = await puppeteer.launch({34      "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/Using AI Code Generation
1const puppeteer = require('puppeteer');2const fs = require('fs');3const path = require('path');4const axios = require('axios');5(async () => {6    const browser = await puppeteer.launch();7    const page = await browser.newPage();8    await page.goto(url);9    await page.screenshot({path: 'google.png'});10    await browser.close();11})();12const fs = require('fs');13const path = require('path');14const axios = require('axios');15axios.get(url)16    .then(response => {17        fs.writeFileSync(path.join(__dirname, 'google.html'), response.data);18    })19    .catch(error => {20        console.log(error);21    });22const fs = require('fs');23const path = require('path');24const axios = require('axios');25axios.get(url)26    .then(response => {27        fs.writeFileSync(path.join(__dirname, 'google.html'), response.data);28    })29    .catch(error => {30        console.log(error);31    });32const fs = require('fs');33const path = require('path');34const axios = require('axios');35axios.get(url)36    .then(response => {37        fs.writeFileSync(path.join(__dirname, 'google.html'), response.data);38    })39    .catch(error => {40        console.log(error);41    });42const fs = require('fs');43const path = require('path');44const axios = require('axios');45axios.get(url)46    .then(response => {47        fs.writeFileSync(path.join(__dirname, 'google.html'), response.data);48    })49    .catch(error => {50        console.log(error);51    });52const fs = require('fs');53const path = require('path');54const axios = require('axios');55axios.get(url)56    .then(response => {57        fs.writeFileSync(path.join(__dirname, 'google.html'), response.data);58    })59    .catch(error => {60        console.log(errorUsing AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3const browser = await puppeteer.launch();4const page = await browser.newPage();5await page.screenshot({path: 'example.png'});6await browser.close();7})();8{9"scripts": {10},11"dependencies": {12}13}14{15"dependencies": {16"puppeteer": {17"requires": {18}19},20"progress": {Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
