Skip to content

Instantly share code, notes, and snippets.

@nicola
Last active August 29, 2015 14:10
Show Gist options
  • Save nicola/19280aa61bef13cc4c64 to your computer and use it in GitHub Desktop.
Save nicola/19280aa61bef13cc4c64 to your computer and use it in GitHub Desktop.
London TubeMap with Voronoi showing closures and Cycle Hire bikes
[
{
"@ID": "1",
"name": "River Street , Clerkenwell",
"latitude": "51.52916347",
"longitude": "-0.109970527",
"bikesAvailable": "14",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "2",
"name": "Phillimore Gardens, Kensington",
"latitude": "51.49960695",
"longitude": "-0.197574246",
"bikesAvailable": "6",
"emptySlots": "31",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "3",
"name": "Christopher Street, Liverpool Street",
"latitude": "51.52128377",
"longitude": "-0.084605692",
"bikesAvailable": "21",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "4",
"name": "St. Chad's Street, King's Cross",
"latitude": "51.53005939",
"longitude": "-0.120973687",
"bikesAvailable": "13",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "5",
"name": "Sedding Street, Sloane Square",
"latitude": "51.49313",
"longitude": "-0.156876",
"bikesAvailable": "24",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "6",
"name": "Broadcasting House, Marylebone",
"latitude": "51.51811784",
"longitude": "-0.144228881",
"bikesAvailable": "17",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "7",
"name": "Charlbert Street, St. John's Wood",
"latitude": "51.53430039",
"longitude": "-0.1680743",
"bikesAvailable": "2",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "8",
"name": "Lodge Road, St. John's Wood",
"latitude": "51.52834133",
"longitude": "-0.170134484",
"bikesAvailable": "10",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "9",
"name": "New Globe Walk, Bankside",
"latitude": "51.5073853",
"longitude": "-0.096440751",
"bikesAvailable": "16",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "10",
"name": "Park Street, Bankside",
"latitude": "51.50597426",
"longitude": "-0.092754157",
"bikesAvailable": "16",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "11",
"name": "Brunswick Square, Bloomsbury",
"latitude": "51.52395143",
"longitude": "-0.122502346",
"bikesAvailable": "18",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "12",
"name": "Malet Street, Bloomsbury",
"latitude": "51.52168078",
"longitude": "-0.130431727",
"bikesAvailable": "43",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "13",
"name": "Scala Street, Fitzrovia",
"latitude": "51.51991453",
"longitude": "-0.136039674",
"bikesAvailable": "18",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "14",
"name": "Belgrove Street , King's Cross",
"latitude": "51.52994371",
"longitude": "-0.123616824",
"bikesAvailable": "9",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "15",
"name": "Great Russell Street, Bloomsbury",
"latitude": "51.51772703",
"longitude": "-0.127854211",
"bikesAvailable": "12",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "17",
"name": "Hatton Wall, Holborn",
"latitude": "51.5216612",
"longitude": "-0.109006325",
"bikesAvailable": "19",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "16",
"name": "Cartwright Gardens , Bloomsbury",
"latitude": "51.52635795",
"longitude": "-0.125979294",
"bikesAvailable": "11",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "19",
"name": "Taviton Street, Bloomsbury",
"latitude": "51.52505093",
"longitude": "-0.131161087",
"bikesAvailable": "9",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "18",
"name": "Drury Lane, Covent Garden",
"latitude": "51.51477076",
"longitude": "-0.12221963",
"bikesAvailable": "13",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "21",
"name": "Hampstead Road (Cartmel), Euston",
"latitude": "51.53007835",
"longitude": "-0.13884627",
"bikesAvailable": "0",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "20",
"name": "Drummond Street , Euston",
"latitude": "51.52773634",
"longitude": "-0.135273468",
"bikesAvailable": "4",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "23",
"name": "Red Lion Square, Holborn",
"latitude": "51.51943538",
"longitude": "-0.119123345",
"bikesAvailable": "9",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "22",
"name": "Northington Street , Holborn",
"latitude": "51.5222641",
"longitude": "-0.114079481",
"bikesAvailable": "15",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "25",
"name": "Doric Way , Somers Town",
"latitude": "51.5288338",
"longitude": "-0.132250369",
"bikesAvailable": "4",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "24",
"name": "British Museum, Bloomsbury",
"latitude": "51.51908011",
"longitude": "-0.124678402",
"bikesAvailable": "30",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "27",
"name": "Bouverie Street, Temple",
"latitude": "51.51382102",
"longitude": "-0.107927706",
"bikesAvailable": "27",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "26",
"name": "Ampton Street , Clerkenwell",
"latitude": "51.52728093",
"longitude": "-0.11829517",
"bikesAvailable": "13",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "29",
"name": "Hereford Road, Bayswater",
"latitude": "51.513735",
"longitude": "-0.193487",
"bikesAvailable": "0",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "28",
"name": "Bolsover Street, Fitzrovia",
"latitude": "51.52351808",
"longitude": "-0.143613641",
"bikesAvailable": "16",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "31",
"name": "Fanshaw Street, Hoxton",
"latitude": "51.52953709",
"longitude": "-0.083353323",
"bikesAvailable": "15",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "30",
"name": "Windsor Terrace, Hoxton",
"latitude": "51.52915444",
"longitude": "-0.093421615",
"bikesAvailable": "20",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "34",
"name": "Pancras Road, King's Cross",
"latitude": "51.5341235",
"longitude": "-0.129386874",
"bikesAvailable": "4",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "32",
"name": "Leonard Circus , Shoreditch",
"latitude": "51.52469624",
"longitude": "-0.084439283",
"bikesAvailable": "37",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "33",
"name": "Altab Ali Park, Whitechapel",
"latitude": "51.51681603",
"longitude": "-0.067827542",
"bikesAvailable": "6",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "38",
"name": "Abingdon Villas, Kensington",
"latitude": "51.4973875",
"longitude": "-0.197245586",
"bikesAvailable": "0",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "39",
"name": "Shoreditch High Street, Shoreditch",
"latitude": "51.5263778",
"longitude": "-0.078130921",
"bikesAvailable": "31",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "36",
"name": "De Vere Gardens, Kensington",
"latitude": "51.50173726",
"longitude": "-0.184980612",
"bikesAvailable": "3",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "37",
"name": "Penywern Road, Earl's Court",
"latitude": "51.49159394",
"longitude": "-0.192369256",
"bikesAvailable": "9",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "42",
"name": "Wenlock Road , Hoxton",
"latitude": "51.53099181",
"longitude": "-0.093903825",
"bikesAvailable": "23",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "43",
"name": "Crawford Street, Marylebone",
"latitude": "51.52026",
"longitude": "-0.157183945",
"bikesAvailable": "16",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "40",
"name": "Commercial Street, Shoreditch",
"latitude": "51.52127071",
"longitude": "-0.0755789",
"bikesAvailable": "13",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "41",
"name": "Sun Street, Liverpool Street",
"latitude": "51.52001715",
"longitude": "-0.083911168",
"bikesAvailable": "23",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "46",
"name": "Nesham Street, Wapping",
"latitude": "51.507131",
"longitude": "-0.06691",
"bikesAvailable": "7",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "47",
"name": "Warwick Avenue Station, Maida Vale",
"latitude": "51.52334476",
"longitude": "-0.183846408",
"bikesAvailable": "4",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "51",
"name": "Finsbury Library , Finsbury",
"latitude": "51.52671796",
"longitude": "-0.104298194",
"bikesAvailable": "18",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "50",
"name": "East Road, Hoxton",
"latitude": "51.52867339",
"longitude": "-0.087459376",
"bikesAvailable": "12",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "49",
"name": "Curzon Street, Mayfair",
"latitude": "51.50706909",
"longitude": "-0.145904427",
"bikesAvailable": "6",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "48",
"name": "Godliman Street, St. Paul's",
"latitude": "51.51248445",
"longitude": "-0.099141408",
"bikesAvailable": "19",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "55",
"name": "Finsbury Circus, Liverpool Street",
"latitude": "51.51707521",
"longitude": "-0.086685542",
"bikesAvailable": "24",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "54",
"name": "Golden Lane, Barbican",
"latitude": "51.52174785",
"longitude": "-0.094475072",
"bikesAvailable": "21",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "53",
"name": "Grafton Street, Mayfair",
"latitude": "51.5099923",
"longitude": "-0.143495266",
"bikesAvailable": "17",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "52",
"name": "Roscoe Street, St. Luke's",
"latitude": "51.52295439",
"longitude": "-0.094934859",
"bikesAvailable": "18",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "59",
"name": "Rodney Street, Angel",
"latitude": "51.53176825",
"longitude": "-0.114329032",
"bikesAvailable": "13",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "58",
"name": "New Inn Yard, Shoreditch",
"latitude": "51.52452699",
"longitude": "-0.079248081",
"bikesAvailable": "17",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "57",
"name": "Guilford Street , Bloomsbury",
"latitude": "51.52334672",
"longitude": "-0.120202614",
"bikesAvailable": "27",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "56",
"name": "Paddington Street, Marylebone",
"latitude": "51.52058381",
"longitude": "-0.154701411",
"bikesAvailable": "7",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "63",
"name": "Murray Grove , Hoxton",
"latitude": "51.53089041",
"longitude": "-0.089782579",
"bikesAvailable": "16",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "62",
"name": "Cotton Garden Estate, Kennington",
"latitude": "51.4907579",
"longitude": "-0.106323685",
"bikesAvailable": "6",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "61",
"name": "Great Dover Street, Borough",
"latitude": "51.49738251",
"longitude": "-0.089446947",
"bikesAvailable": "19",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "60",
"name": "Lisson Grove, St. John's Wood",
"latitude": "51.52644828",
"longitude": "-0.172190727",
"bikesAvailable": "8",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "68",
"name": "Theobalds Road , Holborn",
"latitude": "51.52059681",
"longitude": "-0.116688468",
"bikesAvailable": "19",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "69",
"name": "Euston Road, Euston",
"latitude": "51.5262363",
"longitude": "-0.134407652",
"bikesAvailable": "11",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "70",
"name": "Calshot Street , King's Cross",
"latitude": "51.53136059",
"longitude": "-0.117069978",
"bikesAvailable": "18",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "71",
"name": "Newgate Street , St. Paul's",
"latitude": "51.5154186",
"longitude": "-0.098850915",
"bikesAvailable": "16",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "64",
"name": "William IV Street, Strand",
"latitude": "51.50946212",
"longitude": "-0.124749274",
"bikesAvailable": "15",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "65",
"name": "Gower Place , Euston",
"latitude": "51.52522753",
"longitude": "-0.13518856",
"bikesAvailable": "2",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "66",
"name": "Holborn Circus, Holborn",
"latitude": "51.51795029",
"longitude": "-0.108657431",
"bikesAvailable": "19",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "67",
"name": "Hatton Garden, Holborn",
"latitude": "51.51882555",
"longitude": "-0.108028472",
"bikesAvailable": "23",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "76",
"name": "Longford Street, Regent's Park",
"latitude": "51.52559505",
"longitude": "-0.144083893",
"bikesAvailable": "8",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "77",
"name": "Russell Square Station, Bloomsbury",
"latitude": "51.52341837",
"longitude": "-0.124121774",
"bikesAvailable": "21",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "78",
"name": "Sadlers Sports Centre, Finsbury",
"latitude": "51.52486887",
"longitude": "-0.099489485",
"bikesAvailable": "11",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "72",
"name": "Farringdon Lane, Clerkenwell",
"latitude": "51.52352001",
"longitude": "-0.108340165",
"bikesAvailable": "13",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "73",
"name": "Old Street Station, St. Luke's",
"latitude": "51.52572618",
"longitude": "-0.088486188",
"bikesAvailable": "30",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "74",
"name": "Vauxhall Cross, Vauxhall",
"latitude": "51.48591714",
"longitude": "-0.124469948",
"bikesAvailable": "4",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "75",
"name": "Torrens Street, Angel",
"latitude": "51.53219984",
"longitude": "-0.105480698",
"bikesAvailable": "10",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "85",
"name": "Tanner Street, Bermondsey",
"latitude": "51.50064702",
"longitude": "-0.078600401",
"bikesAvailable": "3",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "84",
"name": "Breams Buildings, Holborn",
"latitude": "51.51593725",
"longitude": "-0.111778348",
"bikesAvailable": "23",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "87",
"name": "Devonshire Square, Liverpool Street",
"latitude": "51.51646835",
"longitude": "-0.079684557",
"bikesAvailable": "14",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "86",
"name": "Sancroft Street, Vauxhall",
"latitude": "51.48947903",
"longitude": "-0.115156562",
"bikesAvailable": "6",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "81",
"name": "Great Titchfield Street, Fitzrovia",
"latitude": "51.52025302",
"longitude": "-0.141327271",
"bikesAvailable": "19",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "80",
"name": "Webber Street , Southwark",
"latitude": "51.50069361",
"longitude": "-0.102091246",
"bikesAvailable": "3",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "83",
"name": "Panton Street, West End",
"latitude": "51.50963938",
"longitude": "-0.131510949",
"bikesAvailable": "19",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "82",
"name": "Chancery Lane, Holborn",
"latitude": "51.514274",
"longitude": "-0.111257",
"bikesAvailable": "13",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "93",
"name": "Cloudesley Road, Angel",
"latitude": "51.53440868",
"longitude": "-0.109025404",
"bikesAvailable": "19",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "92",
"name": "Borough Road, Elephant & Castle",
"latitude": "51.49889832",
"longitude": "-0.100440521",
"bikesAvailable": "19",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "95",
"name": "Aldersgate Street, Barbican",
"latitude": "51.5208417",
"longitude": "-0.097340162",
"bikesAvailable": "12",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "94",
"name": "Bricklayers Arms, Borough",
"latitude": "51.49506109",
"longitude": "-0.085814489",
"bikesAvailable": "2",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "89",
"name": "Tavistock Place, Bloomsbury",
"latitude": "51.5262503",
"longitude": "-0.123509611",
"bikesAvailable": "1",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "88",
"name": "Bayley Street , Bloomsbury",
"latitude": "51.51858757",
"longitude": "-0.132053392",
"bikesAvailable": "13",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "91",
"name": "Walnut Tree Walk, Vauxhall",
"latitude": "51.49368637",
"longitude": "-0.111014912",
"bikesAvailable": "9",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "90",
"name": "Harrington Square, Camden Town",
"latitude": "51.53301907",
"longitude": "-0.139174593",
"bikesAvailable": "17",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "102",
"name": "Jewry Street, Aldgate",
"latitude": "51.51340693",
"longitude": "-0.076793375",
"bikesAvailable": "10",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "103",
"name": "Vicarage Gate, Kensington",
"latitude": "51.50472376",
"longitude": "-0.192538767",
"bikesAvailable": "12",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "100",
"name": "Albert Embankment, Vauxhall",
"latitude": "51.49043573",
"longitude": "-0.122806861",
"bikesAvailable": "14",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "101",
"name": "Queen Street, Bank",
"latitude": "51.51155322",
"longitude": "-0.0929401",
"bikesAvailable": "17",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "98",
"name": "Hampstead Road, Euston",
"latitude": "51.52554222",
"longitude": "-0.138231303",
"bikesAvailable": "18",
"emptySlots": "35",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "99",
"name": "Old Quebec Street, Marylebone",
"latitude": "51.51457763",
"longitude": "-0.158264483",
"bikesAvailable": "13",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "96",
"name": "Falkirk Street, Hoxton",
"latitude": "51.53095071",
"longitude": "-0.078505384",
"bikesAvailable": "14",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "97",
"name": "Gloucester Road (North), Kensington",
"latitude": "51.49792478",
"longitude": "-0.183834706",
"bikesAvailable": "15",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "110",
"name": "Wellington Road, St. John's Wood",
"latitude": "51.53304322",
"longitude": "-0.172528678",
"bikesAvailable": "12",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "111",
"name": "Park Lane , Hyde Park",
"latitude": "51.5100172",
"longitude": "-0.157275636",
"bikesAvailable": "22",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "108",
"name": "Abbey Orchard Street, Westminster",
"latitude": "51.49812559",
"longitude": "-0.132102166",
"bikesAvailable": "18",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "109",
"name": "Soho Square , Soho",
"latitude": "51.51563144",
"longitude": "-0.132328837",
"bikesAvailable": "28",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "106",
"name": "Woodstock Street, Mayfair",
"latitude": "51.51410514",
"longitude": "-0.147301667",
"bikesAvailable": "18",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "107",
"name": "Finsbury Leisure Centre, St. Luke's",
"latitude": "51.52600832",
"longitude": "-0.096317627",
"bikesAvailable": "9",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "104",
"name": "Crosswall, Tower",
"latitude": "51.51159481",
"longitude": "-0.077121322",
"bikesAvailable": "23",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "105",
"name": "Westbourne Grove, Bayswater",
"latitude": "51.51552971",
"longitude": "-0.190240716",
"bikesAvailable": "2",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "119",
"name": "Bath Street, St. Luke's",
"latitude": "51.52589324",
"longitude": "-0.090847761",
"bikesAvailable": "7",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "118",
"name": "Rochester Row, Westminster",
"latitude": "51.49582705",
"longitude": "-0.13547809",
"bikesAvailable": "3",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "117",
"name": "Lollard Street, Vauxhall",
"latitude": "51.49288067",
"longitude": "-0.114934001",
"bikesAvailable": "9",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "116",
"name": "Little Argyll Street, West End",
"latitude": "51.51449962",
"longitude": "-0.141423695",
"bikesAvailable": "21",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "115",
"name": "Braham Street, Aldgate",
"latitude": "51.51423368",
"longitude": "-0.073537654",
"bikesAvailable": "26",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "114",
"name": "\n Park Road (Baker Street), Regent's Park\n ",
"latitude": "51.52451738",
"longitude": "-0.158963647",
"bikesAvailable": "10",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "113",
"name": "\n Gloucester Road (Central), South Kensington\n ",
"latitude": "51.49646288",
"longitude": "-0.183289032",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "112",
"name": "Stonecutter Street, Holborn",
"latitude": "51.51580998",
"longitude": "-0.105270275",
"bikesAvailable": "38",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "127",
"name": "Wood Street, Guildhall",
"latitude": "51.51700801",
"longitude": "-0.09388536",
"bikesAvailable": "9",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "126",
"name": "Museum of London, Barbican",
"latitude": "51.51782144",
"longitude": "-0.096496865",
"bikesAvailable": "43",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "125",
"name": "Borough High Street, The Borough",
"latitude": "51.50069491",
"longitude": "-0.094524319",
"bikesAvailable": "20",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "124",
"name": "Eaton Square, Belgravia",
"latitude": "51.49654462",
"longitude": "-0.150905245",
"bikesAvailable": "16",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "123",
"name": "St. John Street, Finsbury",
"latitude": "51.52836014",
"longitude": "-0.104724625",
"bikesAvailable": "17",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "122",
"name": "Norton Folgate, Liverpool Street",
"latitude": "51.52111369",
"longitude": "-0.078869751",
"bikesAvailable": "22",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "121",
"name": "Baker Street, Marylebone",
"latitude": "51.51891348",
"longitude": "-0.156166631",
"bikesAvailable": "6",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "120",
"name": "The Guildhall, Guildhall",
"latitude": "51.51573534",
"longitude": "-0.093080779",
"bikesAvailable": "16",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "137",
"name": "Bourne Street, Belgravia",
"latitude": "51.49087475",
"longitude": "-0.153319609",
"bikesAvailable": "12",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "136",
"name": "Queen Victoria Street, St. Paul's",
"latitude": "51.51196176",
"longitude": "-0.097441687",
"bikesAvailable": "28",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "139",
"name": "Lambeth Road, Vauxhall",
"latitude": "51.49488108",
"longitude": "-0.117974901",
"bikesAvailable": "12",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "138",
"name": "Green Street, Mayfair",
"latitude": "51.51227622",
"longitude": "-0.157436972",
"bikesAvailable": "11",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "141",
"name": "Chapel Place, Marylebone",
"latitude": "51.51530805",
"longitude": "-0.147203711",
"bikesAvailable": "26",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "140",
"name": "Finsbury Square , Moorgate",
"latitude": "51.52096262",
"longitude": "-0.085634242",
"bikesAvailable": "26",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "143",
"name": "Pont Street, Knightsbridge",
"latitude": "51.4968865",
"longitude": "-0.161203828",
"bikesAvailable": "14",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "142",
"name": "West Cromwell Road, Earl's Court",
"latitude": "51.49372451",
"longitude": "-0.198286569",
"bikesAvailable": "6",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "129",
"name": "Golden Square, Soho",
"latitude": "51.5118973",
"longitude": "-0.137043852",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "128",
"name": "Emperor's Gate, South Kensington",
"latitude": "51.49536226",
"longitude": "-0.185296516",
"bikesAvailable": "10",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "131",
"name": "Eversholt Street , Camden Town",
"latitude": "51.53300545",
"longitude": "-0.136792671",
"bikesAvailable": "12",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "130",
"name": "Tower Gardens , Tower",
"latitude": "51.50950627",
"longitude": "-0.075459482",
"bikesAvailable": "19",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "133",
"name": "Derry Street, Kensington",
"latitude": "51.50136494",
"longitude": "-0.191462381",
"bikesAvailable": "12",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "132",
"name": "Bethnal Green Road, Shoreditch",
"latitude": "51.52364804",
"longitude": "-0.074754872",
"bikesAvailable": "31",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "135",
"name": "Clerkenwell Green, Clerkenwell",
"latitude": "51.52326004",
"longitude": "-0.104708922",
"bikesAvailable": "9",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "134",
"name": "Wapping High Street, Wapping",
"latitude": "51.504904",
"longitude": "-0.06797",
"bikesAvailable": "10",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "152",
"name": "Hampton Street, Walworth",
"latitude": "51.49217002",
"longitude": "-0.101536865",
"bikesAvailable": "9",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "153",
"name": "Bayswater Road, Hyde Park",
"latitude": "51.51183419",
"longitude": "-0.174292825",
"bikesAvailable": "8",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "154",
"name": "Waterloo Station 3, Waterloo",
"latitude": "51.50379168",
"longitude": "-0.11282408",
"bikesAvailable": "11",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "155",
"name": "Lexham Gardens, Kensington",
"latitude": "51.49586666",
"longitude": "-0.191933711",
"bikesAvailable": "4",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "156",
"name": "New Kent Road, Borough",
"latitude": "51.49443626",
"longitude": "-0.092921165",
"bikesAvailable": "16",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "157",
"name": "Wright's Lane, Kensington",
"latitude": "51.50039792",
"longitude": "-0.193068385",
"bikesAvailable": "31",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "158",
"name": "Trebovir Road, Earl's Court",
"latitude": "51.49085368",
"longitude": "-0.196170309",
"bikesAvailable": "1",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "159",
"name": "Great Marlborough Street, Soho",
"latitude": "51.51461995",
"longitude": "-0.137841333",
"bikesAvailable": "35",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "144",
"name": "Kennington Cross, Kennington",
"latitude": "51.48894022",
"longitude": "-0.111435796",
"bikesAvailable": "4",
"emptySlots": "40",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "145",
"name": "Ilchester Place, Kensington",
"latitude": "51.50074359",
"longitude": "-0.202759212",
"bikesAvailable": "5",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "146",
"name": "Vauxhall Bridge , Pimlico",
"latitude": "51.48836528",
"longitude": "-0.129361842",
"bikesAvailable": "11",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "147",
"name": "Portugal Street, Holborn",
"latitude": "51.51494305",
"longitude": "-0.11614642",
"bikesAvailable": "8",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "148",
"name": "Tachbrook Street, Victoria",
"latitude": "51.49211134",
"longitude": "-0.138364847",
"bikesAvailable": "13",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "149",
"name": "Kennington Road Post Office, Oval",
"latitude": "51.48478899",
"longitude": "-0.110683213",
"bikesAvailable": "2",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "150",
"name": "Holy Trinity Brompton, Knightsbridge",
"latitude": "51.49705603",
"longitude": "-0.168917077",
"bikesAvailable": "10",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "151",
"name": "Chepstow Villas, Notting Hill",
"latitude": "51.51213691",
"longitude": "-0.201554966",
"bikesAvailable": "2",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "171",
"name": "Collingham Gardens, Earl's Court",
"latitude": "51.4916156",
"longitude": "-0.186753859",
"bikesAvailable": "4",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "170",
"name": "Hardwick Street, Clerkenwell",
"latitude": "51.52784273",
"longitude": "-0.108068155",
"bikesAvailable": "14",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "169",
"name": "Porchester Place, Paddington",
"latitude": "51.51474612",
"longitude": "-0.165164288",
"bikesAvailable": "3",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "168",
"name": "Argyll Road, Kensington",
"latitude": "51.50040123",
"longitude": "-0.195455928",
"bikesAvailable": "15",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "175",
"name": "Appold Street, Liverpool Street",
"latitude": "51.52174384",
"longitude": "-0.0811189",
"bikesAvailable": "22",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "174",
"name": "Strand, Strand",
"latitude": "51.512529",
"longitude": "-0.115163",
"bikesAvailable": "34",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "173",
"name": "Waterloo Roundabout, Waterloo ",
"latitude": "51.50486",
"longitude": "-0.113001",
"bikesAvailable": "2",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "172",
"name": "Sumner Place, South Kensington",
"latitude": "51.49121192",
"longitude": "-0.173715911",
"bikesAvailable": "16",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "163",
"name": "Sloane Avenue, Knightsbridge",
"latitude": "51.4931848",
"longitude": "-0.167894973",
"bikesAvailable": "11",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "162",
"name": "Southampton Place, Holborn",
"latitude": "51.51760685",
"longitude": "-0.121328408",
"bikesAvailable": "19",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "161",
"name": "Guildhouse Street, Victoria",
"latitude": "51.49234577",
"longitude": "-0.141334487",
"bikesAvailable": "4",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "160",
"name": "Waterloo Place, St. James's",
"latitude": "51.50663341",
"longitude": "-0.131773845",
"bikesAvailable": "13",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "167",
"name": "Eccleston Place, Victoria",
"latitude": "51.49395092",
"longitude": "-0.147624377",
"bikesAvailable": "9",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "166",
"name": "Seville Street, Knightsbridge",
"latitude": "51.50185512",
"longitude": "-0.159237081",
"bikesAvailable": "23",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "165",
"name": "Orsett Terrace, Bayswater",
"latitude": "51.517932",
"longitude": "-0.183716959",
"bikesAvailable": "0",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "164",
"name": "Cleveland Gardens, Bayswater",
"latitude": "51.515607",
"longitude": "-0.183118788",
"bikesAvailable": "0",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "186",
"name": "South Wharf Road, Paddington",
"latitude": "51.51733558",
"longitude": "-0.175810943",
"bikesAvailable": "4",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "187",
"name": "\n Queen's Gate (South), South Kensington\n ",
"latitude": "51.49247977",
"longitude": "-0.178433004",
"bikesAvailable": "6",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "184",
"name": "Portland Place, Marylebone",
"latitude": "51.52071513",
"longitude": "-0.14521173",
"bikesAvailable": "32",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "185",
"name": "Alderney Street, Pimlico",
"latitude": "51.48805753",
"longitude": "-0.140741432",
"bikesAvailable": "5",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "190",
"name": "Rampayne Street, Pimlico",
"latitude": "51.48997562",
"longitude": "-0.132845681",
"bikesAvailable": "14",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "191",
"name": "Hyde Park Corner, Hyde Park",
"latitude": "51.50311799",
"longitude": "-0.153520935",
"bikesAvailable": "10",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "188",
"name": "Nutford Place, Marylebone",
"latitude": "51.5165179",
"longitude": "-0.164393768",
"bikesAvailable": "12",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "189",
"name": "Claremont Square, Angel",
"latitude": "51.53166681",
"longitude": "-0.109914711",
"bikesAvailable": "8",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "178",
"name": "Warwick Square, Pimlico",
"latitude": "51.48985626",
"longitude": "-0.141923621",
"bikesAvailable": "11",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "176",
"name": "Gloucester Terrace, Bayswater",
"latitude": "51.51791921",
"longitude": "-0.188098863",
"bikesAvailable": "1",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "177",
"name": "Ashley Place, Victoria",
"latitude": "51.49616092",
"longitude": "-0.140947636",
"bikesAvailable": "11",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "182",
"name": "Bell Street , Marylebone",
"latitude": "51.52202903",
"longitude": "-0.165842551",
"bikesAvailable": "2",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "180",
"name": "North Audley Street, Mayfair",
"latitude": "51.5129118",
"longitude": "-0.153645496",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "181",
"name": "Belgrave Square, Belgravia",
"latitude": "51.49941247",
"longitude": "-0.152317537",
"bikesAvailable": "20",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "205",
"name": "New Road 2, Whitechapel",
"latitude": "51.518144",
"longitude": "-0.06275",
"bikesAvailable": "17",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "204",
"name": "Margery Street, Clerkenwell",
"latitude": "51.52659961",
"longitude": "-0.112432615",
"bikesAvailable": "13",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "207",
"name": "Grosvenor Crescent, Belgravia",
"latitude": "51.50135267",
"longitude": "-0.153194766",
"bikesAvailable": "18",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "206",
"name": "New Road 1 , Whitechapel",
"latitude": "51.518154",
"longitude": "-0.062697",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "201",
"name": "Dorset Square, Marylebone",
"latitude": "51.5225965",
"longitude": "-0.161113413",
"bikesAvailable": "4",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "200",
"name": "LMU Commercial Road, Whitechapel",
"latitude": "51.51492456",
"longitude": "-0.066078037",
"bikesAvailable": "6",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "203",
"name": "West Smithfield Rotunda, Farringdon",
"latitude": "51.51821864",
"longitude": "-0.100791005",
"bikesAvailable": "7",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "202",
"name": "Leman Street, Aldgate",
"latitude": "51.51236389",
"longitude": "-0.06954201",
"bikesAvailable": "13",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "197",
"name": "Stamford Street, South Bank",
"latitude": "51.50556905",
"longitude": "-0.111606696",
"bikesAvailable": "11",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "196",
"name": "Union Street, The Borough",
"latitude": "51.50368837",
"longitude": "-0.098497684",
"bikesAvailable": "16",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "199",
"name": "Great Tower Street, Monument",
"latitude": "51.51048489",
"longitude": "-0.082989638",
"bikesAvailable": "21",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "193",
"name": "Bankside Mix, Bankside",
"latitude": "51.50581776",
"longitude": "-0.100186337",
"bikesAvailable": "57",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "192",
"name": "Wardour Street, Soho",
"latitude": "51.51251523",
"longitude": "-0.133201961",
"bikesAvailable": "7",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "195",
"name": "Milroy Walk, South Bank",
"latitude": "51.50724437",
"longitude": "-0.106237501",
"bikesAvailable": "18",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "194",
"name": "Hop Exchange, The Borough",
"latitude": "51.50462759",
"longitude": "-0.091773776",
"bikesAvailable": "18",
"emptySlots": "33",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "220",
"name": "Chelsea Green, Chelsea",
"latitude": "51.49066456",
"longitude": "-0.166485083",
"bikesAvailable": "21",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "221",
"name": "Horseferry Road, Westminster",
"latitude": "51.49481649",
"longitude": "-0.13045856",
"bikesAvailable": "12",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "222",
"name": "Knightsbridge, Hyde Park",
"latitude": "51.50275704",
"longitude": "-0.155349725",
"bikesAvailable": "31",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "223",
"name": "Rodney Road , Walworth",
"latitude": "51.49148474",
"longitude": "-0.090220911",
"bikesAvailable": "5",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "216",
"name": "Old Brompton Road, South Kensington",
"latitude": "51.49094565",
"longitude": "-0.181190899",
"bikesAvailable": "11",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "217",
"name": "Wormwood Street, Liverpool Street",
"latitude": "51.51615461",
"longitude": "-0.082422399",
"bikesAvailable": "4",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "218",
"name": "St. Luke's Church, Chelsea",
"latitude": "51.48971651",
"longitude": "-0.170194408",
"bikesAvailable": "18",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "219",
"name": "Bramham Gardens, Earl's Court",
"latitude": "51.49016361",
"longitude": "-0.19039362",
"bikesAvailable": "7",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "212",
"name": "Campden Hill Road, Notting Hill",
"latitude": "51.50658458",
"longitude": "-0.199004026",
"bikesAvailable": "0",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "213",
"name": "Wellington Arch, Hyde Park",
"latitude": "51.50274025",
"longitude": "-0.149569201",
"bikesAvailable": "15",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "214",
"name": "Endsleigh Gardens, Euston",
"latitude": "51.52683806",
"longitude": "-0.130504336",
"bikesAvailable": "15",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "215",
"name": "Moorfields, Moorgate",
"latitude": "51.51906932",
"longitude": "-0.088285377",
"bikesAvailable": "47",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "208",
"name": "Mallory Street, Marylebone",
"latitude": "51.52505151",
"longitude": "-0.166304359",
"bikesAvailable": "0",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "209",
"name": "Denyer Street, Knightsbridge",
"latitude": "51.49358391",
"longitude": "-0.165101392",
"bikesAvailable": "14",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "210",
"name": "Hinde Street, Marylebone",
"latitude": "51.51681444",
"longitude": "-0.151926305",
"bikesAvailable": "20",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "211",
"name": "Cadogan Place, Knightsbridge",
"latitude": "51.49464523",
"longitude": "-0.158105512",
"bikesAvailable": "32",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "239",
"name": "Warren Street Station, Euston",
"latitude": "51.52443845",
"longitude": "-0.138019439",
"bikesAvailable": "12",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "238",
"name": "Frampton Street, Paddington",
"latitude": "51.5233534",
"longitude": "-0.175116099",
"bikesAvailable": "0",
"emptySlots": "32",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "237",
"name": "Vaughan Way, Wapping",
"latitude": "51.5084448",
"longitude": "-0.067176443",
"bikesAvailable": "29",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "236",
"name": "Fashion Street, Whitechapel",
"latitude": "51.51838043",
"longitude": "-0.073438925",
"bikesAvailable": "29",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "235",
"name": "Kennington Road , Vauxhall",
"latitude": "51.49571828",
"longitude": "-0.110889274",
"bikesAvailable": "10",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "234",
"name": "Liverpool Road (N1 Centre), Angel",
"latitude": "51.53450449",
"longitude": "-0.106992706",
"bikesAvailable": "5",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "233",
"name": "Pall Mall East, West End",
"latitude": "51.50777049",
"longitude": "-0.130699733",
"bikesAvailable": "16",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "232",
"name": "Carey Street, Holborn",
"latitude": "51.51501025",
"longitude": "-0.112753217",
"bikesAvailable": "10",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "231",
"name": "\n Queen's Gate (Central), South Kensington\n ",
"latitude": "51.49396755",
"longitude": "-0.17873226",
"bikesAvailable": "9",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "230",
"name": "Poured Lines, Bankside",
"latitude": "51.50669284",
"longitude": "-0.103137426",
"bikesAvailable": "31",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "229",
"name": "Whitehall Place, Strand",
"latitude": "51.50654321",
"longitude": "-0.123179697",
"bikesAvailable": "19",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "228",
"name": "St. James's Square, St. James's",
"latitude": "51.50742485",
"longitude": "-0.134621209",
"bikesAvailable": "38",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "227",
"name": "Great Percy Street, Clerkenwell",
"latitude": "51.52891573",
"longitude": "-0.115480888",
"bikesAvailable": "19",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "226",
"name": "Charles II Street, West End",
"latitude": "51.50844614",
"longitude": "-0.131961389",
"bikesAvailable": "24",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "225",
"name": "Notting Hill Gate Station, Notting Hill",
"latitude": "51.50935342",
"longitude": "-0.196422",
"bikesAvailable": "1",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "224",
"name": "Whiteley's, Bayswater",
"latitude": "51.51476963",
"longitude": "-0.188129731",
"bikesAvailable": "0",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "254",
"name": "Chadwell Street, Angel",
"latitude": "51.53051587",
"longitude": "-0.106408455",
"bikesAvailable": "11",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "255",
"name": "Clifton Road, Maida Vale",
"latitude": "51.52557531",
"longitude": "-0.179592915",
"bikesAvailable": "6",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "252",
"name": "Jubilee Gardens, South Bank",
"latitude": "51.5046364",
"longitude": "-0.116542278",
"bikesAvailable": "7",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "253",
"name": "Shoreditch Park, Hoxton",
"latitude": "51.53404294",
"longitude": "-0.086379717",
"bikesAvailable": "18",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "250",
"name": "Royal Avenue 1, Chelsea",
"latitude": "51.489932",
"longitude": "-0.162727",
"bikesAvailable": "3",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "251",
"name": "Brushfield Street, Liverpool Street",
"latitude": "51.518908",
"longitude": "-0.079249",
"bikesAvailable": "30",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "248",
"name": "Triangle Car Park, Hyde Park",
"latitude": "51.50645179",
"longitude": "-0.170279555",
"bikesAvailable": "8",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "249",
"name": "Harper Road, Borough",
"latitude": "51.49859784",
"longitude": "-0.096191134",
"bikesAvailable": "15",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "246",
"name": "Berry Street, Clerkenwell",
"latitude": "51.52285301",
"longitude": "-0.099994052",
"bikesAvailable": "32",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "247",
"name": "\n St. John's Wood Church, Regent's Park\n ",
"latitude": "51.530052",
"longitude": "-0.168314",
"bikesAvailable": "26",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "244",
"name": "Earnshaw Street , Covent Garden",
"latitude": "51.51611887",
"longitude": "-0.128585022",
"bikesAvailable": "6",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "245",
"name": "Grosvenor Road, Pimlico",
"latitude": "51.4853572",
"longitude": "-0.142207481",
"bikesAvailable": "3",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "242",
"name": "Beaumont Street, Marylebone",
"latitude": "51.52200801",
"longitude": "-0.151359288",
"bikesAvailable": "13",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "243",
"name": "Gloucester Street, Pimlico",
"latitude": "51.49096258",
"longitude": "-0.139625122",
"bikesAvailable": "7",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "240",
"name": "Colombo Street, Southwark",
"latitude": "51.50545935",
"longitude": "-0.10569204",
"bikesAvailable": "13",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "275",
"name": "Barbican Centre, Barbican",
"latitude": "51.52004497",
"longitude": "-0.092176447",
"bikesAvailable": "13",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "274",
"name": "Warwick Road, Olympia",
"latitude": "51.49671237",
"longitude": "-0.20528437",
"bikesAvailable": "9",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "273",
"name": "Belvedere Road, South Bank",
"latitude": "51.50613324",
"longitude": "-0.114686385",
"bikesAvailable": "31",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "272",
"name": "Baylis Road, Waterloo",
"latitude": "51.50144456",
"longitude": "-0.110699309",
"bikesAvailable": "8",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "279",
"name": "North Wharf Road, Paddington",
"latitude": "51.51862243",
"longitude": "-0.176645823",
"bikesAvailable": "17",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "278",
"name": "Tooley Street, Bermondsey",
"latitude": "51.5034938",
"longitude": "-0.07962099",
"bikesAvailable": "4",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "277",
"name": "Kensington Church Street, Kensington",
"latitude": "51.50315739",
"longitude": "-0.191496313",
"bikesAvailable": "2",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "276",
"name": "Lower Thames Street, Monument",
"latitude": "51.50930161",
"longitude": "-0.084985356",
"bikesAvailable": "20",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "283",
"name": "Kingsway, Covent Garden",
"latitude": "51.51440928",
"longitude": "-0.118478757",
"bikesAvailable": "11",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "282",
"name": "Royal London Hospital, Whitechapel",
"latitude": "51.51906446",
"longitude": "-0.059642081",
"bikesAvailable": "22",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "281",
"name": "Smith Square, Westminster",
"latitude": "51.49580589",
"longitude": "-0.127575233",
"bikesAvailable": "8",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "280",
"name": "Royal Avenue 2, Chelsea",
"latitude": "51.490083",
"longitude": "-0.162418",
"bikesAvailable": "8",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "287",
"name": "Bedford Way, Bloomsbury",
"latitude": "51.52367314",
"longitude": "-0.128377673",
"bikesAvailable": "9",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "286",
"name": "\n St. John's Wood Road, St. John's Wood\n ",
"latitude": "51.5272947",
"longitude": "-0.174653609",
"bikesAvailable": "0",
"emptySlots": "34",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "284",
"name": "Lambeth North Station, Waterloo",
"latitude": "51.49914063",
"longitude": "-0.112031483",
"bikesAvailable": "3",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "258",
"name": "Kensington Gore, Knightsbridge",
"latitude": "51.50143293",
"longitude": "-0.178656971",
"bikesAvailable": "20",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "259",
"name": "Embankment (Horse Guards), Westminster",
"latitude": "51.50494561",
"longitude": "-0.123247648",
"bikesAvailable": "16",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "256",
"name": "Houghton Street, Strand",
"latitude": "51.51362054",
"longitude": "-0.116764211",
"bikesAvailable": "12",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "257",
"name": "Westminster University, Marylebone",
"latitude": "51.52248185",
"longitude": "-0.154907218",
"bikesAvailable": "2",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "262",
"name": "\n LSBU (Borough Road), Elephant & Castle\n ",
"latitude": "51.49874469",
"longitude": "-0.103132904",
"bikesAvailable": "18",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "263",
"name": "St. Mary Axe, Aldgate",
"latitude": "51.51422502",
"longitude": "-0.080660083",
"bikesAvailable": "9",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "260",
"name": "Broadwick Street, Soho",
"latitude": "51.5136846",
"longitude": "-0.135580879",
"bikesAvailable": "17",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "261",
"name": "Princes Square, Bayswater",
"latitude": "51.5134891",
"longitude": "-0.191351186",
"bikesAvailable": "1",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "266",
"name": "Queen's Gate (North), Kensington",
"latitude": "51.50102668",
"longitude": "-0.180246101",
"bikesAvailable": "15",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "267",
"name": "Regency Street, Westminster",
"latitude": "51.49206037",
"longitude": "-0.132224622",
"bikesAvailable": "11",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "264",
"name": "Tysoe Street, Clerkenwell",
"latitude": "51.52644342",
"longitude": "-0.109256828",
"bikesAvailable": "9",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "265",
"name": "Southwick Street, Paddington",
"latitude": "51.51595344",
"longitude": "-0.169249375",
"bikesAvailable": "12",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "270",
"name": "Kennington Lane Rail Bridge, Vauxhall",
"latitude": "51.4863434",
"longitude": "-0.122492418",
"bikesAvailable": "22",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "271",
"name": "London Zoo, Regents Park",
"latitude": "51.53583617",
"longitude": "-0.156285395",
"bikesAvailable": "14",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "268",
"name": "Belgrave Road, Victoria",
"latitude": "51.49320445",
"longitude": "-0.144132875",
"bikesAvailable": "9",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "269",
"name": "Empire Square, The Borough",
"latitude": "51.50082346",
"longitude": "-0.089740764",
"bikesAvailable": "19",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "305",
"name": "Kennington Lane Tesco, Vauxhall",
"latitude": "51.48677988",
"longitude": "-0.115853961",
"bikesAvailable": "13",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "304",
"name": "Cumberland Gate, Hyde Park",
"latitude": "51.51211869",
"longitude": "-0.16209757",
"bikesAvailable": "12",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "307",
"name": "Black Lion Gate, Kensington Gardens",
"latitude": "51.50990837",
"longitude": "-0.187842717",
"bikesAvailable": "12",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "306",
"name": "Rathbone Street, Fitzrovia ",
"latitude": "51.51816295",
"longitude": "-0.135025698",
"bikesAvailable": "7",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "309",
"name": "Embankment (Savoy), Strand",
"latitude": "51.50963123",
"longitude": "-0.119047563",
"bikesAvailable": "34",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "308",
"name": "Long Lane , Bermondsey",
"latitude": "51.49907558",
"longitude": "-0.085666316",
"bikesAvailable": "7",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "311",
"name": "Foley Street, Fitzrovia",
"latitude": "51.51918144",
"longitude": "-0.140485596",
"bikesAvailable": "23",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "310",
"name": "Black Prince Road, Vauxhall",
"latitude": "51.4908679",
"longitude": "-0.116911864",
"bikesAvailable": "11",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "313",
"name": "Wells Street, Fitzrovia ",
"latitude": "51.51734403",
"longitude": "-0.138072691",
"bikesAvailable": "33",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "312",
"name": "Grove End Road, St. John's Wood",
"latitude": "51.53088935",
"longitude": "-0.176770502",
"bikesAvailable": "1",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "315",
"name": "The Tennis Courts, Regent's Park",
"latitude": "51.52536703",
"longitude": "-0.153463612",
"bikesAvailable": "13",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "314",
"name": "Tyers Gate, Bermondsey",
"latitude": "51.50088934",
"longitude": "-0.083159352",
"bikesAvailable": "24",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "317",
"name": "Dickens Square, Borough",
"latitude": "51.49679128",
"longitude": "-0.093913472",
"bikesAvailable": "16",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "316",
"name": "Cardinal Place, Victoria",
"latitude": "51.49768448",
"longitude": "-0.141943703",
"bikesAvailable": "8",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "319",
"name": "Baldwin Street, St. Luke's",
"latitude": "51.52702563",
"longitude": "-0.088542771",
"bikesAvailable": "17",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "318",
"name": "Sackville Street, Mayfair",
"latitude": "51.51004801",
"longitude": "-0.138846453",
"bikesAvailable": "11",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "288",
"name": "Elizabeth Bridge, Victoria",
"latitude": "51.49236962",
"longitude": "-0.147478734",
"bikesAvailable": "19",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "289",
"name": "South Audley Street, Mayfair",
"latitude": "51.50923022",
"longitude": "-0.151296092",
"bikesAvailable": "11",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "290",
"name": "Winsland Street, Paddington",
"latitude": "51.51678023",
"longitude": "-0.175488803",
"bikesAvailable": "5",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "291",
"name": "Claverton Street, Pimlico",
"latitude": "51.48483991",
"longitude": "-0.138089062",
"bikesAvailable": "5",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "292",
"name": "Montpelier Street, Knightsbridge",
"latitude": "51.49888404",
"longitude": "-0.165471605",
"bikesAvailable": "6",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "293",
"name": "Kensington Olympia Station, Olympia",
"latitude": "51.49815779",
"longitude": "-0.209494128",
"bikesAvailable": "0",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "294",
"name": "St. George's Square, Pimlico",
"latitude": "51.488226",
"longitude": "-0.135635511",
"bikesAvailable": "7",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "295",
"name": "Swan Street, The Borough",
"latitude": "51.50029631",
"longitude": "-0.092762704",
"bikesAvailable": "19",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "296",
"name": "Knaresborough Place, Earl's Court",
"latitude": "51.49363156",
"longitude": "-0.190603326",
"bikesAvailable": "6",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "297",
"name": "Geraldine Street, Elephant & Castle",
"latitude": "51.49612799",
"longitude": "-0.106000855",
"bikesAvailable": "1",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "298",
"name": "Curlew Street, Shad Thames",
"latitude": "51.50227992",
"longitude": "-0.074189225",
"bikesAvailable": "3",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "299",
"name": "Vincent Square, Westminster",
"latitude": "51.49398524",
"longitude": "-0.136928582",
"bikesAvailable": "17",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "300",
"name": "Serpentine Car Park, Hyde Park",
"latitude": "51.50501351",
"longitude": "-0.172729559",
"bikesAvailable": "8",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "301",
"name": "Marylebone Lane, Marylebone",
"latitude": "51.51475963",
"longitude": "-0.148105415",
"bikesAvailable": "22",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "303",
"name": "Albert Gate, Hyde Park",
"latitude": "51.50295379",
"longitude": "-0.158456089",
"bikesAvailable": "16",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "343",
"name": "London Zoo Car Park, Regent's Park",
"latitude": "51.53692216",
"longitude": "-0.150181444",
"bikesAvailable": "7",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "341",
"name": "Craven Street, Strand",
"latitude": "51.50810309",
"longitude": "-0.12602103",
"bikesAvailable": "3",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "340",
"name": "Bank of England Museum, Bank",
"latitude": "51.51444134",
"longitude": "-0.087587447",
"bikesAvailable": "8",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "339",
"name": "Risinghill Street, Angel",
"latitude": "51.5333196",
"longitude": "-0.111781191",
"bikesAvailable": "8",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "338",
"name": "Wellington Street , Strand",
"latitude": "51.51175646",
"longitude": "-0.119643424",
"bikesAvailable": "13",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "337",
"name": "Pembridge Villas, Notting Hill",
"latitude": "51.51108452",
"longitude": "-0.197524944",
"bikesAvailable": "3",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "336",
"name": "Concert Hall Approach 2, South Bank",
"latitude": "51.504942",
"longitude": "-0.115533",
"bikesAvailable": "6",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "351",
"name": "Macclesfield Rd, St Lukes",
"latitude": "51.529423",
"longitude": "-0.097122",
"bikesAvailable": "22",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "350",
"name": "Queen's Gate, Kensington Gardens",
"latitude": "51.5017154373867",
"longitude": "-0.1798541843891",
"bikesAvailable": "10",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "349",
"name": "St. George Street, Mayfair",
"latitude": "51.51196",
"longitude": "-0.142783033",
"bikesAvailable": "17",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "348",
"name": "Grosvenor Square, Mayfair",
"latitude": "51.51217033",
"longitude": "-0.150481272",
"bikesAvailable": "11",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "347",
"name": "Lower Marsh, Waterloo",
"latitude": "51.50013942",
"longitude": "-0.113936001",
"bikesAvailable": "9",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "345",
"name": "Flood Street, Chelsea",
"latitude": "51.48802358",
"longitude": "-0.166878535",
"bikesAvailable": "18",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "344",
"name": "Goswell Road (City Uni), Finsbury",
"latitude": "51.528246",
"longitude": "-0.10102611",
"bikesAvailable": "11",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "326",
"name": "Graham Street, Angel",
"latitude": "51.53266186",
"longitude": "-0.099981142",
"bikesAvailable": "17",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "327",
"name": "New North Road 1, Hoxton",
"latitude": "51.53114",
"longitude": "-0.086016",
"bikesAvailable": "13",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "324",
"name": "Ontario Street, Elephant & Castle",
"latitude": "51.49652013",
"longitude": "-0.101384068",
"bikesAvailable": "4",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "325",
"name": "St. Martin's Street, West End",
"latitude": "51.50908747",
"longitude": "-0.129697889",
"bikesAvailable": "15",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "322",
"name": "Palissy Street, Shoreditch",
"latitude": "51.526293",
"longitude": "-0.073955",
"bikesAvailable": "11",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "323",
"name": "Clifton Street, Shoreditch",
"latitude": "51.523196",
"longitude": "-0.083067",
"bikesAvailable": "20",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "320",
"name": "Queen Mother Sports Centre, Victoria",
"latitude": "51.49357351",
"longitude": "-0.139956043",
"bikesAvailable": "25",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "321",
"name": "Bermondsey Street, Bermondsey",
"latitude": "51.49785559",
"longitude": "-0.081608045",
"bikesAvailable": "3",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "334",
"name": "Concert Hall Approach 1, South Bank",
"latitude": "51.505044",
"longitude": "-0.115851",
"bikesAvailable": "3",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "335",
"name": "Tavistock Street, Covent Garden",
"latitude": "51.51196803",
"longitude": "-0.120718759",
"bikesAvailable": "25",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "332",
"name": "Nevern Place, Earl's Court",
"latitude": "51.49334336",
"longitude": "-0.194757949",
"bikesAvailable": "3",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "333",
"name": "Palace Gardens Terrace, Notting Hill",
"latitude": "51.50860544",
"longitude": "-0.193764092",
"bikesAvailable": "1",
"emptySlots": "36",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "330",
"name": "Eastbourne Mews, Paddington",
"latitude": "51.51641749",
"longitude": "-0.179135079",
"bikesAvailable": "0",
"emptySlots": "34",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "331",
"name": "Bunhill Row, Moorgate",
"latitude": "51.52085887",
"longitude": "-0.089887855",
"bikesAvailable": "22",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "328",
"name": "New North Road 2, Hoxton",
"latitude": "51.53095",
"longitude": "-0.085603",
"bikesAvailable": "17",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "329",
"name": "Prince Albert Road, Regent's Park",
"latitude": "51.53589283",
"longitude": "-0.160854428",
"bikesAvailable": "17",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "373",
"name": "Prince Consort Road, Knightsbridge",
"latitude": "51.49980661",
"longitude": "-0.176415994",
"bikesAvailable": "5",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "372",
"name": "Sardinia Street, Holborn",
"latitude": "51.515208",
"longitude": "-0.117863",
"bikesAvailable": "17",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "375",
"name": "Kensington Town Hall, Kensington",
"latitude": "51.50194596",
"longitude": "-0.194392952",
"bikesAvailable": "6",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "374",
"name": "Waterloo Station 1, Waterloo",
"latitude": "51.50402793",
"longitude": "-0.11386435",
"bikesAvailable": "15",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "368",
"name": "Harriet Street, Knightsbridge",
"latitude": "51.50024195",
"longitude": "-0.15934065",
"bikesAvailable": "24",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "371",
"name": "King Edward Walk, Waterloo",
"latitude": "51.49775",
"longitude": "-0.10988",
"bikesAvailable": "6",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "370",
"name": "Paddington Green, Paddington",
"latitude": "51.520205",
"longitude": "-0.174593",
"bikesAvailable": "7",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "381",
"name": "Charlotte Street, Fitzrovia",
"latitude": "51.51953043",
"longitude": "-0.13577731",
"bikesAvailable": "4",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "380",
"name": "Stanhope Gate, Mayfair",
"latitude": "51.50686435",
"longitude": "-0.150666888",
"bikesAvailable": "11",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "383",
"name": "Frith Street, Soho",
"latitude": "51.51310333",
"longitude": "-0.13121385",
"bikesAvailable": "16",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "382",
"name": "Farm Street, Mayfair",
"latitude": "51.50935171",
"longitude": "-0.14744969",
"bikesAvailable": "7",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "377",
"name": "Waterloo Bridge, South Bank",
"latitude": "51.50535447",
"longitude": "-0.113656543",
"bikesAvailable": "3",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "376",
"name": "Millbank House, Pimlico",
"latitude": "51.49188409",
"longitude": "-0.125674815",
"bikesAvailable": "18",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "379",
"name": "Turquoise Island, Notting Hill",
"latitude": "51.51431171",
"longitude": "-0.200838199",
"bikesAvailable": "2",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "378",
"name": "Natural History Museum, South Kensington",
"latitude": "51.49559291",
"longitude": "-0.179077626",
"bikesAvailable": "39",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "356",
"name": "\n South Kensington Station, South Kensington\n ",
"latitude": "51.494412",
"longitude": "-0.173881",
"bikesAvailable": "8",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "357",
"name": "Howland Street, Fitzrovia",
"latitude": "51.520994",
"longitude": "-0.139016",
"bikesAvailable": "26",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "358",
"name": "High Holborn , Covent Garden",
"latitude": "51.51643491",
"longitude": "-0.124332175",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "359",
"name": "Butler Place, Westminster",
"latitude": "51.49782999",
"longitude": "-0.135440826",
"bikesAvailable": "12",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "352",
"name": "Vauxhall Street, Vauxhall",
"latitude": "51.486965",
"longitude": "-0.116625",
"bikesAvailable": "4",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "353",
"name": "Greycoat Street , Westminster",
"latitude": "51.49459148",
"longitude": "-0.134234258",
"bikesAvailable": "14",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "354",
"name": "Northumberland Avenue, Strand",
"latitude": "51.506767",
"longitude": "-0.123702",
"bikesAvailable": "16",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "355",
"name": "Oval Way, Lambeth",
"latitude": "51.486575",
"longitude": "-0.117286",
"bikesAvailable": "6",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "364",
"name": "Alfred Place, Bloomsbury",
"latitude": "51.519656",
"longitude": "-0.132339",
"bikesAvailable": "24",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "365",
"name": "City Road, Angel",
"latitude": "51.530344",
"longitude": "-0.100168",
"bikesAvailable": "41",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "366",
"name": "Millennium Hotel, Mayfair",
"latitude": "51.5109192966489",
"longitude": "-0.1511263847351",
"bikesAvailable": "25",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "367",
"name": "Harrowby Street, Marylebone",
"latitude": "51.5173721",
"longitude": "-0.1642075",
"bikesAvailable": "2",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "360",
"name": "Howick Place, Westminster",
"latitude": "51.49675303",
"longitude": "-0.138733562",
"bikesAvailable": "24",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "361",
"name": "Waterloo Station 2, Waterloo",
"latitude": "51.50391972",
"longitude": "-0.11342628",
"bikesAvailable": "0",
"emptySlots": "55",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "362",
"name": "Royal College Street, Camden Town",
"latitude": "51.536264",
"longitude": "-0.133952",
"bikesAvailable": "28",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "363",
"name": "Lord's, St. John's Wood",
"latitude": "51.5291212008901",
"longitude": "-0.171185284853",
"bikesAvailable": "9",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "410",
"name": "Edgware Road Station, Paddington",
"latitude": "51.519968",
"longitude": "-0.169774",
"bikesAvailable": "30",
"emptySlots": "34",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "411",
"name": "Walworth Road, Southwark",
"latitude": "51.49337264",
"longitude": "-0.09968067",
"bikesAvailable": "4",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "408",
"name": "\n Paddington Green Police Station, Paddington\n ",
"latitude": "51.51994326",
"longitude": "-0.170704337",
"bikesAvailable": "2",
"emptySlots": "38",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "409",
"name": "Strata, Southwark",
"latitude": "51.493146",
"longitude": "-0.099828",
"bikesAvailable": "9",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "412",
"name": "Cleaver Street, Kennington",
"latitude": "51.488105",
"longitude": "-0.110121",
"bikesAvailable": "6",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "402",
"name": "Penfold Street, Marylebone",
"latitude": "51.52289229",
"longitude": "-0.171681991",
"bikesAvailable": "11",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "403",
"name": "George Place Mews, Marylebone",
"latitude": "51.51689296",
"longitude": "-0.158249929",
"bikesAvailable": "15",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "400",
"name": "George Street, Marylebone",
"latitude": "51.517703",
"longitude": "-0.154106",
"bikesAvailable": "25",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "401",
"name": "Columbia Road, Weavers",
"latitude": "51.528187",
"longitude": "-0.075375",
"bikesAvailable": "6",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "406",
"name": "Speakers' Corner 2, Hyde Park",
"latitude": "51.512303",
"longitude": "-0.159988",
"bikesAvailable": "9",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "407",
"name": "Speakers' Corner 1, Hyde Park",
"latitude": "51.51222",
"longitude": "-0.160785",
"bikesAvailable": "17",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "404",
"name": "Palace Gate, Kensington Gardens",
"latitude": "51.50204238",
"longitude": "-0.184400221",
"bikesAvailable": "4",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "405",
"name": "\n Gloucester Road Station, South Kensington\n ",
"latitude": "51.49418566",
"longitude": "-0.18267094",
"bikesAvailable": "6",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "395",
"name": "Cadogan Gardens, Sloane Square",
"latitude": "51.492462",
"longitude": "-0.159919",
"bikesAvailable": "14",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "394",
"name": "Aberdeen Place, St. John's Wood",
"latitude": "51.524826",
"longitude": "-0.176268",
"bikesAvailable": "9",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "393",
"name": "Snow Hill, Farringdon",
"latitude": "51.51733427",
"longitude": "-0.103604248",
"bikesAvailable": "11",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "392",
"name": "Imperial College, Knightsbridge",
"latitude": "51.49942855",
"longitude": "-0.179702476",
"bikesAvailable": "9",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "399",
"name": "Brick Lane Market, Shoreditch",
"latitude": "51.52261762",
"longitude": "-0.071653961",
"bikesAvailable": "14",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "398",
"name": "Holland Park, Kensington",
"latitude": "51.502319",
"longitude": "-0.200742",
"bikesAvailable": "1",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "397",
"name": "Devonshire Terrace, Bayswater",
"latitude": "51.51348",
"longitude": "-0.17977",
"bikesAvailable": "1",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "396",
"name": "Shouldham Street, Marylebone",
"latitude": "51.51809",
"longitude": "-0.163609",
"bikesAvailable": "4",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "387",
"name": "Fire Brigade Pier, Vauxhall",
"latitude": "51.49369988",
"longitude": "-0.121394101",
"bikesAvailable": "23",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "386",
"name": "Moor Street, Soho",
"latitude": "51.51352755",
"longitude": "-0.130110822",
"bikesAvailable": "13",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "384",
"name": "Marloes Road, Kensington",
"latitude": "51.496481",
"longitude": "-0.192404",
"bikesAvailable": "5",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "391",
"name": "Clifford Street, Mayfair",
"latitude": "51.51066202",
"longitude": "-0.142345694",
"bikesAvailable": "25",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "390",
"name": "Buxton Street 1, Shoreditch",
"latitude": "51.521776",
"longitude": "-0.068856",
"bikesAvailable": "36",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "389",
"name": "Upper Grosvenor Street, Mayfair",
"latitude": "51.51013066",
"longitude": "-0.155757901",
"bikesAvailable": "6",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "388",
"name": "Southampton Street, Strand",
"latitude": "51.51070161",
"longitude": "-0.121723604",
"bikesAvailable": "1",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "440",
"name": "Kennington Oval, Oval",
"latitude": "51.483145",
"longitude": "-0.113134",
"bikesAvailable": "23",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "441",
"name": "Sail Street, Vauxhall",
"latitude": "51.495656",
"longitude": "-0.114605",
"bikesAvailable": "9",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "442",
"name": "Walmer Road, Notting Hill",
"latitude": "51.510101",
"longitude": "-0.211358",
"bikesAvailable": "11",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "443",
"name": "Philpot Street, Whitechapel",
"latitude": "51.515256",
"longitude": "-0.058641",
"bikesAvailable": "2",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "444",
"name": "Bethnal Green Gardens, Bethnal Green",
"latitude": "51.52568",
"longitude": "-0.055312",
"bikesAvailable": "22",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "445",
"name": "Cheshire Street, Bethnal Green",
"latitude": "51.52388",
"longitude": "-0.065076",
"bikesAvailable": "12",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "446",
"name": "York Hall, Bethnal Green",
"latitude": "51.528936",
"longitude": "-0.055894",
"bikesAvailable": "24",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "447",
"name": "Jubilee Crescent, Cubitt Town",
"latitude": "51.493381",
"longitude": "-0.007542",
"bikesAvailable": "34",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "432",
"name": "Exhibition Road Museums, Knightsbridge",
"latitude": "51.496957",
"longitude": "-0.173894",
"bikesAvailable": "18",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "433",
"name": "Wren Street, Holborn",
"latitude": "51.524564",
"longitude": "-0.116279",
"bikesAvailable": "24",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "435",
"name": "Kennington Station, Kennington",
"latitude": "51.488852",
"longitude": "-0.105593",
"bikesAvailable": "13",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "436",
"name": "Red Lion Street, Holborn",
"latitude": "51.51824",
"longitude": "-0.11655",
"bikesAvailable": "29",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "437",
"name": "Vauxhall Walk, Vauxhall",
"latitude": "51.488124",
"longitude": "-0.120903",
"bikesAvailable": "15",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "439",
"name": "Killick Street, Kings Cross",
"latitude": "51.5338",
"longitude": "-0.118677",
"bikesAvailable": "15",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "425",
"name": "Harrington Square 2, Camden Town",
"latitude": "51.533379",
"longitude": "-0.139159",
"bikesAvailable": "25",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "424",
"name": "Ebury Bridge, Pimlico",
"latitude": "51.490491",
"longitude": "-0.149186",
"bikesAvailable": "20",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "427",
"name": "Cheapside, Bank",
"latitude": "51.51397065",
"longitude": "-0.09294031",
"bikesAvailable": "41",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "426",
"name": "Vincent Street, Pimlico",
"latitude": "51.493072",
"longitude": "-0.129925",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "428",
"name": "Exhibition Road, South Kensington",
"latitude": "51.499917",
"longitude": "-0.174554",
"bikesAvailable": "10",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "431",
"name": "Crinan Street, King's Cross",
"latitude": "51.534474",
"longitude": "-0.122203",
"bikesAvailable": "8",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "430",
"name": "South Parade, Chelsea",
"latitude": "51.48902",
"longitude": "-0.17524",
"bikesAvailable": "14",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "421",
"name": "Southwark Station 2, Southwark",
"latitude": "51.504044",
"longitude": "-0.104778",
"bikesAvailable": "18",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "420",
"name": "Southwark Station 1, Southwark",
"latitude": "51.504043",
"longitude": "-0.105312",
"bikesAvailable": "33",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "423",
"name": "Eaton Square (South), Belgravia",
"latitude": "51.49456127",
"longitude": "-0.15393398",
"bikesAvailable": "31",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "478",
"name": "Stepney Green Station, Stepney",
"latitude": "51.521889",
"longitude": "-0.04667",
"bikesAvailable": "4",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "479",
"name": "Pott Street, Bethnal Green",
"latitude": "51.527152",
"longitude": "-0.058005",
"bikesAvailable": "13",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "476",
"name": "Stebondale Street, Cubitt Town",
"latitude": "51.489096",
"longitude": "-0.009205",
"bikesAvailable": "28",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "477",
"name": "Spindrift Avenue, Millwall",
"latitude": "51.49109",
"longitude": "-0.018716",
"bikesAvailable": "19",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "474",
"name": "Castalia Square, Cubitt Town",
"latitude": "51.498125",
"longitude": "-0.011457",
"bikesAvailable": "15",
"emptySlots": "23",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "475",
"name": "Lightermans Road, Millwall",
"latitude": "51.499041",
"longitude": "-0.020157",
"bikesAvailable": "47",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "472",
"name": "Malmesbury Road, Bow",
"latitude": "51.529452",
"longitude": "-0.027616",
"bikesAvailable": "11",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "473",
"name": "Millharbour, Millwall",
"latitude": "51.496137",
"longitude": "-0.019355",
"bikesAvailable": "14",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "470",
"name": "Mostyn Grove, Bow",
"latitude": "51.530535",
"longitude": "-0.025492",
"bikesAvailable": "15",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "471",
"name": "Hewison Street, Old Ford",
"latitude": "51.533283",
"longitude": "-0.028155",
"bikesAvailable": "1",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "468",
"name": "Cantrell Road, Bow",
"latitude": "51.521564",
"longitude": "-0.022694",
"bikesAvailable": "21",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "469",
"name": "Lindfield Street, Poplar",
"latitude": "51.513757",
"longitude": "-0.020467",
"bikesAvailable": "22",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "466",
"name": "Whiston Road, Haggerston",
"latitude": "51.534464",
"longitude": "-0.076341",
"bikesAvailable": "6",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "467",
"name": "Southern Grove, Bow",
"latitude": "51.523538",
"longitude": "-0.030556",
"bikesAvailable": "3",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "464",
"name": "St. Mary and St. Michael Church, Stepney",
"latitude": "51.51417",
"longitude": "-0.052099",
"bikesAvailable": "18",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "465",
"name": "Pitfield Street (North),Hoxton",
"latitude": "51.53558",
"longitude": "-0.08249",
"bikesAvailable": "6",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "463",
"name": "Thurtle Road, Haggerston",
"latitude": "51.534776",
"longitude": "-0.071881",
"bikesAvailable": "3",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "462",
"name": "Bonny Street, Camden Town",
"latitude": "51.541603",
"longitude": "-0.138853",
"bikesAvailable": "2",
"emptySlots": "43",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "461",
"name": "Aston Street, Stepney",
"latitude": "51.516",
"longitude": "-0.038775",
"bikesAvailable": "6",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "460",
"name": "Burdett Road, Mile End",
"latitude": "51.516196",
"longitude": "-0.029138",
"bikesAvailable": "18",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "459",
"name": "Gun Makers Lane, Old Ford",
"latitude": "51.535179",
"longitude": "-0.03338",
"bikesAvailable": "2",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "458",
"name": "Wapping Lane, Wapping",
"latitude": "51.504749",
"longitude": "-0.057544",
"bikesAvailable": "2",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "457",
"name": "Castlehaven Road, Camden Town",
"latitude": "51.542138",
"longitude": "-0.145393",
"bikesAvailable": "18",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "456",
"name": "Parkway, Camden Town",
"latitude": "51.538071",
"longitude": "-0.144664",
"bikesAvailable": "21",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "455",
"name": "East Ferry Road, Cubitt Town",
"latitude": "51.49447",
"longitude": "-0.014409",
"bikesAvailable": "15",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "454",
"name": "Napier Avenue, Millwall",
"latitude": "51.487679",
"longitude": "-0.021582",
"bikesAvailable": "12",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "453",
"name": "Garnet Street, Shadwell",
"latitude": "51.508447",
"longitude": "-0.055167",
"bikesAvailable": "5",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "452",
"name": "St Katharines Way, Tower",
"latitude": "51.505697",
"longitude": "-0.070542",
"bikesAvailable": "18",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "451",
"name": "Hermitage Court, Wapping",
"latitude": "51.504719",
"longitude": "-0.063531",
"bikesAvailable": "2",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "450",
"name": "Jubilee Street, Stepney",
"latitude": "51.515975",
"longitude": "-0.053177",
"bikesAvailable": "14",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "449",
"name": "Shadwell Station, Shadwell",
"latitude": "51.511088",
"longitude": "-0.057159",
"bikesAvailable": "0",
"emptySlots": "34",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "448",
"name": "Fishermans Walk West, Canary Wharf",
"latitude": "51.50623",
"longitude": "-0.02296",
"bikesAvailable": "18",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "508",
"name": "Fournier Street, Whitechapel",
"latitude": "51.519362",
"longitude": "-0.074431",
"bikesAvailable": "16",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "509",
"name": "Fore Street, Guildhall",
"latitude": "51.517842",
"longitude": "-0.090075",
"bikesAvailable": "10",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "510",
"name": "Westferry DLR, Limehouse",
"latitude": "51.509303",
"longitude": "-0.025996",
"bikesAvailable": "39",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "511",
"name": "Sutton Street, Shadwell",
"latitude": "51.511066",
"longitude": "-0.053558",
"bikesAvailable": "0",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "504",
"name": "St John's Park, Cubitt Town",
"latitude": "51.496454",
"longitude": "-0.009506",
"bikesAvailable": "20",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "505",
"name": "Ackroyd Drive, Bow",
"latitude": "51.520398",
"longitude": "-0.026768",
"bikesAvailable": "19",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "506",
"name": "Bell Lane, Liverpool Street",
"latitude": "51.517475",
"longitude": "-0.075855",
"bikesAvailable": "17",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "507",
"name": "Clarkson Street, Bethnal Green",
"latitude": "51.528692",
"longitude": "-0.059091",
"bikesAvailable": "5",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "500",
"name": "Sidney Street, Stepney",
"latitude": "51.519806",
"longitude": "-0.055731",
"bikesAvailable": "7",
"emptySlots": "36",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "501",
"name": "Cephas Street, Bethnal Green",
"latitude": "51.522561",
"longitude": "-0.054883",
"bikesAvailable": "9",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "502",
"name": "South Quay West, Canary Wharf",
"latitude": "51.502635",
"longitude": "-0.022702",
"bikesAvailable": "18",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "503",
"name": "Cleveland Way, Bethnal Green",
"latitude": "51.520893",
"longitude": "-0.051394",
"bikesAvailable": "14",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "496",
"name": "Devons Road, Bow",
"latitude": "51.52512",
"longitude": "-0.015578",
"bikesAvailable": "15",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "497",
"name": "Coborn Street, Mile End",
"latitude": "51.526535",
"longitude": "-0.028619",
"bikesAvailable": "22",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "498",
"name": "Bow Road Station, Bow",
"latitude": "51.527058",
"longitude": "-0.025296",
"bikesAvailable": "37",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "499",
"name": "Furze Green, Bow",
"latitude": "51.519265",
"longitude": "-0.021345",
"bikesAvailable": "6",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "492",
"name": "The Green Bridge, Mile End",
"latitude": "51.524677",
"longitude": "-0.03562",
"bikesAvailable": "28",
"emptySlots": "35",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "495",
"name": "Bow Church Station, Bow",
"latitude": "51.528169",
"longitude": "-0.018703",
"bikesAvailable": "18",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "494",
"name": "South Quay East, Canary Wharf",
"latitude": "51.50196",
"longitude": "-0.016251",
"bikesAvailable": "25",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "489",
"name": "Christian Street, Whitechapel",
"latitude": "51.513074",
"longitude": "-0.064094",
"bikesAvailable": "9",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "488",
"name": "Reardon Street, Wapping",
"latitude": "51.506946",
"longitude": "-0.058681",
"bikesAvailable": "0",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "491",
"name": "Queen Marys, Mile End",
"latitude": "51.522507",
"longitude": "-0.041378",
"bikesAvailable": "28",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "490",
"name": "Pennington Street, Wapping",
"latitude": "51.508622",
"longitude": "-0.065006",
"bikesAvailable": "28",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "485",
"name": "Old Ford Road, Bethnal Green",
"latitude": "51.531127",
"longitude": "-0.048017",
"bikesAvailable": "3",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "484",
"name": "Bromley High Street, Bromley",
"latitude": "51.528828",
"longitude": "-0.013258",
"bikesAvailable": "8",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "487",
"name": "Canton Street, Poplar",
"latitude": "51.511811",
"longitude": "-0.025626",
"bikesAvailable": "10",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "486",
"name": "Granby Street, Shoreditch",
"latitude": "51.525645",
"longitude": "-0.069543",
"bikesAvailable": "7",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "481",
"name": "Saunders Ness Road, Cubitt Town",
"latitude": "51.487129",
"longitude": "-0.009001",
"bikesAvailable": "30",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "480",
"name": "Flamborough Street, Limehouse",
"latitude": "51.5128711",
"longitude": "-0.0389866",
"bikesAvailable": "1",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "483",
"name": "Albert Gardens, Stepney",
"latitude": "51.51328",
"longitude": "-0.047784",
"bikesAvailable": "11",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "482",
"name": "Thornfield House, Poplar",
"latitude": "51.509843",
"longitude": "-0.02377",
"bikesAvailable": "15",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "550",
"name": "Harford Street, Mile End",
"latitude": "51.521564",
"longitude": "-0.039264",
"bikesAvailable": "22",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "551",
"name": "Montgomery Square, Canary Wharf",
"latitude": "51.503447",
"longitude": "-0.016233",
"bikesAvailable": "34",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "548",
"name": "\n Westminster Bridge Road, Elephant & Castle\n ",
"latitude": "51.498386",
"longitude": "-0.107913",
"bikesAvailable": "13",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "549",
"name": "Gaywood Street, Elephant & Castle",
"latitude": "51.49605",
"longitude": "-0.104193",
"bikesAvailable": "13",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "546",
"name": "New Fetter Lane, Holborn",
"latitude": "51.517428",
"longitude": "-0.107987",
"bikesAvailable": "10",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "547",
"name": "East India DLR, Blackwall",
"latitude": "51.509474",
"longitude": "-0.002275",
"bikesAvailable": "35",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "544",
"name": "Percival Street, Finsbury",
"latitude": "51.526153",
"longitude": "-0.102208",
"bikesAvailable": "14",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "545",
"name": "Arlington Road, Camden Town",
"latitude": "51.539957",
"longitude": "-0.145246",
"bikesAvailable": "18",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "558",
"name": "Page Street, Westminster",
"latitude": "51.493978",
"longitude": "-0.127554",
"bikesAvailable": "20",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "559",
"name": "Abbotsbury Road, Holland Park",
"latitude": "51.501391",
"longitude": "-0.205991",
"bikesAvailable": "3",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "556",
"name": "Heron Quays DLR, Canary Wharf",
"latitude": "51.502661",
"longitude": "-0.021596",
"bikesAvailable": "21",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "557",
"name": "King Edward Street, St Pauls",
"latitude": "51.51601",
"longitude": "-0.0985",
"bikesAvailable": "17",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "554",
"name": "Aberfeldy Street, Poplar",
"latitude": "51.513548",
"longitude": "-0.005659",
"bikesAvailable": "8",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "555",
"name": "\n Westfield Eastern Access Road, Shepherd's Bush\n ",
"latitude": "51.509424",
"longitude": "-0.219712",
"bikesAvailable": "18",
"emptySlots": "37",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "552",
"name": "Watney Street, Shadwell",
"latitude": "51.511542",
"longitude": "-0.056667",
"bikesAvailable": "0",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "553",
"name": "Regent's Row , Haggerston ",
"latitude": "51.535678",
"longitude": "-0.062546",
"bikesAvailable": "5",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "566",
"name": "Westfield Ariel Way, White City",
"latitude": "51.509158",
"longitude": "-0.224103",
"bikesAvailable": "24",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "565",
"name": "Selby Street, Whitechapel",
"latitude": "51.521905",
"longitude": "-0.063386",
"bikesAvailable": "9",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "564",
"name": "Somerset House, Strand",
"latitude": "51.509943",
"longitude": "-0.117619",
"bikesAvailable": "34",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "563",
"name": "Preston's Road, Cubitt Town",
"latitude": "51.499286",
"longitude": "-0.009152",
"bikesAvailable": "25",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "562",
"name": "Bury Place, Holborn",
"latitude": "51.51746",
"longitude": "-0.12335",
"bikesAvailable": "17",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "561",
"name": "Rectory Square, Stepney",
"latitude": "51.518369",
"longitude": "-0.043371",
"bikesAvailable": "2",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "560",
"name": "Ladbroke Grove Central, Notting Hill",
"latitude": "51.511624",
"longitude": "-0.205921",
"bikesAvailable": "11",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "574",
"name": "Eagle Wharf Road, Hoxton",
"latitude": "51.53356",
"longitude": "-0.09315",
"bikesAvailable": "35",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "573",
"name": "Limerston Street, Chelsea",
"latitude": "51.485587",
"longitude": "-0.18119",
"bikesAvailable": "9",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "572",
"name": "Greenland Road, Camden Town",
"latitude": "51.539099",
"longitude": "-0.141728",
"bikesAvailable": "18",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "571",
"name": "\n Westfield Southern Terrace ,Shepherd's Bush\n ",
"latitude": "51.506256",
"longitude": "-0.218337",
"bikesAvailable": "16",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "570",
"name": "Upper Bank Street, Canary Wharf",
"latitude": "51.503083",
"longitude": "-0.017676",
"bikesAvailable": "34",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "569",
"name": "Pitfield Street Central, Hoxton",
"latitude": "51.53213",
"longitude": "-0.08299",
"bikesAvailable": "10",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "568",
"name": "Bishop's Bridge Road West, Bayswater",
"latitude": "51.51616",
"longitude": "-0.18697",
"bikesAvailable": "0",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "516",
"name": "Chrisp Street Market, Poplar",
"latitude": "51.5112",
"longitude": "-0.014438",
"bikesAvailable": "16",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "517",
"name": "Ford Road, Old Ford",
"latitude": "51.532513",
"longitude": "-0.033085",
"bikesAvailable": "0",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "518",
"name": "Antill Road, Mile End",
"latitude": "51.528224",
"longitude": "-0.037471",
"bikesAvailable": "6",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "519",
"name": "Teviot Street, Poplar",
"latitude": "51.518811",
"longitude": "-0.011662",
"bikesAvailable": "26",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "512",
"name": "Pritchard's Road, Bethnal Green",
"latitude": "51.532091",
"longitude": "-0.06142",
"bikesAvailable": "4",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "513",
"name": "Watney Market, Stepney",
"latitude": "51.5142228",
"longitude": "-0.055656",
"bikesAvailable": "9",
"emptySlots": "42",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "514",
"name": "Portman Square, Marylebone",
"latitude": "51.516204",
"longitude": "-0.155525",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "515",
"name": "Russell Gardens, Holland Park",
"latitude": "51.500088",
"longitude": "-0.211316",
"bikesAvailable": "4",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "524",
"name": "Lancaster Gate , Bayswater",
"latitude": "51.511654",
"longitude": "-0.179668",
"bikesAvailable": "8",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "525",
"name": "Churchill Place, Canary Wharf",
"latitude": "51.504714",
"longitude": "-0.014293",
"bikesAvailable": "8",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "526",
"name": "Lancaster Drive, Blackwall",
"latitude": "51.503143",
"longitude": "-0.008428",
"bikesAvailable": "23",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "527",
"name": "Hansard Mews, Shepherds Bush",
"latitude": "51.503802",
"longitude": "-0.215808",
"bikesAvailable": "19",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "520",
"name": "Bancroft Road, Bethnal Green",
"latitude": "51.526041",
"longitude": "-0.047218",
"bikesAvailable": "9",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "521",
"name": "Driffield Road, Old Ford",
"latitude": "51.534137",
"longitude": "-0.037366",
"bikesAvailable": "1",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "522",
"name": "Clinton Road, Mile End",
"latitude": "51.525941",
"longitude": "-0.036017",
"bikesAvailable": "23",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "523",
"name": "Langdon Park, Poplar",
"latitude": "51.51549",
"longitude": "-0.013475",
"bikesAvailable": "15",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "533",
"name": "Wellington Row, Bethnal Green",
"latitude": "51.528222",
"longitude": "-0.069743",
"bikesAvailable": "5",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "532",
"name": "Jubilee Plaza, Canary Wharf",
"latitude": "51.50357",
"longitude": "-0.020068",
"bikesAvailable": "56",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "535",
"name": "Gloucester Avenue, Camden Town",
"latitude": "51.537349",
"longitude": "-0.147154",
"bikesAvailable": "7",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "534",
"name": "Goldsmiths Row, Haggerston",
"latitude": "51.531864",
"longitude": "-0.066035",
"bikesAvailable": "15",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "529",
"name": "Manresa Road, Chelsea",
"latitude": "51.486892",
"longitude": "-0.170983",
"bikesAvailable": "16",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "528",
"name": "Clarges Street, West End",
"latitude": "51.507326",
"longitude": "-0.145827",
"bikesAvailable": "12",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "531",
"name": "Twig Folly Bridge, Mile End",
"latitude": "51.530326",
"longitude": "-0.042744",
"bikesAvailable": "3",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "530",
"name": "Newby Place, Poplar",
"latitude": "51.508896",
"longitude": "-0.012413",
"bikesAvailable": "16",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "541",
"name": "Green Park Station, West End",
"latitude": "51.506613",
"longitude": "-0.142844",
"bikesAvailable": "16",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "540",
"name": "Albany Street, Regent's Park",
"latitude": "51.528302",
"longitude": "-0.144466",
"bikesAvailable": "11",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "543",
"name": "Lansdowne Walk, Notting Hill",
"latitude": "51.509591",
"longitude": "-0.204666",
"bikesAvailable": "8",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "542",
"name": "Salmon Lane, Limehouse",
"latitude": "51.514115",
"longitude": "-0.033828",
"bikesAvailable": "11",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "537",
"name": "Old Montague Street, Whitechapel",
"latitude": "51.51793",
"longitude": "-0.067937",
"bikesAvailable": "8",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "536",
"name": "Queensbridge Road, Haggerston",
"latitude": "51.53385",
"longitude": "-0.06992",
"bikesAvailable": "24",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "539",
"name": "Hoxton Station, Haggerston",
"latitude": "51.531091",
"longitude": "-0.075901",
"bikesAvailable": "17",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "538",
"name": "Naval Row, Blackwall",
"latitude": "51.508981",
"longitude": "-0.00699",
"bikesAvailable": "20",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "610",
"name": "Danvers Street, West Chelsea",
"latitude": "51.48256792",
"longitude": "-0.172078187",
"bikesAvailable": "5",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "611",
"name": "Princedale Road , Holland Park",
"latitude": "51.50646524",
"longitude": "-0.208486599",
"bikesAvailable": "13",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "608",
"name": "Colet Gardens, Hammersmith",
"latitude": "51.491093",
"longitude": "-0.216493",
"bikesAvailable": "19",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "609",
"name": "Sugden Road, Battersea",
"latitude": "51.46512358",
"longitude": "-0.157788279",
"bikesAvailable": "0",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "614",
"name": "Bradmead, Nine Elms",
"latitude": "51.47817208",
"longitude": "-0.144690541",
"bikesAvailable": "26",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "615",
"name": "Finlay Street, Fulham",
"latitude": "51.4768851",
"longitude": "-0.215895601",
"bikesAvailable": "2",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "612",
"name": "\n Wandsworth Rd, Isley Court, Wandsworth Road\n ",
"latitude": "51.46925984",
"longitude": "-0.141812513",
"bikesAvailable": "15",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "613",
"name": "Woodstock Grove, Shepherd's Bush",
"latitude": "51.50403821",
"longitude": "-0.217400093",
"bikesAvailable": "6",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "618",
"name": "Eel Brook Common, Walham Green",
"latitude": "51.47625965",
"longitude": "-0.193254007",
"bikesAvailable": "1",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "619",
"name": "Irene Road, Parsons Green",
"latitude": "51.4737636",
"longitude": "-0.197010096",
"bikesAvailable": "0",
"emptySlots": "43",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "616",
"name": "Aintree Street, Fulham",
"latitude": "51.48102131",
"longitude": "-0.209973497",
"bikesAvailable": "2",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "617",
"name": "Elysium Place, Fulham",
"latitude": "51.47107905",
"longitude": "-0.207842908",
"bikesAvailable": "7",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "622",
"name": "Lansdowne Road, Ladbroke Grove",
"latitude": "51.50748124",
"longitude": "-0.205535908",
"bikesAvailable": "25",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "623",
"name": "Nantes Close, Wandsworth",
"latitude": "51.46193072",
"longitude": "-0.180791784",
"bikesAvailable": "1",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "620",
"name": "Surrey Lane, Battersea",
"latitude": "51.47518024",
"longitude": "-0.167160736",
"bikesAvailable": "0",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "621",
"name": "Wandsworth Town Station, Wandsworth",
"latitude": "51.46086446",
"longitude": "-0.187427294",
"bikesAvailable": "23",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "627",
"name": "Holden Street, Battersea",
"latitude": "51.4687905",
"longitude": "-0.158230901",
"bikesAvailable": "0",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "626",
"name": "Normand Park, Fulham",
"latitude": "51.48438657",
"longitude": "-0.20481514",
"bikesAvailable": "1",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "625",
"name": "Queen's Circus, Battersea Park",
"latitude": "51.47761941",
"longitude": "-0.149551631",
"bikesAvailable": "1",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "624",
"name": "Courland Grove, Wandsworth Road",
"latitude": "51.4729184",
"longitude": "-0.132102704",
"bikesAvailable": "24",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "631",
"name": "Battersea Park Road, Nine Elms",
"latitude": "51.4795017",
"longitude": "-0.141770709",
"bikesAvailable": "13",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "630",
"name": "Clarence Walk, Stockwell",
"latitude": "51.47073264",
"longitude": "-0.126994068",
"bikesAvailable": "1",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "629",
"name": "Morie Street, Wandsworth",
"latitude": "51.45995384",
"longitude": "-0.190184054",
"bikesAvailable": "14",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "628",
"name": "William Morris Way, Sands End",
"latitude": "51.46881971",
"longitude": "-0.184318843",
"bikesAvailable": "2",
"emptySlots": "23",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "635",
"name": "Greyhound Road, Hammersmith",
"latitude": "51.48606206",
"longitude": "-0.214428378",
"bikesAvailable": "1",
"emptySlots": "36",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "634",
"name": "Brook Green South, Brook Green",
"latitude": "51.49434708",
"longitude": "-0.215804559",
"bikesAvailable": "26",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "633",
"name": "Vereker Road, West Kensington",
"latitude": "51.48959104",
"longitude": "-0.209378594",
"bikesAvailable": "1",
"emptySlots": "31",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "632",
"name": "Sheepcote Lane, Battersea",
"latitude": "51.47053858",
"longitude": "-0.163041605",
"bikesAvailable": "12",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "639",
"name": "Coomer Place, West Kensington",
"latitude": "51.48357068",
"longitude": "-0.202038682",
"bikesAvailable": "9",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "638",
"name": "Falcon Road, Clapham Junction",
"latitude": "51.46663393",
"longitude": "-0.169821175",
"bikesAvailable": "7",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "637",
"name": "Spencer Park, Wandsworth Common",
"latitude": "51.45787019",
"longitude": "-0.174691623",
"bikesAvailable": "5",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "636",
"name": "South Park, Sands End",
"latitude": "51.46706414",
"longitude": "-0.193502076",
"bikesAvailable": "4",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "576",
"name": "Alpha Grove, Millwall",
"latitude": "51.497304",
"longitude": "-0.022793",
"bikesAvailable": "22",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "577",
"name": "Globe Town Market, Bethnal Green",
"latitude": "51.528869",
"longitude": "-0.047548",
"bikesAvailable": "3",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "578",
"name": "Hollybush Gardens, Bethnal Green",
"latitude": "51.527607",
"longitude": "-0.057133",
"bikesAvailable": "23",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "579",
"name": "Queen Street 2, Bank",
"latitude": "51.511246",
"longitude": "-0.093051",
"bikesAvailable": "29",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "580",
"name": "Doddington Grove, Kennington",
"latitude": "51.48692917",
"longitude": "-0.102996299",
"bikesAvailable": "5",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "581",
"name": "New Cavendish Street, Marylebone",
"latitude": "51.519167",
"longitude": "-0.147983",
"bikesAvailable": "15",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "583",
"name": "Abingdon Green, Great College Street",
"latitude": "51.497622",
"longitude": "-0.125978",
"bikesAvailable": "20",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "584",
"name": "Ilchester Gardens, Bayswater",
"latitude": "51.51244",
"longitude": "-0.19096",
"bikesAvailable": "1",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "586",
"name": "Mudchute DLR, Cubitt Town",
"latitude": "51.490645",
"longitude": "-0.014582",
"bikesAvailable": "23",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "587",
"name": "Monument Street, Monument",
"latitude": "51.50964",
"longitude": "-0.08497",
"bikesAvailable": "18",
"emptySlots": "1",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "588",
"name": "Hoxton Street, Hoxton",
"latitude": "51.52959",
"longitude": "-0.0801",
"bikesAvailable": "17",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "589",
"name": "Drayton Gardens, Chelsea",
"latitude": "51.487196",
"longitude": "-0.179369",
"bikesAvailable": "3",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "590",
"name": "Greenberry Street, St.John's Wood",
"latitude": "51.53256",
"longitude": "-0.16862",
"bikesAvailable": "17",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "591",
"name": "\n Westfield Library Corner, Shepherd's Bush\n ",
"latitude": "51.506093",
"longitude": "-0.2242237",
"bikesAvailable": "21",
"emptySlots": "6",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "593",
"name": "Northdown Street, King's Cross",
"latitude": "51.531066",
"longitude": "-0.11934",
"bikesAvailable": "15",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "592",
"name": "Bishop's Bridge Road East, Bayswater",
"latitude": "51.5171",
"longitude": "-0.18377",
"bikesAvailable": "0",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "595",
"name": "Hammersmith Road, Hammersmith",
"latitude": "51.493267",
"longitude": "-0.21985",
"bikesAvailable": "12",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "594",
"name": "Kingsway Southbound, Strand",
"latitude": "51.513875",
"longitude": "-0.117774",
"bikesAvailable": "33",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "597",
"name": "Fulham Park Road, Fulham",
"latitude": "51.473471",
"longitude": "-0.20782",
"bikesAvailable": "1",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "596",
"name": "Parson's Green , Parson's Green",
"latitude": "51.472817",
"longitude": "-0.199783",
"bikesAvailable": "2",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "599",
"name": "Manbre Road, Hammersmith",
"latitude": "51.485743",
"longitude": "-0.223616",
"bikesAvailable": "7",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "598",
"name": "Southerton Road, Hammersmith",
"latitude": "51.494499",
"longitude": "-0.228188",
"bikesAvailable": "4",
"emptySlots": "34",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "601",
"name": "BBC White City, White City",
"latitude": "51.514767",
"longitude": "-0.225787",
"bikesAvailable": "8",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "600",
"name": "South Lambeth Road, Vauxhall",
"latitude": "51.481747",
"longitude": "-0.124642",
"bikesAvailable": "1",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "603",
"name": "Caldwell Street, Stockwell",
"latitude": "51.477839",
"longitude": "-0.116493",
"bikesAvailable": "5",
"emptySlots": "38",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "602",
"name": "Union Grove, Wandsworth Road",
"latitude": "51.472993",
"longitude": "-0.133972",
"bikesAvailable": "10",
"emptySlots": "35",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "605",
"name": "Seymour Place, Marylebone",
"latitude": "51.520331",
"longitude": "-0.163667",
"bikesAvailable": "14",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "604",
"name": "St Martin's Close, Camden Town",
"latitude": "51.538792",
"longitude": "-0.138535",
"bikesAvailable": "11",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "607",
"name": "Putney Bridge Station, Fulham",
"latitude": "51.468814",
"longitude": "-0.210279",
"bikesAvailable": "9",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "606",
"name": "Addison Road, Holland Park",
"latitude": "51.504199",
"longitude": "-0.210941",
"bikesAvailable": "16",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "687",
"name": "Maclise Road, Olympia",
"latitude": "51.49760804",
"longitude": "-0.21145598",
"bikesAvailable": "6",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "686",
"name": "Beryl Road, Hammersmith",
"latitude": "51.48814438",
"longitude": "-0.222456468",
"bikesAvailable": "2",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "685",
"name": "Osiers Road, Wandsworth",
"latitude": "51.46067005",
"longitude": "-0.198735357",
"bikesAvailable": "0",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "684",
"name": "Neville Gill Close, Wandsworth",
"latitude": "51.45475251",
"longitude": "-0.195197203",
"bikesAvailable": "18",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "683",
"name": "Dorothy Road, Clapham Junction",
"latitude": "51.46506424",
"longitude": "-0.163750945",
"bikesAvailable": "13",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "682",
"name": "Crisp Road, Hammersmith",
"latitude": "51.48810829",
"longitude": "-0.22660621",
"bikesAvailable": "11",
"emptySlots": "35",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "681",
"name": "Bishop's Avenue, Fulham",
"latitude": "51.47303687",
"longitude": "-0.214749808",
"bikesAvailable": "2",
"emptySlots": "42",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "680",
"name": "Westbridge Road, Battersea",
"latitude": "51.47768469",
"longitude": "-0.170329317",
"bikesAvailable": "12",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "679",
"name": "Orbel Street, Battersea",
"latitude": "51.47453545",
"longitude": "-0.170210533",
"bikesAvailable": "1",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "678",
"name": "Esmond Street, Putney",
"latitude": "51.46231278",
"longitude": "-0.211468596",
"bikesAvailable": "8",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "677",
"name": "Heath Road, Battersea",
"latitude": "51.46866929",
"longitude": "-0.146544642",
"bikesAvailable": "9",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "676",
"name": "Hartington Road, Stockwell",
"latitude": "51.47787084",
"longitude": "-0.126874471",
"bikesAvailable": "9",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "675",
"name": "Usk Road, Battersea",
"latitude": "51.46348914",
"longitude": "-0.182126248",
"bikesAvailable": "1",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "674",
"name": "Carnegie Street, King's Cross",
"latitude": "51.53546778",
"longitude": "-0.11619105",
"bikesAvailable": "28",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "673",
"name": "Hibbert Street, Battersea",
"latitude": "51.46517078",
"longitude": "-0.18038939",
"bikesAvailable": "18",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "672",
"name": "Grant Road Central, Clapham Junction",
"latitude": "51.4646884",
"longitude": "-0.173656546",
"bikesAvailable": "23",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "702",
"name": "Durant Street, Bethnal Green",
"latitude": "51.52868155",
"longitude": "-0.065550321",
"bikesAvailable": "9",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "703",
"name": "St. Bride Street, Holborn",
"latitude": "51.51505991",
"longitude": "-0.10534448",
"bikesAvailable": "22",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "700",
"name": "Battersea Church Road, Battersea",
"latitude": "51.47696496",
"longitude": "-0.174347066",
"bikesAvailable": "7",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "701",
"name": "Vicarage Crescent, Battersea",
"latitude": "51.47287627",
"longitude": "-0.176267008",
"bikesAvailable": "0",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "698",
"name": "Shoreditch Court, Haggerston",
"latitude": "51.53908372",
"longitude": "-0.070329419",
"bikesAvailable": "12",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "699",
"name": "Belford House, Haggerston",
"latitude": "51.5366541",
"longitude": "-0.07023031",
"bikesAvailable": "13",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "696",
"name": "Charing Cross Hospital, Hammersmith",
"latitude": "51.48728535",
"longitude": "-0.217995921",
"bikesAvailable": "9",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "697",
"name": "Charlotte Terrace, Angel",
"latitude": "51.53639219",
"longitude": "-0.112721065",
"bikesAvailable": "18",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "694",
"name": "Putney Rail Station, Putney",
"latitude": "51.46071722",
"longitude": "-0.216526155",
"bikesAvailable": "3",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "695",
"name": "Islington Green, Angel",
"latitude": "51.53638435",
"longitude": "-0.102757578",
"bikesAvailable": "8",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "692",
"name": "Cadogan Close, Victoria Park",
"latitude": "51.54211855",
"longitude": "-0.028941601",
"bikesAvailable": "5",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "693",
"name": "Felsham Road, Putney",
"latitude": "51.464786",
"longitude": "-0.215618902",
"bikesAvailable": "0",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "690",
"name": "Stanley Grove, Battersea",
"latitude": "51.47047503",
"longitude": "-0.152130083",
"bikesAvailable": "3",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "691",
"name": "Erin Close, Walham Green",
"latitude": "51.47946386",
"longitude": "-0.195777222",
"bikesAvailable": "10",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "688",
"name": "Northfields, Wandsworth",
"latitude": "51.46095151",
"longitude": "-0.20066766",
"bikesAvailable": "1",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "689",
"name": "Spanish Road, Wandsworth",
"latitude": "51.45922541",
"longitude": "-0.180884959",
"bikesAvailable": "0",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "653",
"name": "Simpson Street, Battersea",
"latitude": "51.47084722",
"longitude": "-0.17070367",
"bikesAvailable": "5",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "652",
"name": "Evesham Street, Avondale",
"latitude": "51.51148696",
"longitude": "-0.218190203",
"bikesAvailable": "16",
"emptySlots": "13",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "655",
"name": "Crabtree Lane, Fulham",
"latitude": "51.48294452",
"longitude": "-0.219346128",
"bikesAvailable": "4",
"emptySlots": "23",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "654",
"name": "Ashmole Estate, Oval",
"latitude": "51.48267821",
"longitude": "-0.117661574",
"bikesAvailable": "9",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "649",
"name": "World's End Place, West Chelsea",
"latitude": "51.48180515",
"longitude": "-0.18027465",
"bikesAvailable": "1",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "648",
"name": "Peterborough Road, Sands End",
"latitude": "51.46904022",
"longitude": "-0.19627483",
"bikesAvailable": "0",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "651",
"name": "Thorndike Close, West Chelsea",
"latitude": "51.48089844",
"longitude": "-0.183853573",
"bikesAvailable": "1",
"emptySlots": "23",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "650",
"name": "St. Mark's Road, North Kensington",
"latitude": "51.51687069",
"longitude": "-0.213872396",
"bikesAvailable": "2",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "645",
"name": "Great Suffolk Street, The Borough",
"latitude": "51.50173215",
"longitude": "-0.100292412",
"bikesAvailable": "5",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "644",
"name": "Rainville Road, Hammersmith",
"latitude": "51.48373225",
"longitude": "-0.223852256",
"bikesAvailable": "11",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "647",
"name": "Richmond Way, Shepherd's Bush",
"latitude": "51.50035306",
"longitude": "-0.217515071",
"bikesAvailable": "1",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "646",
"name": "Buckingham Gate, Westminster",
"latitude": "51.49886563",
"longitude": "-0.137424571",
"bikesAvailable": "5",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "641",
"name": "Archbishop's Park, Waterloo",
"latitude": "51.49824168",
"longitude": "-0.117495865",
"bikesAvailable": "21",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "640",
"name": "Silverthorne Road, Battersea",
"latitude": "51.47286577",
"longitude": "-0.148059277",
"bikesAvailable": "2",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "643",
"name": "All Saints' Road, Portobello",
"latitude": "51.5190427",
"longitude": "-0.204764421",
"bikesAvailable": "1",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "642",
"name": "Fawcett Close, Battersea",
"latitude": "51.46916161",
"longitude": "-0.174485792",
"bikesAvailable": "27",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "668",
"name": "Ravenscourt Park Station, Hammersmith",
"latitude": "51.49422354",
"longitude": "-0.236769936",
"bikesAvailable": "8",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "669",
"name": "Teversham Lane, Stockwell",
"latitude": "51.47614939",
"longitude": "-0.1232585",
"bikesAvailable": "24",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "670",
"name": "Ashley Crescent, Battersea",
"latitude": "51.46718562",
"longitude": "-0.152248582",
"bikesAvailable": "0",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "671",
"name": "Parsons Green Station, Parsons Green",
"latitude": "51.475089",
"longitude": "-0.201968",
"bikesAvailable": "11",
"emptySlots": "44",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "664",
"name": "Austin Road, Battersea",
"latitude": "51.474376",
"longitude": "-0.155442787",
"bikesAvailable": "8",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "665",
"name": "Smugglers Way, Wandsworth",
"latitude": "51.46108367",
"longitude": "-0.191722864",
"bikesAvailable": "0",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "666",
"name": "Olympia Way, Olympia",
"latitude": "51.49610093",
"longitude": "-0.208158259",
"bikesAvailable": "5",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "667",
"name": "\n Shepherd's Bush Road North, Shepherd's Bush\n ",
"latitude": "51.5015946",
"longitude": "-0.222293381",
"bikesAvailable": "21",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "660",
"name": "West Kensington Station, West Kensington",
"latitude": "51.49087074",
"longitude": "-0.206029743",
"bikesAvailable": "2",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "661",
"name": "All Saints Church, Portobello",
"latitude": "51.51632095",
"longitude": "-0.202608612",
"bikesAvailable": "2",
"emptySlots": "35",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "662",
"name": "Phene Street, Chelsea",
"latitude": "51.48498496",
"longitude": "-0.167919869",
"bikesAvailable": "20",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "663",
"name": "Clarendon Road, Avondale",
"latitude": "51.51323001",
"longitude": "-0.211593602",
"bikesAvailable": "12",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "656",
"name": "Broomhouse Lane, Parsons Green",
"latitude": "51.46841875",
"longitude": "-0.199135704",
"bikesAvailable": "2",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "657",
"name": "Blythe Road West, Shepherd's Bush",
"latitude": "51.4996806",
"longitude": "-0.221791552",
"bikesAvailable": "2",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "658",
"name": "Ethelburga Estate, Battersea Park",
"latitude": "51.47729232",
"longitude": "-0.16478637",
"bikesAvailable": "1",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "659",
"name": "Grant Road West, Clapham Junction",
"latitude": "51.46437067",
"longitude": "-0.174619404",
"bikesAvailable": "23",
"emptySlots": "33",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "747",
"name": "Ormonde Gate, Chelsea",
"latitude": "51.48796408",
"longitude": "-0.161765173",
"bikesAvailable": "17",
"emptySlots": "7",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "746",
"name": "Lots Road, West Chelsea",
"latitude": "51.4795738",
"longitude": "-0.17903854",
"bikesAvailable": "9",
"emptySlots": "15",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "745",
"name": "Upcerne Road, West Chelsea",
"latitude": "51.47816972",
"longitude": "-0.18243547",
"bikesAvailable": "8",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "744",
"name": "Ingrave Street, Battersea",
"latitude": "51.46745485",
"longitude": "-0.172293499",
"bikesAvailable": "0",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "751",
"name": "Newton Street, Covent Garden",
"latitude": "51.51612862",
"longitude": "-0.120909408",
"bikesAvailable": "20",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "750",
"name": "Culvert Road, Battersea",
"latitude": "51.4710956",
"longitude": "-0.157850096",
"bikesAvailable": "2",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "749",
"name": "Haggerston Road, Haggerston ",
"latitude": "51.53932857",
"longitude": "-0.074284675",
"bikesAvailable": "16",
"emptySlots": "19",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "748",
"name": "Hertford Road, De Beauvoir Town",
"latitude": "51.53727795",
"longitude": "-0.079201849",
"bikesAvailable": "17",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "739",
"name": "Hortensia Road, West Brompton",
"latitude": "51.48176572",
"longitude": "-0.185273723",
"bikesAvailable": "4",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "738",
"name": "Imperial Road, Sands End",
"latitude": "51.47514228",
"longitude": "-0.187278987",
"bikesAvailable": "5",
"emptySlots": "32",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "737",
"name": "Fulham Broadway, Walham Green",
"latitude": "51.47993289",
"longitude": "-0.19411695",
"bikesAvailable": "6",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "736",
"name": "Queensdale Road, Shepherd's Bush",
"latitude": "51.50659035",
"longitude": "-0.216104479",
"bikesAvailable": "3",
"emptySlots": "27",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "743",
"name": "Oxford Road, Putney",
"latitude": "51.46079243",
"longitude": "-0.212607684",
"bikesAvailable": "9",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "742",
"name": "Blenheim Crescent, Ladbroke Grove",
"latitude": "51.51510818",
"longitude": "-0.208565479",
"bikesAvailable": "5",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "741",
"name": "Freston Road, Avondale",
"latitude": "51.5129814",
"longitude": "-0.219486603",
"bikesAvailable": "9",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "740",
"name": "Sirdar Road, Avondale",
"latitude": "51.51092871",
"longitude": "-0.214594781",
"bikesAvailable": "18",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "762",
"name": "Storey's Gate, Westminster",
"latitude": "51.50070305",
"longitude": "-0.129698963",
"bikesAvailable": "15",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "763",
"name": "Mile End Park Leisure Centre, Mile End",
"latitude": "51.52059714",
"longitude": "-0.032566533",
"bikesAvailable": "16",
"emptySlots": "31",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "760",
"name": "Rossmore Road, Marylebone",
"latitude": "51.52526975",
"longitude": "-0.163795009",
"bikesAvailable": "8",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "761",
"name": "Humbolt Road, Fulham",
"latitude": "51.48321729",
"longitude": "-0.211860644",
"bikesAvailable": "7",
"emptySlots": "20",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "766",
"name": "Ram Street, Wandsworth",
"latitude": "51.45752945",
"longitude": "-0.192165613",
"bikesAvailable": "17",
"emptySlots": "8",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "767",
"name": "Santos Road, Wandsworth",
"latitude": "51.45705988",
"longitude": "-0.200806304",
"bikesAvailable": "0",
"emptySlots": "30",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "764",
"name": "St. John's Road, Clapham Junction",
"latitude": "51.46239255",
"longitude": "-0.16829214",
"bikesAvailable": "16",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "765",
"name": "Ranelagh Gardens, Fulham",
"latitude": "51.46760141",
"longitude": "-0.20682737",
"bikesAvailable": "4",
"emptySlots": "33",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "754",
"name": "Grenfell Road, Avondale",
"latitude": "51.5129006",
"longitude": "-0.214762686",
"bikesAvailable": "7",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "755",
"name": "The Vale, Chelsea",
"latitude": "51.48512191",
"longitude": "-0.174971902",
"bikesAvailable": "12",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "752",
"name": "Manfred Road, East Putney",
"latitude": "51.45816465",
"longitude": "-0.20600248",
"bikesAvailable": "3",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "753",
"name": "Hammersmith Town Hall, Hammersmith",
"latitude": "51.49263658",
"longitude": "-0.234094148",
"bikesAvailable": "3",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "758",
"name": "Westbourne Park Road, Portobello",
"latitude": "51.51787005",
"longitude": "-0.201005397",
"bikesAvailable": "1",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "759",
"name": "Broadley Terrace, Marylebone",
"latitude": "51.52456169",
"longitude": "-0.165668686",
"bikesAvailable": "4",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "756",
"name": "Prince of Wales Drive, Battersea Park",
"latitude": "51.47515398",
"longitude": "-0.159169801",
"bikesAvailable": "0",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "757",
"name": "Harcourt Terrace, West Brompton",
"latitude": "51.48795853",
"longitude": "-0.187404506",
"bikesAvailable": "2",
"emptySlots": "22",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "713",
"name": "Hawley Crescent, Camden Town",
"latitude": "51.54100708",
"longitude": "-0.14326094",
"bikesAvailable": "22",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "712",
"name": "Mile End Stadium, Mile End",
"latitude": "51.51854104",
"longitude": "-0.034903714",
"bikesAvailable": "10",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "715",
"name": "Aylward Street, Stepney",
"latitude": "51.51563007",
"longitude": "-0.049067243",
"bikesAvailable": "6",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "714",
"name": "Stewart's Road, Nine Elms",
"latitude": "51.47311696",
"longitude": "-0.137235175",
"bikesAvailable": "17",
"emptySlots": "11",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "717",
"name": "Dunston Road , Haggerston",
"latitude": "51.53658514",
"longitude": "-0.075885686",
"bikesAvailable": "19",
"emptySlots": "23",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "716",
"name": "Stainsby Road , Poplar",
"latitude": "51.51542791",
"longitude": "-0.02356501",
"bikesAvailable": "3",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "719",
"name": "Victoria Park Road, Hackney Central",
"latitude": "51.53642464",
"longitude": "-0.054162264",
"bikesAvailable": "13",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "718",
"name": "Ada Street, Hackney Central",
"latitude": "51.53571683",
"longitude": "-0.060291813",
"bikesAvailable": "9",
"emptySlots": "35",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "705",
"name": "Upper Richmond Road, East Putney",
"latitude": "51.45971528",
"longitude": "-0.212145939",
"bikesAvailable": "4",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "704",
"name": "Mexfield Road, East Putney",
"latitude": "51.45682071",
"longitude": "-0.202802098",
"bikesAvailable": "1",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "707",
"name": "Barons Court Station, West Kensington",
"latitude": "51.49021762",
"longitude": "-0.215087092",
"bikesAvailable": "27",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "706",
"name": "Snowsfields, London Bridge",
"latitude": "51.50215353",
"longitude": "-0.083632928",
"bikesAvailable": "14",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "709",
"name": "Montserrat Road , Putney",
"latitude": "51.46321128",
"longitude": "-0.215550761",
"bikesAvailable": "14",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "708",
"name": "Disraeli Road, Putney",
"latitude": "51.46161068",
"longitude": "-0.21614583",
"bikesAvailable": "6",
"emptySlots": "25",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "711",
"name": "Everington Street, Fulham",
"latitude": "51.48335692",
"longitude": "-0.216305546",
"bikesAvailable": "8",
"emptySlots": "23",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "710",
"name": "Albert Bridge Road, Battersea Park",
"latitude": "51.47439218",
"longitude": "-0.163347594",
"bikesAvailable": "3",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "728",
"name": "Putney Bridge Road, East Putney",
"latitude": "51.46199911",
"longitude": "-0.206240805",
"bikesAvailable": "24",
"emptySlots": "5",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "729",
"name": "St. Peter's Terrace, Fulham",
"latitude": "51.47893931",
"longitude": "-0.208485293",
"bikesAvailable": "2",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "730",
"name": "Bridge Avenue, Hammersmith",
"latitude": "51.49208492",
"longitude": "-0.229116862",
"bikesAvailable": "14",
"emptySlots": "3",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "731",
"name": "Michael Road, Walham Green",
"latitude": "51.47727637",
"longitude": "-0.189210466",
"bikesAvailable": "0",
"emptySlots": "36",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "732",
"name": "Duke Street Hill, London Bridge",
"latitude": "51.50630441",
"longitude": "-0.087262995",
"bikesAvailable": "14",
"emptySlots": "2",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "733",
"name": "Park Lane, Mayfair",
"latitude": "51.50542628",
"longitude": "-0.150817316",
"bikesAvailable": "2",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "734",
"name": "Plough Terrace, Clapham Junction",
"latitude": "51.46230566",
"longitude": "-0.175407201",
"bikesAvailable": "2",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "735",
"name": "Grant Road East, Clapham Junction",
"latitude": "51.46489445",
"longitude": "-0.17302926",
"bikesAvailable": "24",
"emptySlots": "9",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "720",
"name": "Star Road, West Kensington",
"latitude": "51.48724429",
"longitude": "-0.205279052",
"bikesAvailable": "0",
"emptySlots": "24",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "721",
"name": "Wendon Street, Old Ford",
"latitude": "51.53603947",
"longitude": "-0.026262677",
"bikesAvailable": "4",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "722",
"name": "Finnis Street, Bethnal Green",
"latitude": "51.52458353",
"longitude": "-0.058631453",
"bikesAvailable": "5",
"emptySlots": "14",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "723",
"name": "Stephendale Road, Sands End",
"latitude": "51.46822047",
"longitude": "-0.190346493",
"bikesAvailable": "5",
"emptySlots": "43",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "724",
"name": "Alma Road, Wandsworth",
"latitude": "51.45799126",
"longitude": "-0.184806157",
"bikesAvailable": "1",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "725",
"name": "Thessaly Road North, Nine Elms",
"latitude": "51.47732253",
"longitude": "-0.138748723",
"bikesAvailable": "7",
"emptySlots": "21",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "726",
"name": "Alfreda Street, Battersea Park",
"latitude": "51.47505096",
"longitude": "-0.150908371",
"bikesAvailable": "3",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "727",
"name": "Chesilton Road, Fulham",
"latitude": "51.47569809",
"longitude": "-0.20587627",
"bikesAvailable": "4",
"emptySlots": "17",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "774",
"name": "Hurlingham Park, Parsons Green",
"latitude": "51.470131",
"longitude": "-0.20464",
"bikesAvailable": "10",
"emptySlots": "10",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "775",
"name": "Little Brook Green, Brook Green",
"latitude": "51.496664",
"longitude": "-0.223868",
"bikesAvailable": "3",
"emptySlots": "29",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "772",
"name": "Binfield Road, Stockwell",
"latitude": "51.47250956",
"longitude": "-0.122831913",
"bikesAvailable": "8",
"emptySlots": "26",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "773",
"name": "Tallis Street, Temple",
"latitude": "51.511891",
"longitude": "-0.107349",
"bikesAvailable": "22",
"emptySlots": "0",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "770",
"name": "Gwendwr Road, West Kensington",
"latitude": "51.491026",
"longitude": "-0.209121",
"bikesAvailable": "2",
"emptySlots": "28",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "771",
"name": "Rifle Place, Avondale",
"latitude": "51.509224",
"longitude": "-0.216016",
"bikesAvailable": "9",
"emptySlots": "12",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "768",
"name": "Clapham Common Northside, Clapham Common",
"latitude": "51.46134382",
"longitude": "-0.159322467",
"bikesAvailable": "2",
"emptySlots": "34",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "769",
"name": "Sandilands Road, Walham Green",
"latitude": "51.473611",
"longitude": "-0.191803",
"bikesAvailable": "5",
"emptySlots": "16",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "776",
"name": "Abyssinia Close, Clapham Junction",
"latitude": "51.460333",
"longitude": "-0.167029",
"bikesAvailable": "2",
"emptySlots": "18",
"installed": "true",
"locked": "false",
"temporary": "false"
},
{
"@ID": "777",
"name": "Limburg Road, Clapham Common",
"latitude": "51.4619230679",
"longitude": "-0.165297856693",
"bikesAvailable": "16",
"emptySlots": "4",
"installed": "true",
"locked": "false",
"temporary": "false"
}
]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Graph map</title>
<meta charset="utf-8" />
<style type="text/css">
svg {
font: 10px sans-serif;
}
.axis path, .axis line {
fill: none;
stroke: #666;
stroke-width: 0.3;
}
path {
stroke: #fff;
}
circle.station {
stroke-width: 0.5;
}
.voronoi path {
stroke: #aaa;
}
circle {
fill: #000;
pointer-events: none;
}
.q0-9 { fill: #d3d3d3;}
.q1-9 { fill: #efefef; }
.q2-9 { fill: #fefefe; }
.q3-9 { fill: #eeeeee; }
.q4-9 { fill: #dedede; }
.q5-9 { fill: #d0d0d0; }
.q6-9 { fill: #eaeaea; }
.q7-9 { fill: #e9e9e9; }
.q8-9 { fill: #f2f2f2; }
</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript" src="tubemaps.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.js"></script>
<script type="text/javascript">
function polygon(d) {
return "M" + d.join("L") + "Z";
}
var margin = {top: 20, right: 20, bottom: 30, left: 40},
w = Math.max(760, window.innerWidth) - margin.left - margin.right,
h = Math.max(500, window.innerHeight) - margin.top - margin.bottom;
var voronoi = d3.geom.voronoi()
.clipExtent([[0, 0], [w, h]]);
d3.json('london.json', function(data) {
d3.json('bikes.json', function(bikes) {
bikes.forEach(function(b) {
b.latitude = +b.latitude;
b.longitude = +b.longitude;
})
data.stations.forEach(function(d) {
d.longitude = +d.longitude;
d.latitude = +d.latitude;
})
var tube = new TubeMaps.TubeMap(data)
var closures = [];
closures = closures.concat(tube.path(tube.getStationByName("Euston"), tube.getStationByName("Victoria")));
closures = closures.concat(tube.path(tube.getStationByName("West Ruislip"), tube.getStationByName("North Acton")));
closures = closures.concat(tube.path(tube.getStationByName("Tottenham Hale"), tube.getStationByName("Finsbury Park")));
var closuresById = {};
closures.forEach(function(d) {
if (!(d.station1.id in closuresById)) {
closuresById[d.station1.id] = d.station1
}
if (!(d.station2.id in closuresById)) {
closuresById[d.station2.id] = d.station2
}
})
// Find min and max long and lat
// var minLat = d3.min(bikes, function(d) {return d.latitude});
// var minLon = d3.min(bikes, function(d) {return d.longitude});
// var maxLat = d3.max(bikes, function(d) {return d.latitude});
// var maxLon = d3.max(bikes, function(d) {return d.longitude});
var minLat = d3.min(tube.stations, function(d) {return d.latitude});
var minLon = d3.min(tube.stations, function(d) {return d.longitude});
var maxLat = d3.max(tube.stations, function(d) {return d.latitude});
var maxLon = d3.max(tube.stations, function(d) {return d.longitude});
// Set up the scales
var x = d3.scale.linear()
.domain([minLon, maxLon])
.range([0, w]);
var y = d3.scale.linear()
.domain([minLat, maxLat])
.range([h, 0]);
// Set up the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-h);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickSize(-w);
// Set up what will happen when zooming
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
/*
Drawing from now on
*/
// Setting up the canvas
var vis = d3.select("#map").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
// Make sure it is zoomable
d3.select("#map svg")
.call(zoom);
var voronoiMap = vis.append("g").attr('class','voronoi').selectAll("path");
var stations = tube.stations.map(function(d) {
return [x(d.longitude), y(d.latitude)]
})
var voronoiData = voronoi(stations);
var mapped = []
var voronoiColors = {};
tube.stations.forEach(function(station, i) {
if (station.id in closuresById) {
// console.log(closuresById[station.id])
voronoiColors[i] = closuresById[station.id].line;
console.log(voronoiColors[i])
mapped.push(voronoiData[i])
}
})
voronoiMap = voronoiMap
.data(voronoiData, polygon);
voronoiMap.exit().remove();
voronoiMap.enter().append("path")
.attr("class", function(d, i) {
return "q" + (i % 9) + "-9";
})
.style('fill', function(d, i) {
if (i in voronoiColors) {
return '#'+tube.linesById[voronoiColors[i]].colour;
}
})
.style('opacity', function(d, i) {
return 0.3;
})
.attr("d", polygon);
voronoiMap.order();
// Drawing lines between stations
var route = vis.selectAll("line.route")
.data(tube.connections)
.enter().append("svg:line")
.attr("class", "route")
.attr("stroke", function(d) { return '#'+tube.linesById[d.line].colour; })
.attr("stroke-linecap", 'round')
.attr("x1", function(d) { return x(d.station1.longitude); })
.attr("y1", function(d) { return y(d.station1.latitude); })
.attr("x2", function(d) { return x(d.station2.longitude); })
.attr("y2", function(d) { return y(d.station2.latitude); })
.style("opacity", 1)
// Drawing routes
var closure = vis.selectAll("line.closure")
.data(closures)
.enter().append("svg:line")
.attr("class", "route closure")
.attr("stroke", function(d) { return '#'+tube.linesById[d.line || d.station1.line].colour; })
.attr("stroke-linecap", 'round')
.attr("x1", function(d) { return x(d.station1.longitude); })
.attr("y1", function(d) { return y(d.station1.latitude); })
.attr("x2", function(d) { return x(d.station2.longitude); })
.attr("y2", function(d) { return y(d.station2.latitude); })
var bike = vis.selectAll("circle.bikes")
.data(bikes)
.enter().append("svg:circle")
.attr("class", "bikes")
.attr("cx", function(d) { return x(d.longitude); })
.attr("cy", function(d) { return y(d.latitude); })
.style("fill", 'blue')
.style("stroke", 'black')
.style("opacity", 0.4)
// Striped stations (see official map)
var stripe = vis.selectAll("line.stripe")
.data(tube.connections.filter(function(d) {
return tube.linesById[d.line].stripe != "NULL";
}))
.enter().append("svg:line")
.attr("class", "stripe")
.attr("stroke", function(d) { return '#'+tube.linesById[d.line].stripe; })
.attr("stroke-linecap", 'round')
.attr("x1", function(d) { return x(d.station1.longitude); })
.attr("y1", function(d) { return y(d.station1.latitude); })
.attr("x2", function(d) { return x(d.station2.longitude); })
.attr("y2", function(d) { return y(d.station2.latitude); })
// Drawing all the stations
var station = vis.selectAll("circle.station")
.data(tube.stations)
.enter().append("svg:circle")
.attr("class", "station")
.attr("id", function(d) { return 'station'+d.id })
.attr("cx", function(d) { return x(d.longitude); })
.attr("cy", function(d) { return y(d.latitude); })
.attr("data-cx", function(d) { return d.longitude; })
.attr("data-cy", function(d) { return d.latitude; })
.attr("title", function(d) { return d.name })
.style("stroke", 'gray')
.style("fill", '#ffffff')
.style("opacity", 1)
.on('mouseover', function(d,i) {
d3.selectAll('#station'+d.id)
.transition()
.duration(25)
.attr("r", 3 / zoom.scale())
.style("stroke", 'black')
.style("stroke-width", 1 / zoom.scale())
.style('opacity', 1);
})
.on('mouseout', function(d,i) {
d3.selectAll('#station'+d.id)
.transition()
.attr("r", 2.5 / zoom.scale())
.duration(25)
.style("stroke-width", 0.5 / zoom.scale())
.style("stroke", 'gray')
.style('opacity', 0.3);
})
// .on('click', selectStation);
// Adding axis
vis.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
vis.append("g")
.attr("class", "y axis")
.call(yAxis);
zoomed()
function zoomed() {
// Reset axis
vis.select(".x.axis").call(xAxis);
vis.select(".y.axis").call(yAxis);
// Rescale circles
vis.selectAll("circle")
.attr("transform", "translate(" + zoom.translate() + ")scale(" + zoom.scale() + ")")
.style("stroke-width", 1 / zoom.scale())
.attr("r", 2.5 / zoom.scale());
// Rescale lines
vis.selectAll("line.route, line.stripe")
.attr("transform", "translate(" + zoom.translate() + ")scale(" + zoom.scale() + ")")
vis.selectAll("line.route")
.attr("stroke-width", 1 / (zoom.scale()))
vis.selectAll("line.stripe")
.attr("stroke-width", 0.8 / (zoom.scale()))
vis.selectAll("line.closure")
.attr("stroke-width", 4 / (zoom.scale()))
// Voronoi scale
vis.selectAll("g.voronoi")
.attr("transform", "translate(" + zoom.translate() + ")scale(" + zoom.scale() + ")")
vis.selectAll(".voronoi path")
.attr("stroke-width", 0.5 / (zoom.scale()))
}
});
});
</script>
</body>
</html>
{"connections":[{"station1":"11","station2":"163","line":"1","time":"1"},{"station1":"11","station2":"212","line":"1","time":"2"},{"station1":"49","station2":"87","line":"1","time":"1"},{"station1":"49","station2":"197","line":"1","time":"2"},{"station1":"82","station2":"163","line":"1","time":"2"},{"station1":"82","station2":"193","line":"1","time":"3"},{"station1":"84","station2":"148","line":"1","time":"3"},{"station1":"87","station2":"279","line":"1","time":"2"},{"station1":"113","station2":"246","line":"1","time":"2"},{"station1":"113","station2":"298","line":"1","time":"2"},{"station1":"114","station2":"140","line":"1","time":"2"},{"station1":"137","station2":"206","line":"1","time":"3"},{"station1":"137","station2":"298","line":"1","time":"3"},{"station1":"140","station2":"237","line":"1","time":"2"},{"station1":"143","station2":"159","line":"1","time":"2"},{"station1":"143","station2":"206","line":"1","time":"2"},{"station1":"148","station2":"279","line":"1","time":"1"},{"station1":"159","station2":"278","line":"1","time":"1"},{"station1":"185","station2":"237","line":"1","time":"2"},{"station1":"185","station2":"281","line":"1","time":"2"},{"station1":"192","station2":"197","line":"1","time":"2"},{"station1":"192","station2":"212","line":"1","time":"2"},{"station1":"193","station2":"278","line":"1","time":"2"},{"station1":"246","station2":"281","line":"1","time":"3"},{"station1":"13","station2":"156","line":"2","time":"2"},{"station1":"13","station2":"250","line":"2","time":"2"},{"station1":"16","station2":"91","line":"2","time":"2"},{"station1":"16","station2":"173","line":"2","time":"2"},{"station1":"24","station2":"156","line":"2","time":"3"},{"station1":"24","station2":"164","line":"2","time":"2"},{"station1":"28","station2":"162","line":"2","time":"1"},{"station1":"28","station2":"192","line":"2","time":"1"},{"station1":"37","station2":"158","line":"2","time":"3"},{"station1":"37","station2":"301","line":"2","time":"3"},{"station1":"48","station2":"126","line":"2","time":"1"},{"station1":"48","station2":"250","line":"2","time":"2"},{"station1":"51","station2":"103","line":"2","time":"2"},{"station1":"51","station2":"215","line":"2","time":"2"},{"station1":"68","station2":"158","line":"2","time":"2"},{"station1":"68","station2":"256","line":"2","time":"3"},{"station1":"72","station2":"286","line":"2","time":"3"},{"station1":"76","station2":"181","line":"2","time":"2"},{"station1":"76","station2":"296","line":"2","time":"3"},{"station1":"88","station2":"256","line":"2","time":"2"},{"station1":"91","station2":"109","line":"2","time":"2"},{"station1":"98","station2":"173","line":"2","time":"3"},{"station1":"98","station2":"211","line":"2","time":"2"},{"station1":"103","station2":"109","line":"2","time":"3"},{"station1":"105","station2":"177","line":"2","time":"2"},{"station1":"105","station2":"196","line":"2","time":"2"},{"station1":"112","station2":"181","line":"2","time":"3"},{"station1":"112","station2":"196","line":"2","time":"2"},{"station1":"126","station2":"259","line":"2","time":"2"},{"station1":"127","station2":"186","line":"2","time":"2"},{"station1":"127","station2":"226","line":"2","time":"1"},{"station1":"149","station2":"162","line":"2","time":"3"},{"station1":"149","station2":"208","line":"2","time":"1"},{"station1":"153","station2":"154","line":"2","time":"3"},{"station1":"153","station2":"247","line":"2","time":"2"},{"station1":"154","station2":"230","line":"2","time":"2"},{"station1":"154","station2":"275","line":"2","time":"2"},{"station1":"164","station2":"247","line":"2","time":"4"},{"station1":"177","station2":"239","line":"2","time":"3"},{"station1":"181","station2":"286","line":"2","time":"2"},{"station1":"186","station2":"208","line":"2","time":"2"},{"station1":"192","station2":"259","line":"2","time":"2"},{"station1":"211","station2":"275","line":"2","time":"2"},{"station1":"215","station2":"301","line":"2","time":"3"},{"station1":"221","station2":"239","line":"2","time":"1"},{"station1":"221","station2":"294","line":"2","time":"3"},{"station1":"226","station2":"296","line":"2","time":"3"},{"station1":"230","station2":"241","line":"2","time":"2"},{"station1":"241","station2":"301","line":"2","time":"2"},{"station1":"2","station2":"156","line":"3","time":"2"},{"station1":"2","station2":"263","line":"3","time":"4"},{"station1":"11","station2":"83","line":"3","time":"3"},{"station1":"11","station2":"104","line":"3","time":"3"},{"station1":"14","station2":"92","line":"3","time":"1"},{"station1":"14","station2":"167","line":"3","time":"2"},{"station1":"18","station2":"186","line":"3","time":"2"},{"station1":"18","station2":"193","line":"3","time":"2"},{"station1":"25","station2":"161","line":"3","time":"1"},{"station1":"25","station2":"255","line":"3","time":"2"},{"station1":"44","station2":"161","line":"3","time":"1"},{"station1":"44","station2":"166","line":"3","time":"2"},{"station1":"83","station2":"193","line":"3","time":"3"},{"station1":"87","station2":"255","line":"3","time":"2"},{"station1":"87","station2":"285","line":"3","time":"2"},{"station1":"90","station2":"104","line":"3","time":"2"},{"station1":"90","station2":"145","line":"3","time":"2"},{"station1":"92","station2":"145","line":"3","time":"4"},{"station1":"99","station2":"122","line":"3","time":"4"},{"station1":"99","station2":"236","line":"3","time":"1"},{"station1":"122","station2":"186","line":"3","time":"3"},{"station1":"156","station2":"167","line":"3","time":"2"},{"station1":"166","station2":"263","line":"3","time":"2"},{"station1":"229","station2":"236","line":"3","time":"2"},{"station1":"229","station2":"273","line":"3","time":"2"},{"station1":"248","station2":"273","line":"3","time":"2"},{"station1":"248","station2":"285","line":"3","time":"2"},{"station1":"3","station2":"263","line":"4","time":"2"},{"station1":"3","station2":"295","line":"4","time":"2"},{"station1":"15","station2":"78","line":"4","time":"4"},{"station1":"15","station2":"269","line":"4","time":"2"},{"station1":"17","station2":"110","line":"4","time":"1"},{"station1":"17","station2":"293","line":"4","time":"2"},{"station1":"18","station2":"186","line":"4","time":"2"},{"station1":"18","station2":"193","line":"4","time":"2"},{"station1":"21","station2":"67","line":"4","time":"3"},{"station1":"21","station2":"269","line":"4","time":"2"},{"station1":"25","station2":"161","line":"4","time":"1"},{"station1":"25","station2":"255","line":"4","time":"2"},{"station1":"33","station2":"36","line":"4","time":"2"},{"station1":"33","station2":"164","line":"4","time":"1"},{"station1":"36","station2":"289","line":"4","time":"2"},{"station1":"44","station2":"161","line":"4","time":"1"},{"station1":"44","station2":"166","line":"4","time":"2"},{"station1":"52","station2":"1","line":"4","time":"2"},{"station1":"52","station2":"265","line":"4","time":"2"},{"station1":"66","station2":"67","line":"4","time":"4"},{"station1":"66","station2":"85","line":"4","time":"3"},{"station1":"72","station2":"73","line":"4","time":"4"},{"station1":"73","station2":"1","line":"4","time":"2"},{"station1":"74","station2":"99","line":"4","time":"3"},{"station1":"74","station2":"122","line":"4","time":"3"},{"station1":"74","station2":"138","line":"4","time":"2"},{"station1":"74","station2":"287","line":"4","time":"2"},{"station1":"74","station2":"293","line":"4","time":"1"},{"station1":"78","station2":"270","line":"4","time":"2"},{"station1":"80","station2":"205","line":"4","time":"2"},{"station1":"80","station2":"231","line":"4","time":"2"},{"station1":"83","station2":"193","line":"4","time":"3"},{"station1":"85","station2":"129","line":"4","time":"2"},{"station1":"87","station2":"255","line":"4","time":"2"},{"station1":"87","station2":"285","line":"4","time":"2"},{"station1":"96","station2":"195","line":"4","time":"2"},{"station1":"96","station2":"287","line":"4","time":"1"},{"station1":"99","station2":"236","line":"4","time":"1"},{"station1":"108","station2":"141","line":"4","time":"3"},{"station1":"108","station2":"265","line":"4","time":"3"},{"station1":"110","station2":"209","line":"4","time":"2"},{"station1":"122","station2":"186","line":"4","time":"3"},{"station1":"129","station2":"268","line":"4","time":"2"},{"station1":"141","station2":"213","line":"4","time":"3"},{"station1":"164","station2":"244","line":"4","time":"2"},{"station1":"166","station2":"263","line":"4","time":"2"},{"station1":"195","station2":"205","line":"4","time":"3"},{"station1":"200","station2":"270","line":"4","time":"2"},{"station1":"200","station2":"289","line":"4","time":"2"},{"station1":"209","station2":"242","line":"4","time":"2"},{"station1":"229","station2":"236","line":"4","time":"2"},{"station1":"229","station2":"273","line":"4","time":"2"},{"station1":"231","station2":"300","line":"4","time":"3"},{"station1":"242","station2":"265","line":"4","time":"1"},{"station1":"244","station2":"295","line":"4","time":"3"},{"station1":"248","station2":"273","line":"4","time":"2"},{"station1":"248","station2":"285","line":"4","time":"2"},{"station1":"267","station2":"268","line":"4","time":"3"},{"station1":"299","station2":"300","line":"4","time":"3"},{"station1":"4","station2":"70","line":"13","time":"2"},{"station1":"4","station2":"201","line":"13","time":"2"},{"station1":"13","station2":"225","line":"13","time":"2"},{"station1":"19","station2":"97","line":"13","time":"2"},{"station1":"20","station2":"65","line":"13","time":"2"},{"station1":"20","station2":"217","line":"13","time":"2"},{"station1":"27","station2":"79","line":"13","time":"2"},{"station1":"27","station2":"201","line":"13","time":"2"},{"station1":"32","station2":"70","line":"13","time":"2"},{"station1":"32","station2":"204","line":"13","time":"2"},{"station1":"42","station2":"120","line":"13","time":"2"},{"station1":"42","station2":"292","line":"13","time":"2"},{"station1":"43","station2":"79","line":"13","time":"2"},{"station1":"43","station2":"219","line":"13","time":"2"},{"station1":"61","station2":"171","line":"13","time":"2"},{"station1":"61","station2":"238","line":"13","time":"2"},{"station1":"63","station2":"203","line":"13","time":"2"},{"station1":"63","station2":"219","line":"13","time":"2"},{"station1":"64","station2":"106","line":"13","time":"2"},{"station1":"64","station2":"135","line":"13","time":"2"},{"station1":"65","station2":"97","line":"13","time":"2"},{"station1":"69","station2":"86","line":"13","time":"2"},{"station1":"69","station2":"106","line":"13","time":"2"},{"station1":"86","station2":"152","line":"13","time":"2"},{"station1":"120","station2":"238","line":"13","time":"2"},{"station1":"135","station2":"171","line":"13","time":"2"},{"station1":"155","station2":"225","line":"13","time":"2"},{"station1":"155","station2":"284","line":"13","time":"2"},{"station1":"201","station2":"284","line":"13","time":"2"},{"station1":"201","station2":"292","line":"13","time":"2"},{"station1":"203","station2":"217","line":"13","time":"2"},{"station1":"204","station2":"247","line":"13","time":"2"},{"station1":"225","station2":"262","line":"13","time":"2"},{"station1":"284","station2":"292","line":"13","time":"2"},{"station1":"41","station2":"216","line":"5","time":"1"},{"station1":"41","station2":"253","line":"5","time":"2"},{"station1":"174","station2":"253","line":"5","time":"4"},{"station1":"175","station2":"253","line":"5","time":"4"},{"station1":"216","station2":"276","line":"5","time":"1"},{"station1":"225","station2":"276","line":"5","time":"1"},{"station1":"225","station2":"295","line":"5","time":"2"},{"station1":"228","station2":"295","line":"5","time":"2"},{"station1":"3","station2":"156","line":"6","time":"4"},{"station1":"3","station2":"295","line":"6","time":"2"},{"station1":"11","station2":"83","line":"6","time":"3"},{"station1":"11","station2":"104","line":"6","time":"3"},{"station1":"14","station2":"92","line":"6","time":"1"},{"station1":"14","station2":"167","line":"6","time":"2"},{"station1":"15","station2":"78","line":"6","time":"4"},{"station1":"33","station2":"36","line":"6","time":"2"},{"station1":"33","station2":"164","line":"6","time":"1"},{"station1":"36","station2":"289","line":"6","time":"2"},{"station1":"78","station2":"270","line":"6","time":"2"},{"station1":"83","station2":"193","line":"6","time":"4"},{"station1":"90","station2":"104","line":"6","time":"2"},{"station1":"90","station2":"145","line":"6","time":"2"},{"station1":"92","station2":"145","line":"6","time":"4"},{"station1":"101","station2":"110","line":"6","time":"2"},{"station1":"101","station2":"227","line":"6","time":"1"},{"station1":"147","station2":"150","line":"6","time":"1"},{"station1":"147","station2":"283","line":"6","time":"2"},{"station1":"150","station2":"227","line":"6","time":"2"},{"station1":"156","station2":"167","line":"6","time":"2"},{"station1":"164","station2":"244","line":"6","time":"2"},{"station1":"193","station2":"218","line":"6","time":"1"},{"station1":"200","station2":"270","line":"6","time":"2"},{"station1":"200","station2":"289","line":"6","time":"2"},{"station1":"218","station2":"283","line":"6","time":"2"},{"station1":"244","station2":"295","line":"6","time":"3"},{"station1":"11","station2":"28","line":"7","time":"2"},{"station1":"11","station2":"249","line":"7","time":"4"},{"station1":"23","station2":"41","line":"7","time":"2"},{"station1":"23","station2":"157","line":"7","time":"3"},{"station1":"28","station2":"107","line":"7","time":"2"},{"station1":"41","station2":"42","line":"7","time":"3"},{"station1":"42","station2":"183","line":"7","time":"3"},{"station1":"43","station2":"183","line":"7","time":"3"},{"station1":"43","station2":"289","line":"7","time":"3"},{"station1":"45","station2":"207","line":"7","time":"2"},{"station1":"45","station2":"243","line":"7","time":"2"},{"station1":"71","station2":"172","line":"7","time":"2"},{"station1":"71","station2":"297","line":"7","time":"2"},{"station1":"94","station2":"254","line":"7","time":"2"},{"station1":"94","station2":"290","line":"7","time":"1"},{"station1":"107","station2":"285","line":"7","time":"3"},{"station1":"142","station2":"290","line":"7","time":"2"},{"station1":"142","station2":"297","line":"7","time":"2"},{"station1":"144","station2":"207","line":"7","time":"2"},{"station1":"144","station2":"282","line":"7","time":"4"},{"station1":"157","station2":"233","line":"7","time":"2"},{"station1":"172","station2":"282","line":"7","time":"4"},{"station1":"233","station2":"279","line":"7","time":"1"},{"station1":"247","station2":"289","line":"7","time":"3"},{"station1":"249","station2":"254","line":"7","time":"1"},{"station1":"279","station2":"285","line":"7","time":"2"},{"station1":"2","station2":"156","line":"8","time":"2"},{"station1":"6","station2":"46","line":"8","time":"4"},{"station1":"11","station2":"94","line":"8","time":"6"},{"station1":"11","station2":"104","line":"8","time":"3"},{"station1":"14","station2":"92","line":"8","time":"1"},{"station1":"14","station2":"167","line":"8","time":"2"},{"station1":"46","station2":"50","line":"8","time":"8"},{"station1":"46","station2":"53","line":"8","time":"4"},{"station1":"53","station2":"214","line":"8","time":"4"},{"station1":"62","station2":"168","line":"8","time":"4"},{"station1":"62","station2":"280","line":"8","time":"3"},{"station1":"75","station2":"210","line":"8","time":"2"},{"station1":"75","station2":"222","line":"8","time":"2"},{"station1":"90","station2":"104","line":"8","time":"2"},{"station1":"90","station2":"145","line":"8","time":"2"},{"station1":"92","station2":"145","line":"8","time":"4"},{"station1":"94","station2":"282","line":"8","time":"7"},{"station1":"115","station2":"178","line":"8","time":"2"},{"station1":"115","station2":"184","line":"8","time":"3"},{"station1":"115","station2":"291","line":"8","time":"2"},{"station1":"125","station2":"134","line":"8","time":"2"},{"station1":"125","station2":"271","line":"8","time":"3"},{"station1":"134","station2":"220","line":"8","time":"3"},{"station1":"156","station2":"167","line":"8","time":"2"},{"station1":"168","station2":"179","line":"8","time":"3"},{"station1":"168","station2":"214","line":"8","time":"4"},{"station1":"178","station2":"202","line":"8","time":"2"},{"station1":"179","station2":"180","line":"8","time":"2"},{"station1":"180","station2":"199","line":"8","time":"2"},{"station1":"184","station2":"199","line":"8","time":"3"},{"station1":"202","station2":"282","line":"8","time":"3"},{"station1":"210","station2":"291","line":"8","time":"3"},{"station1":"220","station2":"222","line":"8","time":"2"},{"station1":"7","station2":"145","line":"9","time":"2"},{"station1":"7","station2":"188","line":"9","time":"3"},{"station1":"8","station2":"124","line":"9","time":"3"},{"station1":"8","station2":"264","line":"9","time":"2"},{"station1":"12","station2":"56","line":"9","time":"2"},{"station1":"12","station2":"257","line":"9","time":"1"},{"station1":"13","station2":"157","line":"9","time":"2"},{"station1":"13","station2":"167","line":"9","time":"3"},{"station1":"22","station2":"47","line":"9","time":"2"},{"station1":"22","station2":"111","line":"9","time":"2"},{"station1":"29","station2":"84","line":"9","time":"1"},{"station1":"29","station2":"157","line":"9","time":"2"},{"station1":"34","station2":"100","line":"9","time":"3"},{"station1":"34","station2":"119","line":"9","time":"2"},{"station1":"38","station2":"58","line":"9","time":"2"},{"station1":"38","station2":"81","line":"9","time":"3"},{"station1":"40","station2":"47","line":"9","time":"2"},{"station1":"40","station2":"89","line":"9","time":"3"},{"station1":"40","station2":"139","line":"9","time":"2"},{"station1":"40","station2":"170","line":"9","time":"1"},{"station1":"49","station2":"87","line":"9","time":"1"},{"station1":"49","station2":"151","line":"9","time":"2"},{"station1":"54","station2":"55","line":"9","time":"2"},{"station1":"54","station2":"56","line":"9","time":"2"},{"station1":"55","station2":"245","line":"9","time":"1"},{"station1":"58","station2":"119","line":"9","time":"3"},{"station1":"59","station2":"240","line":"9","time":"2"},{"station1":"59","station2":"258","line":"9","time":"2"},{"station1":"77","station2":"93","line":"9","time":"4"},{"station1":"77","station2":"124","line":"9","time":"2"},{"station1":"84","station2":"136","line":"9","time":"2"},{"station1":"87","station2":"279","line":"9","time":"2"},{"station1":"89","station2":"145","line":"9","time":"2"},{"station1":"89","station2":"170","line":"9","time":"2"},{"station1":"89","station2":"277","line":"9","time":"1"},{"station1":"93","station2":"165","line":"9","time":"3"},{"station1":"93","station2":"288","line":"9","time":"2"},{"station1":"100","station2":"111","line":"9","time":"4"},{"station1":"102","station2":"259","line":"9","time":"1"},{"station1":"102","station2":"277","line":"9","time":"2"},{"station1":"121","station2":"261","line":"9","time":"3"},{"station1":"136","station2":"191","line":"9","time":"2"},{"station1":"136","station2":"279","line":"9","time":"3"},{"station1":"139","station2":"264","line":"9","time":"2"},{"station1":"151","station2":"259","line":"9","time":"1"},{"station1":"167","station2":"188","line":"9","time":"1"},{"station1":"169","station2":"240","line":"9","time":"4"},{"station1":"191","station2":"245","line":"9","time":"3"},{"station1":"257","station2":"258","line":"9","time":"2"},{"station1":"261","station2":"302","line":"9","time":"3"},{"station1":"288","station2":"302","line":"9","time":"1"},{"station1":"1","station2":"73","line":"10","time":"2"},{"station1":"1","station2":"234","line":"10","time":"4"},{"station1":"1","station2":"265","line":"10","time":"3"},{"station1":"5","station2":"194","line":"10","time":"3"},{"station1":"5","station2":"252","line":"10","time":"2"},{"station1":"9","station2":"31","line":"10","time":"3"},{"station1":"9","station2":"232","line":"10","time":"3"},{"station1":"10","station2":"95","line":"10","time":"2"},{"station1":"10","station2":"128","line":"10","time":"1"},{"station1":"17","station2":"74","line":"10","time":"3"},{"station1":"17","station2":"110","line":"10","time":"2"},{"station1":"30","station2":"176","line":"10","time":"2"},{"station1":"30","station2":"190","line":"10","time":"3"},{"station1":"31","station2":"303","line":"10","time":"2"},{"station1":"39","station2":"128","line":"10","time":"2"},{"station1":"39","station2":"145","line":"10","time":"5"},{"station1":"57","station2":"187","line":"10","time":"4"},{"station1":"60","station2":"126","line":"10","time":"1"},{"station1":"60","station2":"151","line":"10","time":"1"},{"station1":"73","station2":"182","line":"10","time":"3"},{"station1":"74","station2":"99","line":"10","time":"2"},{"station1":"75","station2":"210","line":"10","time":"2"},{"station1":"75","station2":"222","line":"10","time":"2"},{"station1":"95","station2":"160","line":"10","time":"2"},{"station1":"99","station2":"236","line":"10","time":"1"},{"station1":"107","station2":"133","line":"10","time":"2"},{"station1":"107","station2":"197","line":"10","time":"1"},{"station1":"110","station2":"265","line":"10","time":"2"},{"station1":"116","station2":"117","line":"10","time":"3"},{"station1":"116","station2":"118","line":"10","time":"3"},{"station1":"116","station2":"132","line":"10","time":"4"},{"station1":"117","station2":"118","line":"10","time":"5"},{"station1":"125","station2":"134","line":"10","time":"2"},{"station1":"125","station2":"271","line":"10","time":"3"},{"station1":"126","station2":"223","line":"10","time":"2"},{"station1":"130","station2":"131","line":"10","time":"2"},{"station1":"130","station2":"132","line":"10","time":"2"},{"station1":"131","station2":"190","line":"10","time":"2"},{"station1":"133","station2":"146","line":"10","time":"2"},{"station1":"134","station2":"220","line":"10","time":"3"},{"station1":"145","station2":"223","line":"10","time":"2"},{"station1":"146","station2":"236","line":"10","time":"3"},{"station1":"151","station2":"197","line":"10","time":"2"},{"station1":"160","station2":"266","line":"10","time":"3"},{"station1":"176","station2":"234","line":"10","time":"1"},{"station1":"182","station2":"194","line":"10","time":"2"},{"station1":"187","station2":"232","line":"10","time":"3"},{"station1":"210","station2":"235","line":"10","time":"3"},{"station1":"220","station2":"222","line":"10","time":"2"},{"station1":"235","station2":"251","line":"10","time":"2"},{"station1":"251","station2":"252","line":"10","time":"3"},{"station1":"266","station2":"303","line":"10","time":"2"},{"station1":"26","station2":"260","line":"11","time":"2"},{"station1":"26","station2":"274","line":"11","time":"2"},{"station1":"35","station2":"245","line":"11","time":"2"},{"station1":"89","station2":"145","line":"11","time":"2"},{"station1":"89","station2":"277","line":"11","time":"1"},{"station1":"95","station2":"123","line":"11","time":"2"},{"station1":"95","station2":"224","line":"11","time":"4"},{"station1":"107","station2":"192","line":"11","time":"2"},{"station1":"107","station2":"273","line":"11","time":"2"},{"station1":"123","station2":"145","line":"11","time":"4"},{"station1":"192","station2":"277","line":"11","time":"2"},{"station1":"198","station2":"272","line":"11","time":"1"},{"station1":"198","station2":"273","line":"11","time":"3"},{"station1":"224","station2":"260","line":"11","time":"3"},{"station1":"245","station2":"272","line":"11","time":"3"},{"station1":"13","station2":"279","line":"12","time":"4"}],"lines":[{"line":"1","name":"Bakerloo Line","colour":"AE6017","stripe":"NULL"},{"line":"3","name":"Circle Line","colour":"FFE02B","stripe":"NULL"},{"line":"6","name":"Hammersmith & City Line","colour":"F491A8","stripe":"NULL"},{"line":"7","name":"Jubilee Line","colour":"949699","stripe":"NULL"},{"line":"11","name":"Victoria Line","colour":"0A9CDA","stripe":"NULL"},{"line":"2","name":"Central Line","colour":"F15B2E","stripe":"NULL"},{"line":"4","name":"District Line","colour":"00A166","stripe":"NULL"},{"line":"5","name":"East London Line","colour":"FBAE34","stripe":"NULL"},{"line":"8","name":"Metropolitan Line","colour":"91005A","stripe":"NULL"},{"line":"9","name":"Northern Line","colour":"000000","stripe":"NULL"},{"line":"10","name":"Piccadilly Line","colour":"094FA3","stripe":"NULL"},{"line":"12","name":"Waterloo & City Line","colour":"88D0C4","stripe":"NULL"},{"line":"13","name":"Docklands Light Railway","colour":"00A77E","stripe":"FFFFFF"}],"stations":[{"id":"1","latitude":"51.5028","longitude":"-0.2801","name":"Acton Town","display_name":"Acton<br />Town","zone":"3","total_lines":"2","rail":"0"},{"id":"2","latitude":"51.5143","longitude":"-0.0755","name":"Aldgate","display_name":"NULL","zone":"1","total_lines":"2","rail":"0"},{"id":"3","latitude":"51.5154","longitude":"-0.0726","name":"Aldgate East","display_name":"Aldgate<br />East","zone":"1","total_lines":"2","rail":"0"},{"id":"4","latitude":"51.5107","longitude":"-0.013","name":"All Saints","display_name":"All<br />Saints","zone":"2","total_lines":"1","rail":"0"},{"id":"5","latitude":"51.5407","longitude":"-0.2997","name":"Alperton","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"7","latitude":"51.5322","longitude":"-0.1058","name":"Angel","display_name":"NULL","zone":"1","total_lines":"1","rail":"0"},{"id":"8","latitude":"51.5653","longitude":"-0.1353","name":"Archway","display_name":"NULL","zone":"2.5","total_lines":"1","rail":"0"},{"id":"9","latitude":"51.6164","longitude":"-0.1331","name":"Arnos Grove","display_name":"Arnos<br />Grove","zone":"4","total_lines":"1","rail":"0"},{"id":"10","latitude":"51.5586","longitude":"-0.1059","name":"Arsenal","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"11","latitude":"51.5226","longitude":"-0.1571","name":"Baker Street","display_name":"Baker<br />Street","zone":"1","total_lines":"5","rail":"0"},{"id":"12","latitude":"51.4431","longitude":"-0.1525","name":"Balham","display_name":"NULL","zone":"3","total_lines":"1","rail":"1"},{"id":"13","latitude":"51.5133","longitude":"-0.0886","name":"Bank","display_name":"NULL","zone":"1","total_lines":"4","rail":"0"},{"id":"14","latitude":"51.5204","longitude":"-0.0979","name":"Barbican","display_name":"NULL","zone":"1","total_lines":"3","rail":"0"},{"id":"15","latitude":"51.5396","longitude":"0.081","name":"Barking","display_name":"NULL","zone":"4","total_lines":"2","rail":"1"},{"id":"16","latitude":"51.5856","longitude":"0.0887","name":"Barkingside","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"17","latitude":"51.4905","longitude":"-0.2139","name":"Barons Court","display_name":"Barons<br />Court","zone":"2","total_lines":"2","rail":"0"},{"id":"18","latitude":"51.5121","longitude":"-0.1879","name":"Bayswater","display_name":"NULL","zone":"1","total_lines":"2","rail":"0"},{"id":"19","latitude":"51.5148","longitude":"0.0613","name":"Beckton","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"20","latitude":"51.5087","longitude":"0.055","name":"Beckton Park","display_name":"Beckton<br />Park","zone":"3","total_lines":"1","rail":"0"},{"id":"21","latitude":"51.5403","longitude":"0.127","name":"Becontree","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"22","latitude":"51.5504","longitude":"-0.1642","name":"Belsize Park","display_name":"Belsize<br />Park","zone":"2","total_lines":"1","rail":"0"},{"id":"24","latitude":"51.527","longitude":"-0.0549","name":"Bethnal Green","display_name":"Bethnal<br />Green","zone":"2","total_lines":"1","rail":"0"},{"id":"25","latitude":"51.512","longitude":"-0.1031","name":"Blackfriars","display_name":"NULL","zone":"1","total_lines":"2","rail":"0"},{"id":"26","latitude":"51.5867","longitude":"-0.0417","name":"Blackhorse Road","display_name":"Blackhorse<br />Road","zone":"3","total_lines":"1","rail":"1"},{"id":"27","latitude":"51.5079","longitude":"-0.0066","name":"Blackwall","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"28","latitude":"51.5142","longitude":"-0.1494","name":"Bond Street","display_name":"Bond<br />Street","zone":"1","total_lines":"2","rail":"0"},{"id":"29","latitude":"51.5011","longitude":"-0.0943","name":"Borough","display_name":"NULL","zone":"1","total_lines":"1","rail":"0"},{"id":"30","latitude":"51.4956","longitude":"-0.325","name":"Boston Manor","display_name":"Boston<br />Manor","zone":"4","total_lines":"1","rail":"0"},{"id":"31","latitude":"51.6071","longitude":"-0.1243","name":"Bounds Green","display_name":"Bounds<br />Green","zone":"3.5","total_lines":"1","rail":"0"},{"id":"32","latitude":"51.5273","longitude":"-0.0208","name":"Bow Church","display_name":"Bow<br />Church","zone":"2","total_lines":"3","rail":"0"},{"id":"33","latitude":"51.5269","longitude":"-0.0247","name":"Bow Road","display_name":"Bow<br />Road","zone":"2","total_lines":"2","rail":"0"},{"id":"34","latitude":"51.5766","longitude":"-0.2136","name":"Brent Cross","display_name":"Brent<br />Cross","zone":"3","total_lines":"1","rail":"0"},{"id":"36","latitude":"51.5248","longitude":"-0.0119","name":"Bromley-By-Bow","display_name":"NULL","zone":"2.5","total_lines":"2","rail":"0"},{"id":"38","latitude":"51.6028","longitude":"-0.2641","name":"Burnt Oak","display_name":"Burnt<br />Oak","zone":"4","total_lines":"1","rail":"0"},{"id":"39","latitude":"51.5481","longitude":"-0.1188","name":"Caledonian Road","display_name":"Caledonian<br />Road","zone":"2","total_lines":"1","rail":"0"},{"id":"40","latitude":"51.5392","longitude":"-0.1426","name":"Camden Town","display_name":"Camden<br />Town","zone":"2","total_lines":"1","rail":"0"},{"id":"42","latitude":"51.5051","longitude":"-0.0209","name":"Canary Wharf","display_name":"Canary<br />Wharf","zone":"2","total_lines":"2","rail":"0"},{"id":"44","latitude":"51.5113","longitude":"-0.0904","name":"Cannon Street","display_name":"Cannon<br />Street","zone":"1","total_lines":"2","rail":"0"},{"id":"45","latitude":"51.6078","longitude":"-0.2947","name":"Canons Park","display_name":"Canons<br />Park","zone":"5","total_lines":"1","rail":"0"},{"id":"47","latitude":"51.5441","longitude":"-0.1538","name":"Chalk Farm","display_name":"Chalk<br />Farm","zone":"2","total_lines":"1","rail":"0"},{"id":"48","latitude":"51.5185","longitude":"-0.1111","name":"Chancery Lane","display_name":"Chancery<br />Lane","zone":"1","total_lines":"1","rail":"0"},{"id":"49","latitude":"51.508","longitude":"-0.1247","name":"Charing Cross","display_name":"Charing<br />Cross","zone":"1","total_lines":"2","rail":"1"},{"id":"51","latitude":"51.6177","longitude":"0.0755","name":"Chigwell","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"52","latitude":"51.4946","longitude":"-0.2678","name":"Chiswick Park","display_name":"Chiswick<br />Park","zone":"3","total_lines":"1","rail":"0"},{"id":"54","latitude":"51.4618","longitude":"-0.1384","name":"Clapham Common","display_name":"Clapham<br />Common","zone":"2","total_lines":"1","rail":"0"},{"id":"55","latitude":"51.4649","longitude":"-0.1299","name":"Clapham North","display_name":"Clapham<br />North","zone":"2","total_lines":"1","rail":"0"},{"id":"56","latitude":"51.4527","longitude":"-0.148","name":"Clapham South","display_name":"Clapham<br />South","zone":"2.5","total_lines":"1","rail":"0"},{"id":"58","latitude":"51.5955","longitude":"-0.2502","name":"Colindale","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"59","latitude":"51.418","longitude":"-0.1778","name":"Colliers Wood","display_name":"Colliers<br />Wood","zone":"3","total_lines":"1","rail":"0"},{"id":"60","latitude":"51.5129","longitude":"-0.1243","name":"Covent Garden","display_name":"Covent<br />Garden","zone":"1","total_lines":"1","rail":"0"},{"id":"61","latitude":"51.4957","longitude":"-0.0144","name":"Crossharbour & London Arena","display_name":"Crossharbour &<br />London Arena","zone":"2","total_lines":"1","rail":"0"},{"id":"63","latitude":"51.5095","longitude":"0.0276","name":"Custom House","display_name":"Custom<br />House","zone":"3","total_lines":"1","rail":"0"},{"id":"65","latitude":"51.5085","longitude":"0.064","name":"Cyprus","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"66","latitude":"51.5443","longitude":"0.1655","name":"Dagenham East","display_name":"Dagenham<br />East","zone":"5","total_lines":"1","rail":"0"},{"id":"67","latitude":"51.5417","longitude":"0.1469","name":"Dagenham Heathway","display_name":"Dagenham<br />Heathway","zone":"5","total_lines":"1","rail":"0"},{"id":"70","latitude":"51.5223","longitude":"-0.0173","name":"Devons Road","display_name":"Devons<br />Road","zone":"2","total_lines":"1","rail":"0"},{"id":"71","latitude":"51.552","longitude":"-0.2387","name":"Dollis Hill","display_name":"Dollis<br />Hill","zone":"3","total_lines":"1","rail":"0"},{"id":"72","latitude":"51.5152","longitude":"-0.3017","name":"Ealing Broadway","display_name":"Ealing<br />Broadway","zone":"3","total_lines":"2","rail":"1"},{"id":"73","latitude":"51.5101","longitude":"-0.2882","name":"Ealing Common","display_name":"Ealing<br />Common","zone":"3","total_lines":"2","rail":"0"},{"id":"74","latitude":"51.492","longitude":"-0.1973","name":"Earl's Court","display_name":"Earl's<br />Court","zone":"1.5","total_lines":"2","rail":"0"},{"id":"75","latitude":"51.5765","longitude":"-0.397","name":"Eastcote","display_name":"NULL","zone":"5","total_lines":"2","rail":"0"},{"id":"76","latitude":"51.5168","longitude":"-0.2474","name":"East Acton","display_name":"East<br />Acton","zone":"2","total_lines":"1","rail":"0"},{"id":"77","latitude":"51.5874","longitude":"-0.165","name":"East Finchley","display_name":"East<br />Finchley","zone":"3","total_lines":"1","rail":"0"},{"id":"78","latitude":"51.5394","longitude":"0.0518","name":"East Ham","display_name":"East<br />Ham","zone":"3.5","total_lines":"2","rail":"0"},{"id":"79","latitude":"51.5093","longitude":"-0.0021","name":"East India","display_name":"East<br />India","zone":"2.5","total_lines":"1","rail":"0"},{"id":"80","latitude":"51.4586","longitude":"-0.2112","name":"East Putney","display_name":"East<br />Putney","zone":"2.5","total_lines":"1","rail":"0"},{"id":"81","latitude":"51.6137","longitude":"-0.275","name":"Edgware","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"82","latitude":"51.5199","longitude":"-0.1679","name":"Edgware Road (B)","display_name":"Edgware<br />Road","zone":"1","total_lines":"1","rail":"0"},{"id":"83","latitude":"51.5203","longitude":"-0.17","name":"Edgware Road (C)","display_name":"Edgware<br />Road","zone":"1","total_lines":"3","rail":"0"},{"id":"84","latitude":"51.4943","longitude":"-0.1001","name":"Elephant & Castle","display_name":"Elephant &<br />Castle","zone":"1.5","total_lines":"2","rail":"1"},{"id":"85","latitude":"51.5496","longitude":"0.1977","name":"Elm Park","display_name":"Elm<br />Park","zone":"6","total_lines":"1","rail":"0"},{"id":"87","latitude":"51.5074","longitude":"-0.1223","name":"Embankment","display_name":"NULL","zone":"1","total_lines":"4","rail":"0"},{"id":"89","latitude":"51.5282","longitude":"-0.1337","name":"Euston","display_name":"NULL","zone":"1","total_lines":"2","rail":"1"},{"id":"90","latitude":"51.526","longitude":"-0.1359","name":"Euston Square","display_name":"Euston<br />Square","zone":"1","total_lines":"3","rail":"0"},{"id":"91","latitude":"51.596","longitude":"0.0912","name":"Fairlop","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"92","latitude":"51.5203","longitude":"-0.1053","name":"Farringdon","display_name":"NULL","zone":"1","total_lines":"3","rail":"1"},{"id":"93","latitude":"51.6012","longitude":"-0.1932","name":"Finchley Central","display_name":"Finchley<br />Central","zone":"4","total_lines":"1","rail":"0"},{"id":"94","latitude":"51.5472","longitude":"-0.1803","name":"Finchley Road","display_name":"Finchley<br />Road","zone":"2","total_lines":"2","rail":"0"},{"id":"95","latitude":"51.5642","longitude":"-0.1065","name":"Finsbury Park","display_name":"Finsbury<br />Park","zone":"2","total_lines":"1","rail":"1"},{"id":"96","latitude":"51.4804","longitude":"-0.195","name":"Fulham Broadway","display_name":"Fulham<br />Broadway","zone":"2","total_lines":"1","rail":"0"},{"id":"97","latitude":"51.5096","longitude":"0.0716","name":"Gallions Reach","display_name":"Gallions<br />Reach","zone":"3","total_lines":"1","rail":"0"},{"id":"98","latitude":"51.5765","longitude":"0.0663","name":"Gants Hill","display_name":"Gants<br />Hill","zone":"4","total_lines":"1","rail":"0"},{"id":"99","latitude":"51.4945","longitude":"-0.1829","name":"Gloucester Road","display_name":"Gloucester<br />Road","zone":"1","total_lines":"3","rail":"0"},{"id":"100","latitude":"51.5724","longitude":"-0.1941","name":"Golders Green","display_name":"Golders<br />Green","zone":"3","total_lines":"1","rail":"0"},{"id":"101","latitude":"51.5018","longitude":"-0.2267","name":"Goldhawk Road","display_name":"Goldhawk<br />Road","zone":"2","total_lines":"1","rail":"0"},{"id":"102","latitude":"51.5205","longitude":"-0.1347","name":"Goodge Street","display_name":"Goodge<br />Street","zone":"1","total_lines":"1","rail":"0"},{"id":"103","latitude":"51.6132","longitude":"0.0923","name":"Grange Hill","display_name":"Grange<br />Hill","zone":"5","total_lines":"1","rail":"0"},{"id":"104","latitude":"51.5238","longitude":"-0.1439","name":"Great Portland Street","display_name":"Great<br />Portland<br />Street","zone":"1","total_lines":"3","rail":"0"},{"id":"105","latitude":"51.5423","longitude":"-0.3456","name":"Greenford","display_name":"NULL","zone":"4","total_lines":"1","rail":"1"},{"id":"107","latitude":"51.5067","longitude":"-0.1428","name":"Green Park","display_name":"Green<br />Park","zone":"1","total_lines":"3","rail":"0"},{"id":"108","latitude":"51.4915","longitude":"-0.2754","name":"Gunnersbury","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"109","latitude":"51.603","longitude":"0.0933","name":"Hainault","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"110","latitude":"51.4936","longitude":"-0.2251","name":"Hammersmith","display_name":"NULL","zone":"2","total_lines":"3","rail":"0"},{"id":"111","latitude":"51.5568","longitude":"-0.178","name":"Hampstead","display_name":"NULL","zone":"2.5","total_lines":"1","rail":"0"},{"id":"112","latitude":"51.5302","longitude":"-0.2933","name":"Hanger Lane","display_name":"Hanger<br />Lane","zone":"3","total_lines":"1","rail":"0"},{"id":"113","latitude":"51.5362","longitude":"-0.2575","name":"Harlesden","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"114","latitude":"51.5925","longitude":"-0.3351","name":"Harrow & Wealdston","display_name":"Harrow &<br />Wealdston","zone":"5","total_lines":"1","rail":"1"},{"id":"115","latitude":"51.5793","longitude":"-0.3366","name":"Harrow-on-the-Hill","display_name":"Harrow-<br />on-the-Hill","zone":"5","total_lines":"1","rail":"1"},{"id":"116","latitude":"51.4669","longitude":"-0.4227","name":"Hatton Cross","display_name":"Hatton<br />Cross","zone":"5.5","total_lines":"1","rail":"0"},{"id":"117","latitude":"51.4713","longitude":"-0.4524","name":"Heathrow Terminals 1, 2 & 3","display_name":"Heathrow<br />Terminals<br />1, 2 & 3","zone":"6","total_lines":"1","rail":"0"},{"id":"118","latitude":"51.4598","longitude":"-0.4476","name":"Heathrow Terminal 4","display_name":"Heathrow<br />Terminal 4","zone":"6","total_lines":"1","rail":"0"},{"id":"119","latitude":"51.5829","longitude":"-0.2259","name":"Hendon Central","display_name":"Hendon<br />Central","zone":"3.5","total_lines":"1","rail":"0"},{"id":"120","latitude":"51.5033","longitude":"-0.0215","name":"Heron Quays","display_name":"Heron<br />Quays","zone":"2","total_lines":"1","rail":"0"},{"id":"122","latitude":"51.5009","longitude":"-0.1925","name":"High Street Kensington","display_name":"High<br />Street<br />Kensington","zone":"1","total_lines":"2","rail":"0"},{"id":"123","latitude":"51.546","longitude":"-0.104","name":"Highbury & Islington","display_name":"Highbury &<br />Islington","zone":"2","total_lines":"1","rail":"1"},{"id":"124","latitude":"51.5777","longitude":"-0.1458","name":"Highgate","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"125","latitude":"51.5538","longitude":"-0.4499","name":"Hillingdon","display_name":"NULL","zone":"6","total_lines":"2","rail":"0"},{"id":"126","latitude":"51.5174","longitude":"-0.12","name":"Holborn","display_name":"NULL","zone":"1","total_lines":"2","rail":"0"},{"id":"127","latitude":"51.5075","longitude":"-0.206","name":"Holland Park","display_name":"Holland<br />Park","zone":"2","total_lines":"1","rail":"0"},{"id":"128","latitude":"51.5526","longitude":"-0.1132","name":"Holloway Road","display_name":"Holloway<br />Road","zone":"2","total_lines":"1","rail":"0"},{"id":"129","latitude":"51.5539","longitude":"0.2184","name":"Hornchurch","display_name":"NULL","zone":"6","total_lines":"1","rail":"0"},{"id":"130","latitude":"51.4713","longitude":"-0.3665","name":"Hounslow Central","display_name":"Hounslow<br />Central","zone":"4","total_lines":"1","rail":"0"},{"id":"131","latitude":"51.4733","longitude":"-0.3564","name":"Hounslow East","display_name":"Hounslow<br />East","zone":"4","total_lines":"1","rail":"0"},{"id":"132","latitude":"51.4734","longitude":"-0.3855","name":"Hounslow West","display_name":"Hounslow<br />West","zone":"5","total_lines":"1","rail":"0"},{"id":"133","latitude":"51.5027","longitude":"-0.1527","name":"Hyde Park Corner","display_name":"Hyde<br />Park<br />Corner","zone":"1","total_lines":"1","rail":"0"},{"id":"134","latitude":"51.5619","longitude":"-0.4421","name":"Ickenham","display_name":"NULL","zone":"6","total_lines":"2","rail":"0"},{"id":"135","latitude":"51.4871","longitude":"-0.0101","name":"Island Gardens","display_name":"Island<br />Gardens","zone":"2","total_lines":"1","rail":"0"},{"id":"136","latitude":"51.4884","longitude":"-0.1053","name":"Kennington","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"137","latitude":"51.5304","longitude":"-0.225","name":"Kensal Green","display_name":"Kensal<br />Green","zone":"2","total_lines":"1","rail":"0"},{"id":"138","latitude":"51.4983","longitude":"-0.2106","name":"Kensington (Olympia)","display_name":"Kensington<br />(Olympia)","zone":"2","total_lines":"1","rail":"1"},{"id":"139","latitude":"51.5507","longitude":"-0.1402","name":"Kentish Town","display_name":"Kentish<br />Town","zone":"2","total_lines":"1","rail":"1"},{"id":"140","latitude":"51.5816","longitude":"-0.3162","name":"Kenton","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"141","latitude":"51.477","longitude":"-0.285","name":"Kew Gardens","display_name":"Kew<br />Gardens","zone":"3.5","total_lines":"1","rail":"0"},{"id":"142","latitude":"51.5471","longitude":"-0.2047","name":"Kilburn","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"143","latitude":"51.5351","longitude":"-0.1939","name":"Kilburn Park","display_name":"Kilburn<br />Park","zone":"2","total_lines":"1","rail":"0"},{"id":"144","latitude":"51.5846","longitude":"-0.2786","name":"Kingsbury","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"145","latitude":"51.5308","longitude":"-0.1238","name":"King's Cross St. Pancras","display_name":"King's Cross<br />St. Pancras","zone":"1","total_lines":"6","rail":"1"},{"id":"146","latitude":"51.5015","longitude":"-0.1607","name":"Knightsbridge","display_name":"NULL","zone":"1","total_lines":"1","rail":"0"},{"id":"147","latitude":"51.5172","longitude":"-0.2107","name":"Ladbroke Grove","display_name":"Ladbroke<br />Grove","zone":"2","total_lines":"1","rail":"0"},{"id":"148","latitude":"51.4991","longitude":"-0.1115","name":"Lambeth North","display_name":"Lambeth<br />North","zone":"1","total_lines":"1","rail":"0"},{"id":"149","latitude":"51.5119","longitude":"-0.1756","name":"Lancaster Gate","display_name":"Lancaster<br />Gate","zone":"1","total_lines":"1","rail":"0"},{"id":"150","latitude":"51.5139","longitude":"-0.2172","name":"Latimer Road","display_name":"Latimer<br />Road","zone":"2","total_lines":"1","rail":"0"},{"id":"151","latitude":"51.5113","longitude":"-0.1281","name":"Leicester Square","display_name":"Leicester<br />Square","zone":"1","total_lines":"2","rail":"0"},{"id":"153","latitude":"51.5566","longitude":"-0.0053","name":"Leyton","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"154","latitude":"51.5683","longitude":"0.0083","name":"Leytonstone","display_name":"NULL","zone":"3.5","total_lines":"1","rail":"0"},{"id":"155","latitude":"51.5123","longitude":"-0.0396","name":"Limehouse","display_name":"NULL","zone":"2","total_lines":"1","rail":"1"},{"id":"156","latitude":"51.5178","longitude":"-0.0823","name":"Liverpool Street","display_name":"Liverpool<br />Street","zone":"1","total_lines":"4","rail":"1"},{"id":"157","latitude":"51.5052","longitude":"-0.0864","name":"London Bridge","display_name":"London<br />Bridge","zone":"1","total_lines":"2","rail":"1"},{"id":"159","latitude":"51.53","longitude":"-0.1854","name":"Maida Vale","display_name":"Maida<br />Vale","zone":"2","total_lines":"1","rail":"0"},{"id":"160","latitude":"51.5712","longitude":"-0.0958","name":"Manor House","display_name":"Manor<br />House","zone":"2.5","total_lines":"1","rail":"0"},{"id":"161","latitude":"51.5122","longitude":"-0.094","name":"Mansion House","display_name":"Mansion<br />House","zone":"1","total_lines":"2","rail":"0"},{"id":"162","latitude":"51.5136","longitude":"-0.1586","name":"Marble Arch","display_name":"Marble<br />Arch","zone":"1","total_lines":"1","rail":"0"},{"id":"163","latitude":"51.5225","longitude":"-0.1631","name":"Marylebone","display_name":"NULL","zone":"1","total_lines":"1","rail":"1"},{"id":"164","latitude":"51.5249","longitude":"-0.0332","name":"Mile End","display_name":"Mile<br />End","zone":"2","total_lines":"3","rail":"0"},{"id":"165","latitude":"51.6082","longitude":"-0.2103","name":"Mill Hill East","display_name":"Mill<br />Hill<br />East","zone":"4","total_lines":"1","rail":"0"},{"id":"166","latitude":"51.5108","longitude":"-0.0863","name":"Monument","display_name":"NULL","zone":"1","total_lines":"2","rail":"0"},{"id":"167","latitude":"51.5186","longitude":"-0.0886","name":"Moorgate","display_name":"NULL","zone":"1","total_lines":"4","rail":"1"},{"id":"168","latitude":"51.6294","longitude":"-0.432","name":"Moor Park","display_name":"Moor<br />Park","zone":"6.5","total_lines":"1","rail":"0"},{"id":"169","latitude":"51.4022","longitude":"-0.1948","name":"Morden","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"170","latitude":"51.5342","longitude":"-0.1387","name":"Mornington Crescent","display_name":"Mornington<br />Crescent","zone":"2","total_lines":"1","rail":"0"},{"id":"171","latitude":"51.4902","longitude":"-0.0145","name":"Mudchute","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"172","latitude":"51.5542","longitude":"-0.2503","name":"Neasden","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"173","latitude":"51.5756","longitude":"0.0899","name":"Newbury Park","display_name":"Newbury<br />Park","zone":"4","total_lines":"1","rail":"0"},{"id":"176","latitude":"51.4995","longitude":"-0.3142","name":"Northfields","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"177","latitude":"51.5483","longitude":"-0.3687","name":"Northolt","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"178","latitude":"51.5784","longitude":"-0.3184","name":"Northwick Park","display_name":"Northwick<br />Park","zone":"4","total_lines":"1","rail":"0"},{"id":"179","latitude":"51.6111","longitude":"-0.424","name":"Northwood","display_name":"NULL","zone":"6","total_lines":"1","rail":"0"},{"id":"180","latitude":"51.6004","longitude":"-0.4092","name":"Northwood Hills","display_name":"Northwood<br />Hills","zone":"6","total_lines":"1","rail":"0"},{"id":"181","latitude":"51.5237","longitude":"-0.2597","name":"North Acton","display_name":"North<br />Acton","zone":"2.5","total_lines":"1","rail":"0"},{"id":"182","latitude":"51.5175","longitude":"-0.2887","name":"North Ealing","display_name":"North<br />Ealing","zone":"3","total_lines":"1","rail":"0"},{"id":"184","latitude":"51.5846","longitude":"-0.3626","name":"North Harrow","display_name":"North<br />Harrow","zone":"5","total_lines":"1","rail":"0"},{"id":"185","latitude":"51.5621","longitude":"-0.3034","name":"North Wembley","display_name":"North<br />Wembley","zone":"4","total_lines":"1","rail":"0"},{"id":"186","latitude":"51.5094","longitude":"-0.1967","name":"Notting Hill Gate","display_name":"Notting<br />Hill Gate","zone":"1.5","total_lines":"3","rail":"0"},{"id":"188","latitude":"51.5263","longitude":"-0.0873","name":"Old Street","display_name":"Old<br />Street","zone":"1","total_lines":"1","rail":"1"},{"id":"190","latitude":"51.4813","longitude":"-0.3522","name":"Osterley","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"191","latitude":"51.4819","longitude":"-0.113","name":"Oval","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"192","latitude":"51.515","longitude":"-0.1415","name":"Oxford Circus","display_name":"Oxford<br />Circus","zone":"1","total_lines":"3","rail":"0"},{"id":"193","latitude":"51.5154","longitude":"-0.1755","name":"Paddington","display_name":"NULL","zone":"1","total_lines":"4","rail":"1"},{"id":"194","latitude":"51.527","longitude":"-0.2841","name":"Park Royal","display_name":"Park<br />Royal","zone":"3","total_lines":"1","rail":"0"},{"id":"195","latitude":"51.4753","longitude":"-0.2011","name":"Parsons Green","display_name":"Parsons<br />Green","zone":"2","total_lines":"1","rail":"0"},{"id":"196","latitude":"51.5366","longitude":"-0.3232","name":"Perivale","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"197","latitude":"51.5098","longitude":"-0.1342","name":"Picadilly Circus","display_name":"Picadilly<br />Circus","zone":"1","total_lines":"2","rail":"0"},{"id":"198","latitude":"51.4893","longitude":"-0.1334","name":"Pimlico","display_name":"NULL","zone":"1","total_lines":"1","rail":"0"},{"id":"199","latitude":"51.5926","longitude":"-0.3805","name":"Pinner","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"200","latitude":"51.5313","longitude":"0.0172","name":"Plaistow","display_name":"NULL","zone":"3","total_lines":"2","rail":"0"},{"id":"201","latitude":"51.5077","longitude":"-0.0173","name":"Poplar","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"202","latitude":"51.572","longitude":"-0.2954","name":"Preston Road","display_name":"Preston<br />Road","zone":"4","total_lines":"1","rail":"0"},{"id":"203","latitude":"51.5093","longitude":"0.0336","name":"Prince Regent","display_name":"Prince<br />Regent","zone":"3","total_lines":"1","rail":"0"},{"id":"205","latitude":"51.4682","longitude":"-0.2089","name":"Putney Bridge","display_name":"Putney<br />Bridge","zone":"2","total_lines":"1","rail":"0"},{"id":"206","latitude":"51.5341","longitude":"-0.2047","name":"Queen's Park","display_name":"Queens<br />Park","zone":"2","total_lines":"1","rail":"1"},{"id":"207","latitude":"51.5942","longitude":"-0.2861","name":"Queensbury","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"208","latitude":"51.5107","longitude":"-0.1877","name":"Queensway","display_name":"NULL","zone":"1","total_lines":"1","rail":"0"},{"id":"209","latitude":"51.4942","longitude":"-0.2359","name":"Ravenscourt Park","display_name":"Ravenscourt<br />Park","zone":"2","total_lines":"1","rail":"0"},{"id":"210","latitude":"51.5753","longitude":"-0.3714","name":"Rayners Lane","display_name":"Rayners<br />Lane","zone":"5","total_lines":"2","rail":"0"},{"id":"211","latitude":"51.5763","longitude":"0.0454","name":"Redbridge","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"212","latitude":"51.5234","longitude":"-0.1466","name":"Regent's Park","display_name":"Regent's<br />Park","zone":"1","total_lines":"1","rail":"0"},{"id":"213","latitude":"51.4633","longitude":"-0.3013","name":"Richmond","display_name":"NULL","zone":"4","total_lines":"1","rail":"1"},{"id":"215","latitude":"51.6171","longitude":"0.0439","name":"Roding Valley","display_name":"Roding<br />Valley","zone":"5","total_lines":"1","rail":"0"},{"id":"216","latitude":"51.501","longitude":"-0.0525","name":"Rotherhithe","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"217","latitude":"51.5084","longitude":"0.0465","name":"Royal Albert","display_name":"Royal<br />Albert","zone":"3","total_lines":"1","rail":"0"},{"id":"218","latitude":"51.519","longitude":"-0.188","name":"Royal Oak","display_name":"Royal<br />Oak","zone":"2","total_lines":"1","rail":"0"},{"id":"219","latitude":"51.5091","longitude":"0.0181","name":"Royal Victoria","display_name":"Royal<br />Victoria","zone":"3","total_lines":"1","rail":"0"},{"id":"220","latitude":"51.5715","longitude":"-0.4213","name":"Ruislip","display_name":"NULL","zone":"6","total_lines":"2","rail":"0"},{"id":"222","latitude":"51.5732","longitude":"-0.4125","name":"Ruislip Manor","display_name":"Ruislip<br />Manor","zone":"6","total_lines":"2","rail":"0"},{"id":"223","latitude":"51.523","longitude":"-0.1244","name":"Russell Square","display_name":"Russell<br />Square","zone":"1","total_lines":"1","rail":"0"},{"id":"224","latitude":"51.5822","longitude":"-0.0749","name":"Seven Sisters","display_name":"Seven<br />Sisters","zone":"3","total_lines":"1","rail":"1"},{"id":"225","latitude":"51.5117","longitude":"-0.056","name":"Shadwell","display_name":"NULL","zone":"2","total_lines":"2","rail":"0"},{"id":"226","latitude":"51.5046","longitude":"-0.2187","name":"Shepherd's Bush (C)","display_name":"Shepherd's<br />Bush","zone":"2","total_lines":"1","rail":"0"},{"id":"227","latitude":"51.5058","longitude":"-0.2265","name":"Shepherd's Bush (H)","display_name":"Shepherd's<br />Bush","zone":"2","total_lines":"1","rail":"0"},{"id":"228","latitude":"51.5227","longitude":"-0.0708","name":"Shoreditch","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"229","latitude":"51.4924","longitude":"-0.1565","name":"Sloane Square","display_name":"Sloane<br />Square","zone":"1","total_lines":"2","rail":"0"},{"id":"230","latitude":"51.5808","longitude":"0.0216","name":"Snaresbrook","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"231","latitude":"51.4454","longitude":"-0.2066","name":"Southfields","display_name":"NULL","zone":"3","total_lines":"1","rail":"0"},{"id":"234","latitude":"51.5011","longitude":"-0.3072","name":"South Ealing","display_name":"South<br />Ealing","zone":"3","total_lines":"1","rail":"0"},{"id":"235","latitude":"51.5646","longitude":"-0.3521","name":"South Harrow","display_name":"South<br />Harrow","zone":"5","total_lines":"1","rail":"0"},{"id":"236","latitude":"51.4941","longitude":"-0.1738","name":"South Kensington","display_name":"South<br />Kensington","zone":"1","total_lines":"3","rail":"0"},{"id":"237","latitude":"51.5701","longitude":"-0.3081","name":"South Kenton","display_name":"South<br />Kenton","zone":"4","total_lines":"1","rail":"0"},{"id":"238","latitude":"51.5007","longitude":"-0.0191","name":"South Quay","display_name":"South<br />Quay","zone":"2","total_lines":"1","rail":"0"},{"id":"239","latitude":"51.5569","longitude":"-0.3988","name":"South Ruislip","display_name":"South<br />Ruislip","zone":"5","total_lines":"1","rail":"1"},{"id":"240","latitude":"51.4154","longitude":"-0.1919","name":"South Wimbledon","display_name":"South<br />Wimbledon","zone":"3.5","total_lines":"1","rail":"0"},{"id":"241","latitude":"51.5917","longitude":"0.0275","name":"South Woodford","display_name":"South<br />Woodford","zone":"4","total_lines":"1","rail":"0"},{"id":"242","latitude":"51.495","longitude":"-0.2459","name":"Stamford Brook","display_name":"Stamford<br />Brook","zone":"2","total_lines":"1","rail":"0"},{"id":"243","latitude":"51.6194","longitude":"-0.3028","name":"Stanmore","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"244","latitude":"51.5221","longitude":"-0.047","name":"Stepney Green","display_name":"Stepney<br />Green","zone":"2","total_lines":"2","rail":"0"},{"id":"245","latitude":"51.4723","longitude":"-0.123","name":"Stockwell","display_name":"NULL","zone":"2","total_lines":"2","rail":"0"},{"id":"246","latitude":"51.5439","longitude":"-0.2759","name":"Stonebridge Park","display_name":"Stonebridge<br />Park","zone":"3","total_lines":"1","rail":"0"},{"id":"247","latitude":"51.5416","longitude":"-0.0042","name":"Stratford","display_name":"NULL","zone":"3","total_lines":"3","rail":"1"},{"id":"248","latitude":"51.4994","longitude":"-0.1335","name":"St. James's Park","display_name":"St. James's<br />Park","zone":"1","total_lines":"2","rail":"0"},{"id":"249","latitude":"51.5347","longitude":"-0.174","name":"St. John's Wood","display_name":"St. John's<br />Wood","zone":"2","total_lines":"1","rail":"0"},{"id":"250","latitude":"51.5146","longitude":"-0.0973","name":"St. Paul's","display_name":"St. Paul's","zone":"1","total_lines":"1","rail":"0"},{"id":"251","latitude":"51.5569","longitude":"-0.3366","name":"Sudbury Hill","display_name":"Sudbury<br />Hill","zone":"4","total_lines":"1","rail":"0"},{"id":"252","latitude":"51.5507","longitude":"-0.3156","name":"Sudbury Town","display_name":"Sudbury<br />Town","zone":"4","total_lines":"1","rail":"0"},{"id":"253","latitude":"51.4933","longitude":"-0.0478","name":"Surrey Quays","display_name":"Surrey<br />Quays","zone":"2","total_lines":"1","rail":"0"},{"id":"254","latitude":"51.5432","longitude":"-0.1738","name":"Swiss Cottage","display_name":"Swiss<br />Cottage","zone":"2","total_lines":"2","rail":"0"},{"id":"255","latitude":"51.5111","longitude":"-0.1141","name":"Temple","display_name":"NULL","zone":"1","total_lines":"2","rail":"0"},{"id":"257","latitude":"51.4361","longitude":"-0.1598","name":"Tooting Bec","display_name":"Tooting<br />Bec","zone":"3","total_lines":"1","rail":"0"},{"id":"258","latitude":"51.4275","longitude":"-0.168","name":"Tooting Broadway","display_name":"Tooting<br />Broadway","zone":"3","total_lines":"1","rail":"0"},{"id":"259","latitude":"51.5165","longitude":"-0.131","name":"Tottenham Court Road","display_name":"Tottenham<br />Court<br />Road","zone":"1","total_lines":"2","rail":"0"},{"id":"260","latitude":"51.5882","longitude":"-0.0594","name":"Tottenham Hale","display_name":"Tottenham<br />Hale","zone":"3","total_lines":"1","rail":"1"},{"id":"262","latitude":"51.5106","longitude":"-0.0743","name":"Tower Gateway","display_name":"Tower<br />Gateway","zone":"1","total_lines":"1","rail":"0"},{"id":"263","latitude":"51.5098","longitude":"-0.0766","name":"Tower Hill","display_name":"Tower<br />Hill","zone":"1","total_lines":"2","rail":"0"},{"id":"264","latitude":"51.5567","longitude":"-0.1374","name":"Tufnell Park","display_name":"Tufnell<br />Park","zone":"2","total_lines":"1","rail":"0"},{"id":"265","latitude":"51.4951","longitude":"-0.2547","name":"Turnham Green","display_name":"Turnham<br />Green","zone":"2.5","total_lines":"2","rail":"0"},{"id":"266","latitude":"51.5904","longitude":"-0.1028","name":"Turnpike Lane","display_name":"Turnpike<br />Lane","zone":"3","total_lines":"1","rail":"0"},{"id":"267","latitude":"51.559","longitude":"0.251","name":"Upminster","display_name":"NULL","zone":"6","total_lines":"1","rail":"1"},{"id":"268","latitude":"51.5582","longitude":"0.2343","name":"Upminster Bridge","display_name":"Upminster<br />Bridge","zone":"6","total_lines":"1","rail":"0"},{"id":"269","latitude":"51.5385","longitude":"0.1014","name":"Upney","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"270","latitude":"51.5352","longitude":"0.0343","name":"Upton Park","display_name":"Upton<br />Park","zone":"3","total_lines":"2","rail":"0"},{"id":"271","latitude":"51.5463","longitude":"-0.4786","name":"Uxbridge","display_name":"NULL","zone":"6","total_lines":"2","rail":"0"},{"id":"272","latitude":"51.4861","longitude":"-0.1253","name":"Vauxhall","display_name":"NULL","zone":"1.5","total_lines":"1","rail":"1"},{"id":"273","latitude":"51.4965","longitude":"-0.1447","name":"Victoria","display_name":"NULL","zone":"1","total_lines":"3","rail":"1"},{"id":"274","latitude":"51.583","longitude":"-0.0195","name":"Walthamstow Central","display_name":"Walthamstow<br />Central","zone":"3","total_lines":"1","rail":"1"},{"id":"275","latitude":"51.5775","longitude":"0.0288","name":"Wanstead","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"276","latitude":"51.5043","longitude":"-0.0558","name":"Wapping","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"277","latitude":"51.5247","longitude":"-0.1384","name":"Warren Street","display_name":"Warren<br />Street","zone":"1","total_lines":"2","rail":"0"},{"id":"278","latitude":"51.5235","longitude":"-0.1835","name":"Warwick Avenue","display_name":"Warwick<br />Avenue","zone":"2","total_lines":"1","rail":"0"},{"id":"279","latitude":"51.5036","longitude":"-0.1143","name":"Waterloo","display_name":"NULL","zone":"1","total_lines":"4","rail":"1"},{"id":"281","latitude":"51.5519","longitude":"-0.2963","name":"Wembley Central","display_name":"Wembley<br />Central","zone":"4","total_lines":"1","rail":"1"},{"id":"282","latitude":"51.5635","longitude":"-0.2795","name":"Wembley Park","display_name":"Wembley<br />Park","zone":"4","total_lines":"2","rail":"0"},{"id":"283","latitude":"51.521","longitude":"-0.2011","name":"Westbourne Park","display_name":"Westbourne<br />Park","zone":"2","total_lines":"1","rail":"0"},{"id":"284","latitude":"51.5097","longitude":"-0.0265","name":"Westferry","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"285","latitude":"51.501","longitude":"-0.1254","name":"Westminster","display_name":"NULL","zone":"1","total_lines":"3","rail":"0"},{"id":"286","latitude":"51.518","longitude":"-0.2809","name":"West Acton","display_name":"West<br />Acton","zone":"3","total_lines":"1","rail":"0"},{"id":"287","latitude":"51.4872","longitude":"-0.1953","name":"West Brompton","display_name":"West<br />Brompton","zone":"2","total_lines":"1","rail":"1"},{"id":"288","latitude":"51.6095","longitude":"-0.1883","name":"West Finchley","display_name":"West<br />Finchley","zone":"4","total_lines":"1","rail":"0"},{"id":"289","latitude":"51.5287","longitude":"0.0056","name":"West Ham","display_name":"West<br />Ham","zone":"3","total_lines":"3","rail":"1"},{"id":"290","latitude":"51.5469","longitude":"-0.1906","name":"West Hampstead","display_name":"West<br />Hampstead","zone":"2","total_lines":"1","rail":"1"},{"id":"291","latitude":"51.5795","longitude":"-0.3533","name":"West Harrow","display_name":"West<br />Harrow","zone":"5","total_lines":"1","rail":"0"},{"id":"292","latitude":"51.507","longitude":"-0.0203","name":"West India Quay","display_name":"West<br />India<br />Quay","zone":"2","total_lines":"1","rail":"0"},{"id":"293","latitude":"51.4907","longitude":"-0.2065","name":"West Kensington","display_name":"West<br />Kensington","zone":"2","total_lines":"1","rail":"0"},{"id":"294","latitude":"51.5696","longitude":"-0.4376","name":"West Ruislip","display_name":"West<br />Ruislip","zone":"6","total_lines":"1","rail":"1"},{"id":"295","latitude":"51.5194","longitude":"-0.0612","name":"Whitechapel","display_name":"NULL","zone":"2","total_lines":"3","rail":"0"},{"id":"296","latitude":"51.512","longitude":"-0.2239","name":"White City","display_name":"White<br />City","zone":"2","total_lines":"1","rail":"0"},{"id":"297","latitude":"51.5492","longitude":"-0.2215","name":"Willesden Green","display_name":"Willesden<br />Green","zone":"2.5","total_lines":"1","rail":"0"},{"id":"298","latitude":"51.5326","longitude":"-0.2478","name":"Willesden Junction","display_name":"Willesden<br />Junction","zone":"3","total_lines":"1","rail":"1"},{"id":"299","latitude":"51.4214","longitude":"-0.2064","name":"Wimbledon","display_name":"NULL","zone":"3","total_lines":"1","rail":"1"},{"id":"300","latitude":"51.4343","longitude":"-0.1992","name":"Wimbledon Park","display_name":"Wimbledon<br />Park","zone":"3","total_lines":"1","rail":"0"},{"id":"301","latitude":"51.607","longitude":"0.0341","name":"Woodford","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"302","latitude":"51.6179","longitude":"-0.1856","name":"Woodside Park","display_name":"Woodside<br />Park","zone":"4","total_lines":"1","rail":"0"},{"id":"303","latitude":"51.5975","longitude":"-0.1097","name":"Wood Green","display_name":"Wood<br />Green","zone":"3","total_lines":"1","rail":"0"},{"id":"35","latitude":"51.4627","longitude":"-0.1145","name":"Brixton","display_name":"NULL","zone":"2","total_lines":"1","rail":"1"},{"id":"6","latitude":"51.6736","longitude":"-0.607","name":"Amersham","display_name":"NULL","zone":"10","total_lines":"1","rail":"1"},{"id":"23","latitude":"51.4979","longitude":"-0.0637","name":"Bermondsey","display_name":"NULL","zone":"2","total_lines":"1","rail":"0"},{"id":"50","latitude":"51.7052","longitude":"-0.611","name":"Chesham","display_name":"NULL","zone":"10","total_lines":"1","rail":"0"},{"id":"46","latitude":"51.6679","longitude":"-0.561","name":"Chalfont & Latimer","display_name":"Chalfont &<br />Latimer","zone":"9","total_lines":"1","rail":"1"},{"id":"53","latitude":"51.6543","longitude":"-0.5183","name":"Chorleywood","display_name":"NULL","zone":"8","total_lines":"1","rail":"0"},{"id":"214","latitude":"51.6404","longitude":"-0.4733","name":"Rickmansworth","display_name":"NULL","zone":"7","total_lines":"1","rail":"0"},{"id":"62","latitude":"51.647","longitude":"-0.4412","name":"Croxley","display_name":"NULL","zone":"7","total_lines":"1","rail":"0"},{"id":"280","latitude":"51.6573","longitude":"-0.4177","name":"Watford","display_name":"NULL","zone":"8","total_lines":"1","rail":"0"},{"id":"221","latitude":"51.5606","longitude":"-0.4103","name":"Ruislip Gardens","display_name":"Ruislip<br />Gardens","zone":"5","total_lines":"1","rail":"0"},{"id":"121","latitude":"51.6503","longitude":"-0.1943","name":"High Barnet","display_name":"High<br />Barnet","zone":"5","total_lines":"1","rail":"0"},{"id":"261","latitude":"51.6302","longitude":"-0.1791","name":"Totteridge & Whetstone","display_name":"Totteridge<br />& Whetstone","zone":"4","total_lines":"1","rail":"0"},{"id":"57","latitude":"51.6517","longitude":"-0.1496","name":"Cockfosters","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"187","latitude":"51.6476","longitude":"-0.1318","name":"Oakwood","display_name":"NULL","zone":"5","total_lines":"1","rail":"0"},{"id":"232","latitude":"51.6322","longitude":"-0.128","name":"Southgate","display_name":"NULL","zone":"4","total_lines":"1","rail":"0"},{"id":"88","latitude":"51.6937","longitude":"0.1139","name":"Epping","display_name":"NULL","zone":"6","total_lines":"1","rail":"0"},{"id":"256","latitude":"51.6717","longitude":"0.1033","name":"Theydon Bois","display_name":"Theydon<br />Bois","zone":"6","total_lines":"1","rail":"0"},{"id":"68","latitude":"51.6455","longitude":"0.0838","name":"Debden","display_name":"NULL","zone":"6","total_lines":"1","rail":"0"},{"id":"158","latitude":"51.6412","longitude":"0.0558","name":"Loughton","display_name":"NULL","zone":"6","total_lines":"1","rail":"0"},{"id":"37","latitude":"51.6266","longitude":"0.0471","name":"Buckhurst Hill","display_name":"Buckhurst<br />Hill","zone":"5","total_lines":"1","rail":"0"},{"id":"204","latitude":"51.5343","longitude":"-0.0139","name":"Pudding Mill Lane","display_name":"Pudding<br />Mill Lane","zone":"2.5","total_lines":"1","rail":"0"},{"id":"233","latitude":"51.501","longitude":"-0.1052","name":"Southwark","display_name":"NULL","zone":"1","total_lines":"1","rail":"0"},{"id":"41","latitude":"51.4982","longitude":"-0.0502","name":"Canada Water","display_name":"Canada<br />Water","zone":"2","total_lines":"2","rail":"0"},{"id":"43","latitude":"51.5147","longitude":"0.0082","name":"Canning Town","display_name":"Canning<br />Town","zone":"3","total_lines":"2","rail":"0"},{"id":"183","latitude":"51.5005","longitude":"0.0039","name":"North Greenwich","display_name":"North<br />Greenwich","zone":"2.5","total_lines":"1","rail":"0"},{"id":"64","latitude":"51.4827","longitude":"-0.0096","name":"Cutty Sark","display_name":"Cutty<br />Sark","zone":"2.5","total_lines":"1","rail":"0"},{"id":"106","latitude":"51.4781","longitude":"-0.0149","name":"Greenwich","display_name":"NULL","zone":"2.5","total_lines":"1","rail":"1"},{"id":"69","latitude":"51.474","longitude":"-0.0216","name":"Deptford Bridge","display_name":"Deptford<br />Bridge","zone":"2.5","total_lines":"1","rail":"0"},{"id":"86","latitude":"51.4693","longitude":"-0.0174","name":"Elverson Road","display_name":"Elverson<br />Road","zone":"2.5","total_lines":"1","rail":"0"},{"id":"152","latitude":"51.4657","longitude":"-0.0142","name":"Lewisham","display_name":"NULL","zone":"2.5","total_lines":"1","rail":"1"},{"id":"174","latitude":"51.4767","longitude":"-0.0327","name":"New Cross","display_name":"New<br />Cross","zone":"2","total_lines":"1","rail":"1"},{"id":"175","latitude":"51.4757","longitude":"-0.0402","name":"New Cross Gate","display_name":"New<br />Cross<br />Gate","zone":"2","total_lines":"1","rail":"1"}]}
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.TubeMaps=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function (__dirname){
module.exports = {
"london": {
csv: {
connections: __dirname + '/london.connections.csv',
lines: __dirname + '/london.lines.csv',
stations: __dirname + '/london.stations.csv'
},
json: __dirname + '/london.json'
}
};
}).call(this,"/datasets")
},{}],2:[function(require,module,exports){
var async = require('async');
var fs = require('fs');
var path = require('path');
var JSONStream = require('JSONStream');
var __ = require('highland');
var datasets = require('./datasets');
exports.TubeMap = TubeMap;
exports.Maps = Maps;
function Station(opts) {
this.id = opts.id;
this.conns = opts.conns || [];
this.name = opts.name || "Unknown";
this.display_name = opts.display_name || "Unknown";
this.rail = opts.rail ? parseInt(opts.rail, 10) : null;
this.total_lines = opts.total_lines ? parseInt(opts.total_lines, 10) : 1;
this.latitude = +parseFloat(opts.latitude);
this.longitude = +parseFloat(opts.longitude);
}
function TubeMap(opts) {
opts = opts || {};
this.stationsById = {};
this.stationsByName = {};
this.linesById = {};
this.linesByName = {};
this.stations = opts.stations || [];
this.connections = opts.connections || [];
this.lines = opts.lines || [];
this.make();
}
TubeMap.prototype.makeStation = function(s) {
s = new Station(s);
this.stationsById[s.id] = s;
this.stationsByName[s.name] = s;
};
TubeMap.prototype.getAdjacent = function (root, line) {
var conns = root.conns;
if (line) {
conns = conns.filter(function (c) {
return c.line == line;
});
}
return conns.map(function(c) {
c.station1.line = c.line;
c.station2.line = c.line;
return c.station1.id !== root.id ? c.station1 : c.station2;
});
};
TubeMap.prototype.constructPath = function (dict, path, start, destination){
if (path[path.length-1] && path[path.length-1].station2 == start) {
return path;
}
path.push({station1: destination, station2: dict[destination.id]});
return this.constructPath(dict, path, start, dict[destination.id]);
};
TubeMap.prototype.path = function(start, destination, line){
var Q = [destination];
var V = {};
var family = {};
family[destination.id] = null;
while (Q.length > 0) {
var currentStation = Q.shift();
if (currentStation.id in V) {
continue;
}
var conns = this.getAdjacent(currentStation, line);
conns.forEach(function(child) {
if (!(child.id in V)){
Q.push(child);
}
if (!(child.id in family)){
family[child.id] = currentStation;
}
});
V[currentStation.id] = currentStation;
if (currentStation.id === start.id) {
var path = this.constructPath(family, [], destination, start);
if (line) {
path = path.map(function(d) {
d.line = line;
return d;
});
}
return path;
}
}
return false;
};
TubeMap.prototype.line = function(id) {
return this.connections.filter(function(d) {
return d.line == id;
});
};
TubeMap.prototype.makeConnection = function(c) {
c.station1 = this.stationsById[c.station1];
c.station2 = this.stationsById[c.station2];
c.time = parseInt(c.time, 10);
c.station1.conns.push(c);
c.station2.conns.push(c);
};
TubeMap.prototype.makeLine = function(r) {
this.linesById[r.line] = r;
this.linesByName[r.name] = r;
};
TubeMap.prototype.getLine = function(id) {
return this.linesById[id];
};
TubeMap.prototype.getLineByName = function(name) {
return this.linesByName[name];
}
TubeMap.prototype.getStation = function(id) {
return this.stationsById[id];
};
TubeMap.prototype.getStationByName = function(display_name) {
return this.stationsByName[display_name];
};
TubeMap.prototype.make = function() {
this.stations.forEach(this.makeStation.bind(this));
this.connections.forEach(this.makeConnection.bind(this));
this.lines.forEach(this.makeLine.bind(this));
};
function Maps (city, cb) {
var dataset = require(datasets[city].json);
cb(null, new TubeMap(dataset));
};
},{"./datasets":1,"JSONStream":3,"async":6,"fs":8,"highland":7,"path":15}],3:[function(require,module,exports){
(function (process,Buffer){
var Parser = require('jsonparse')
, through = require('through')
/*
the value of this.stack that creationix's jsonparse has is weird.
it makes this code ugly, but his problem is way harder that mine,
so i'll forgive him.
*/
exports.parse = function (path, map) {
var parser = new Parser()
var stream = through(function (chunk) {
if('string' === typeof chunk)
chunk = new Buffer(chunk)
parser.write(chunk)
},
function (data) {
if(data)
stream.write(data)
stream.queue(null)
})
if('string' === typeof path)
path = path.split('.').map(function (e) {
if (e === '*')
return true
else if (e === '') // '..'.split('.') returns an empty string
return {recurse: true}
else
return e
})
var count = 0, _key
if(!path || !path.length)
path = null
parser.onValue = function (value) {
if (!this.root)
stream.root = value
if(! path) return
var i = 0 // iterates on path
var j = 0 // iterates on stack
while (i < path.length) {
var key = path[i]
var c
j++
if (key && !key.recurse) {
c = (j === this.stack.length) ? this : this.stack[j]
if (!c) return
if (! check(key, c.key)) return
i++
} else {
i++
var nextKey = path[i]
if (! nextKey) return
while (true) {
c = (j === this.stack.length) ? this : this.stack[j]
if (!c) return
if (check(nextKey, c.key)) { i++; break}
j++
}
}
}
if (j !== this.stack.length) return
count ++
var actualPath = this.stack.slice(1).map(function(element) { return element.key }).concat([this.key])
var data = this.value[this.key]
if(null != data)
if(null != (data = map ? map(data, actualPath) : data))
stream.queue(data)
delete this.value[this.key]
}
parser._onToken = parser.onToken;
parser.onToken = function (token, value) {
parser._onToken(token, value);
if (this.stack.length === 0) {
if (stream.root) {
if(!path)
stream.queue(stream.root)
stream.emit('root', stream.root, count)
count = 0;
stream.root = null;
}
}
}
parser.onError = function (err) {
stream.emit('error', err)
}
return stream
}
function check (x, y) {
if ('string' === typeof x)
return y == x
else if (x && 'function' === typeof x.exec)
return x.exec(y)
else if ('boolean' === typeof x)
return x
else if ('function' === typeof x)
return x(y)
return false
}
exports.stringify = function (op, sep, cl, indent) {
indent = indent || 0
if (op === false){
op = ''
sep = '\n'
cl = ''
} else if (op == null) {
op = '[\n'
sep = '\n,\n'
cl = '\n]\n'
}
//else, what ever you like
var stream
, first = true
, anyData = false
stream = through(function (data) {
anyData = true
var json = JSON.stringify(data, null, indent)
if(first) { first = false ; stream.queue(op + json)}
else stream.queue(sep + json)
},
function (data) {
if(!anyData)
stream.queue(op)
stream.queue(cl)
stream.queue(null)
})
return stream
}
exports.stringifyObject = function (op, sep, cl, indent) {
indent = indent || 0
if (op === false){
op = ''
sep = '\n'
cl = ''
} else if (op == null) {
op = '{\n'
sep = '\n,\n'
cl = '\n}\n'
}
//else, what ever you like
var first = true
, anyData = false
stream = through(function (data) {
anyData = true
var json = JSON.stringify(data[0]) + ':' + JSON.stringify(data[1], null, indent)
if(first) { first = false ; this.queue(op + json)}
else this.queue(sep + json)
},
function (data) {
if(!anyData) this.queue(op)
this.queue(cl)
this.queue(null)
})
return stream
}
if(!module.parent && process.title !== 'browser') {
process.stdin
.pipe(exports.parse(process.argv[2]))
.pipe(exports.stringify('[', ',\n', ']\n', 2))
.pipe(process.stdout)
}
}).call(this,require('_process'),require("buffer").Buffer)
},{"_process":16,"buffer":9,"jsonparse":4,"through":5}],4:[function(require,module,exports){
(function (Buffer){
/*global Buffer*/
// Named constants with unique integer values
var C = {};
// Tokens
var LEFT_BRACE = C.LEFT_BRACE = 0x1;
var RIGHT_BRACE = C.RIGHT_BRACE = 0x2;
var LEFT_BRACKET = C.LEFT_BRACKET = 0x3;
var RIGHT_BRACKET = C.RIGHT_BRACKET = 0x4;
var COLON = C.COLON = 0x5;
var COMMA = C.COMMA = 0x6;
var TRUE = C.TRUE = 0x7;
var FALSE = C.FALSE = 0x8;
var NULL = C.NULL = 0x9;
var STRING = C.STRING = 0xa;
var NUMBER = C.NUMBER = 0xb;
// Tokenizer States
var START = C.START = 0x11;
var TRUE1 = C.TRUE1 = 0x21;
var TRUE2 = C.TRUE2 = 0x22;
var TRUE3 = C.TRUE3 = 0x23;
var FALSE1 = C.FALSE1 = 0x31;
var FALSE2 = C.FALSE2 = 0x32;
var FALSE3 = C.FALSE3 = 0x33;
var FALSE4 = C.FALSE4 = 0x34;
var NULL1 = C.NULL1 = 0x41;
var NULL2 = C.NULL3 = 0x42;
var NULL3 = C.NULL2 = 0x43;
var NUMBER1 = C.NUMBER1 = 0x51;
var NUMBER2 = C.NUMBER2 = 0x52;
var NUMBER3 = C.NUMBER3 = 0x53;
var NUMBER4 = C.NUMBER4 = 0x54;
var NUMBER5 = C.NUMBER5 = 0x55;
var NUMBER6 = C.NUMBER6 = 0x56;
var NUMBER7 = C.NUMBER7 = 0x57;
var NUMBER8 = C.NUMBER8 = 0x58;
var STRING1 = C.STRING1 = 0x61;
var STRING2 = C.STRING2 = 0x62;
var STRING3 = C.STRING3 = 0x63;
var STRING4 = C.STRING4 = 0x64;
var STRING5 = C.STRING5 = 0x65;
var STRING6 = C.STRING6 = 0x66;
// Parser States
var VALUE = C.VALUE = 0x71;
var KEY = C.KEY = 0x72;
// Parser Modes
var OBJECT = C.OBJECT = 0x81;
var ARRAY = C.ARRAY = 0x82;
// Slow code to string converter (only used when throwing syntax errors)
function toknam(code) {
var keys = Object.keys(C);
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
if (C[key] === code) { return key; }
}
return code && ("0x" + code.toString(16));
}
function Parser() {
this.tState = START;
this.value = undefined;
this.string = undefined; // string data
this.unicode = undefined; // unicode escapes
// For number parsing
this.negative = undefined;
this.magnatude = undefined;
this.position = undefined;
this.exponent = undefined;
this.negativeExponent = undefined;
this.key = undefined;
this.mode = undefined;
this.stack = [];
this.state = VALUE;
this.bytes_remaining = 0; // number of bytes remaining in multi byte utf8 char to read after split boundary
this.bytes_in_sequence = 0; // bytes in multi byte utf8 char to read
this.temp_buffs = { "2": new Buffer(2), "3": new Buffer(3), "4": new Buffer(4) }; // for rebuilding chars split before boundary is reached
}
var proto = Parser.prototype;
proto.charError = function (buffer, i) {
this.onError(new Error("Unexpected " + JSON.stringify(String.fromCharCode(buffer[i])) + " at position " + i + " in state " + toknam(this.tState)));
};
proto.onError = function (err) { throw err; };
proto.write = function (buffer) {
if (typeof buffer === "string") buffer = new Buffer(buffer);
//process.stdout.write("Input: ");
//console.dir(buffer.toString());
var n;
for (var i = 0, l = buffer.length; i < l; i++) {
if (this.tState === START){
n = buffer[i];
if(n === 0x7b){ this.onToken(LEFT_BRACE, "{"); // {
}else if(n === 0x7d){ this.onToken(RIGHT_BRACE, "}"); // }
}else if(n === 0x5b){ this.onToken(LEFT_BRACKET, "["); // [
}else if(n === 0x5d){ this.onToken(RIGHT_BRACKET, "]"); // ]
}else if(n === 0x3a){ this.onToken(COLON, ":"); // :
}else if(n === 0x2c){ this.onToken(COMMA, ","); // ,
}else if(n === 0x74){ this.tState = TRUE1; // t
}else if(n === 0x66){ this.tState = FALSE1; // f
}else if(n === 0x6e){ this.tState = NULL1; // n
}else if(n === 0x22){ this.string = ""; this.tState = STRING1; // "
}else if(n === 0x2d){ this.negative = true; this.tState = NUMBER1; // -
}else if(n === 0x30){ this.magnatude = 0; this.tState = NUMBER2; // 0
}else{
if (n > 0x30 && n < 0x40) { // 1-9
this.magnatude = n - 0x30; this.tState = NUMBER3;
} else if (n === 0x20 || n === 0x09 || n === 0x0a || n === 0x0d) {
// whitespace
} else { this.charError(buffer, i); }
}
}else if (this.tState === STRING1){ // After open quote
n = buffer[i]; // get current byte from buffer
// check for carry over of a multi byte char split between data chunks
// & fill temp buffer it with start of this data chunk up to the boundary limit set in the last iteration
if (this.bytes_remaining > 0) {
for (var j = 0; j < this.bytes_remaining; j++) {
this.temp_buffs[this.bytes_in_sequence][this.bytes_in_sequence - this.bytes_remaining + j] = buffer[j];
}
this.string += this.temp_buffs[this.bytes_in_sequence].toString();
this.bytes_in_sequence = this.bytes_remaining = 0;
i = i + j - 1;
} else if (this.bytes_remaining === 0 && n >= 128) { // else if no remainder bytes carried over, parse multi byte (>=128) chars one at a time
if ((n >= 194) && (n <= 223)) this.bytes_in_sequence = 2;
if ((n >= 224) && (n <= 239)) this.bytes_in_sequence = 3;
if ((n >= 240) && (n <= 244)) this.bytes_in_sequence = 4;
if ((this.bytes_in_sequence + i) > buffer.length) { // if bytes needed to complete char fall outside buffer length, we have a boundary split
for (var k = 0; k <= (buffer.length - 1 - i); k++) {
this.temp_buffs[this.bytes_in_sequence][k] = buffer[i + k]; // fill temp buffer of correct size with bytes available in this chunk
}
this.bytes_remaining = (i + this.bytes_in_sequence) - buffer.length;
i = buffer.length - 1;
} else {
this.string += buffer.slice(i, (i + this.bytes_in_sequence)).toString();
i = i + this.bytes_in_sequence - 1;
}
} else if (n === 0x22) { this.tState = START; this.onToken(STRING, this.string); this.string = undefined; }
else if (n === 0x5c) { this.tState = STRING2; }
else if (n >= 0x20) { this.string += String.fromCharCode(n); }
else { this.charError(buffer, i); }
}else if (this.tState === STRING2){ // After backslash
n = buffer[i];
if(n === 0x22){ this.string += "\""; this.tState = STRING1;
}else if(n === 0x5c){ this.string += "\\"; this.tState = STRING1;
}else if(n === 0x2f){ this.string += "\/"; this.tState = STRING1;
}else if(n === 0x62){ this.string += "\b"; this.tState = STRING1;
}else if(n === 0x66){ this.string += "\f"; this.tState = STRING1;
}else if(n === 0x6e){ this.string += "\n"; this.tState = STRING1;
}else if(n === 0x72){ this.string += "\r"; this.tState = STRING1;
}else if(n === 0x74){ this.string += "\t"; this.tState = STRING1;
}else if(n === 0x75){ this.unicode = ""; this.tState = STRING3;
}else{
this.charError(buffer, i);
}
}else if (this.tState === STRING3 || this.tState === STRING4 || this.tState === STRING5 || this.tState === STRING6){ // unicode hex codes
n = buffer[i];
// 0-9 A-F a-f
if ((n >= 0x30 && n < 0x40) || (n > 0x40 && n <= 0x46) || (n > 0x60 && n <= 0x66)) {
this.unicode += String.fromCharCode(n);
if (this.tState++ === STRING6) {
this.string += String.fromCharCode(parseInt(this.unicode, 16));
this.unicode = undefined;
this.tState = STRING1;
}
} else {
this.charError(buffer, i);
}
}else if (this.tState === NUMBER1){ // after minus
n = buffer[i];
if (n === 0x30) { this.magnatude = 0; this.tState = NUMBER2; }
else if (n > 0x30 && n < 0x40) { this.magnatude = n - 0x30; this.tState = NUMBER3; }
else { this.charError(buffer, i); }
}else if (this.tState === NUMBER2){ // * After initial zero
n = buffer[i];
if(n === 0x2e){ // .
this.position = 0.1; this.tState = NUMBER4;
}else if(n === 0x65 || n === 0x45){ // e/E
this.exponent = 0; this.tState = NUMBER6;
}else{
this.tState = START;
this.onToken(NUMBER, 0);
this.magnatude = undefined;
this.negative = undefined;
i--;
}
}else if (this.tState === NUMBER3){ // * After digit (before period)
n = buffer[i];
if(n === 0x2e){ // .
this.position = 0.1; this.tState = NUMBER4;
}else if(n === 0x65 || n === 0x45){ // e/E
this.exponent = 0; this.tState = NUMBER6;
}else{
if (n >= 0x30 && n < 0x40) { this.magnatude = this.magnatude * 10 + n - 0x30; }
else {
this.tState = START;
if (this.negative) {
this.magnatude = -this.magnatude;
this.negative = undefined;
}
this.onToken(NUMBER, this.magnatude);
this.magnatude = undefined;
i--;
}
}
}else if (this.tState === NUMBER4){ // After period
n = buffer[i];
if (n >= 0x30 && n < 0x40) { // 0-9
this.magnatude += this.position * (n - 0x30);
this.position /= 10;
this.tState = NUMBER5;
} else { this.charError(buffer, i); }
}else if (this.tState === NUMBER5){ // * After digit (after period)
n = buffer[i];
if (n >= 0x30 && n < 0x40) { // 0-9
this.magnatude += this.position * (n - 0x30);
this.position /= 10;
}
else if (n === 0x65 || n === 0x45) { this.exponent = 0; this.tState = NUMBER6; } // E/e
else {
this.tState = START;
if (this.negative) {
this.magnatude = -this.magnatude;
this.negative = undefined;
}
this.onToken(NUMBER, this.negative ? -this.magnatude : this.magnatude);
this.magnatude = undefined;
this.position = undefined;
i--;
}
}else if (this.tState === NUMBER6){ // After E
n = buffer[i];
if (n === 0x2b || n === 0x2d) { // +/-
if (n === 0x2d) { this.negativeExponent = true; }
this.tState = NUMBER7;
}
else if (n >= 0x30 && n < 0x40) {
this.exponent = this.exponent * 10 + (n - 0x30);
this.tState = NUMBER8;
}
else { this.charError(buffer, i); }
}else if (this.tState === NUMBER7){ // After +/-
n = buffer[i];
if (n >= 0x30 && n < 0x40) { // 0-9
this.exponent = this.exponent * 10 + (n - 0x30);
this.tState = NUMBER8;
}
else { this.charError(buffer, i); }
}else if (this.tState === NUMBER8){ // * After digit (after +/-)
n = buffer[i];
if (n >= 0x30 && n < 0x40) { // 0-9
this.exponent = this.exponent * 10 + (n - 0x30);
}
else {
if (this.negativeExponent) {
this.exponent = -this.exponent;
this.negativeExponent = undefined;
}
this.magnatude *= Math.pow(10, this.exponent);
this.exponent = undefined;
if (this.negative) {
this.magnatude = -this.magnatude;
this.negative = undefined;
}
this.tState = START;
this.onToken(NUMBER, this.magnatude);
this.magnatude = undefined;
i--;
}
}else if (this.tState === TRUE1){ // r
if (buffer[i] === 0x72) { this.tState = TRUE2; }
else { this.charError(buffer, i); }
}else if (this.tState === TRUE2){ // u
if (buffer[i] === 0x75) { this.tState = TRUE3; }
else { this.charError(buffer, i); }
}else if (this.tState === TRUE3){ // e
if (buffer[i] === 0x65) { this.tState = START; this.onToken(TRUE, true); }
else { this.charError(buffer, i); }
}else if (this.tState === FALSE1){ // a
if (buffer[i] === 0x61) { this.tState = FALSE2; }
else { this.charError(buffer, i); }
}else if (this.tState === FALSE2){ // l
if (buffer[i] === 0x6c) { this.tState = FALSE3; }
else { this.charError(buffer, i); }
}else if (this.tState === FALSE3){ // s
if (buffer[i] === 0x73) { this.tState = FALSE4; }
else { this.charError(buffer, i); }
}else if (this.tState === FALSE4){ // e
if (buffer[i] === 0x65) { this.tState = START; this.onToken(FALSE, false); }
else { this.charError(buffer, i); }
}else if (this.tState === NULL1){ // u
if (buffer[i] === 0x75) { this.tState = NULL2; }
else { this.charError(buffer, i); }
}else if (this.tState === NULL2){ // l
if (buffer[i] === 0x6c) { this.tState = NULL3; }
else { this.charError(buffer, i); }
}else if (this.tState === NULL3){ // l
if (buffer[i] === 0x6c) { this.tState = START; this.onToken(NULL, null); }
else { this.charError(buffer, i); }
}
}
};
proto.onToken = function (token, value) {
// Override this to get events
};
proto.parseError = function (token, value) {
this.onError(new Error("Unexpected " + toknam(token) + (value ? ("(" + JSON.stringify(value) + ")") : "") + " in state " + toknam(this.state)));
};
proto.onError = function (err) { throw err; };
proto.push = function () {
this.stack.push({value: this.value, key: this.key, mode: this.mode});
};
proto.pop = function () {
var value = this.value;
var parent = this.stack.pop();
this.value = parent.value;
this.key = parent.key;
this.mode = parent.mode;
this.emit(value);
if (!this.mode) { this.state = VALUE; }
};
proto.emit = function (value) {
if (this.mode) { this.state = COMMA; }
this.onValue(value);
};
proto.onValue = function (value) {
// Override me
};
proto.onToken = function (token, value) {
//console.log("OnToken: state=%s token=%s %s", toknam(this.state), toknam(token), value?JSON.stringify(value):"");
if(this.state === VALUE){
if(token === STRING || token === NUMBER || token === TRUE || token === FALSE || token === NULL){
if (this.value) {
this.value[this.key] = value;
}
this.emit(value);
}else if(token === LEFT_BRACE){
this.push();
if (this.value) {
this.value = this.value[this.key] = {};
} else {
this.value = {};
}
this.key = undefined;
this.state = KEY;
this.mode = OBJECT;
}else if(token === LEFT_BRACKET){
this.push();
if (this.value) {
this.value = this.value[this.key] = [];
} else {
this.value = [];
}
this.key = 0;
this.mode = ARRAY;
this.state = VALUE;
}else if(token === RIGHT_BRACE){
if (this.mode === OBJECT) {
this.pop();
} else {
this.parseError(token, value);
}
}else if(token === RIGHT_BRACKET){
if (this.mode === ARRAY) {
this.pop();
} else {
this.parseError(token, value);
}
}else{
this.parseError(token, value);
}
}else if(this.state === KEY){
if (token === STRING) {
this.key = value;
this.state = COLON;
} else if (token === RIGHT_BRACE) {
this.pop();
} else {
this.parseError(token, value);
}
}else if(this.state === COLON){
if (token === COLON) { this.state = VALUE; }
else { this.parseError(token, value); }
}else if(this.state === COMMA){
if (token === COMMA) {
if (this.mode === ARRAY) { this.key++; this.state = VALUE; }
else if (this.mode === OBJECT) { this.state = KEY; }
} else if (token === RIGHT_BRACKET && this.mode === ARRAY || token === RIGHT_BRACE && this.mode === OBJECT) {
this.pop();
} else {
this.parseError(token, value);
}
}else{
this.parseError(token, value);
}
};
module.exports = Parser;
}).call(this,require("buffer").Buffer)
},{"buffer":9}],5:[function(require,module,exports){
(function (process){
var Stream = require('stream')
// through
//
// a stream that does nothing but re-emit the input.
// useful for aggregating a series of changing but not ending streams into one stream)
exports = module.exports = through
through.through = through
//create a readable writable stream.
function through (write, end, opts) {
write = write || function (data) { this.queue(data) }
end = end || function () { this.queue(null) }
var ended = false, destroyed = false, buffer = [], _ended = false
var stream = new Stream()
stream.readable = stream.writable = true
stream.paused = false
// stream.autoPause = !(opts && opts.autoPause === false)
stream.autoDestroy = !(opts && opts.autoDestroy === false)
stream.write = function (data) {
write.call(this, data)
return !stream.paused
}
function drain() {
while(buffer.length && !stream.paused) {
var data = buffer.shift()
if(null === data)
return stream.emit('end')
else
stream.emit('data', data)
}
}
stream.queue = stream.push = function (data) {
// console.error(ended)
if(_ended) return stream
if(data == null) _ended = true
buffer.push(data)
drain()
return stream
}
//this will be registered as the first 'end' listener
//must call destroy next tick, to make sure we're after any
//stream piped from here.
//this is only a problem if end is not emitted synchronously.
//a nicer way to do this is to make sure this is the last listener for 'end'
stream.on('end', function () {
stream.readable = false
if(!stream.writable && stream.autoDestroy)
process.nextTick(function () {
stream.destroy()
})
})
function _end () {
stream.writable = false
end.call(stream)
if(!stream.readable && stream.autoDestroy)
stream.destroy()
}
stream.end = function (data) {
if(ended) return
ended = true
if(arguments.length) stream.write(data)
_end() // will emit or queue
return stream
}
stream.destroy = function () {
if(destroyed) return
destroyed = true
ended = true
buffer.length = 0
stream.writable = stream.readable = false
stream.emit('close')
return stream
}
stream.pause = function () {
if(stream.paused) return
stream.paused = true
return stream
}
stream.resume = function () {
if(stream.paused) {
stream.paused = false
stream.emit('resume')
}
drain()
//may have become paused again,
//as drain emits 'data'.
if(!stream.paused)
stream.emit('drain')
return stream
}
return stream
}
}).call(this,require('_process'))
},{"_process":16,"stream":29}],6:[function(require,module,exports){
(function (process){
/*!
* async
* https://github.com/caolan/async
*
* Copyright 2010-2014 Caolan McMahon
* Released under the MIT license
*/
/*jshint onevar: false, indent:4 */
/*global setImmediate: false, setTimeout: false, console: false */
(function () {
var async = {};
// global on the server, window in the browser
var root, previous_async;
root = this;
if (root != null) {
previous_async = root.async;
}
async.noConflict = function () {
root.async = previous_async;
return async;
};
function only_once(fn) {
var called = false;
return function() {
if (called) throw new Error("Callback was already called.");
called = true;
fn.apply(root, arguments);
}
}
//// cross-browser compatiblity functions ////
var _toString = Object.prototype.toString;
var _isArray = Array.isArray || function (obj) {
return _toString.call(obj) === '[object Array]';
};
var _each = function (arr, iterator) {
if (arr.forEach) {
return arr.forEach(iterator);
}
for (var i = 0; i < arr.length; i += 1) {
iterator(arr[i], i, arr);
}
};
var _map = function (arr, iterator) {
if (arr.map) {
return arr.map(iterator);
}
var results = [];
_each(arr, function (x, i, a) {
results.push(iterator(x, i, a));
});
return results;
};
var _reduce = function (arr, iterator, memo) {
if (arr.reduce) {
return arr.reduce(iterator, memo);
}
_each(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
};
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
//// exported async module functions ////
//// nextTick implementation with browser-compatible fallback ////
if (typeof process === 'undefined' || !(process.nextTick)) {
if (typeof setImmediate === 'function') {
async.nextTick = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
async.setImmediate = async.nextTick;
}
else {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
async.setImmediate = async.nextTick;
}
}
else {
async.nextTick = process.nextTick;
if (typeof setImmediate !== 'undefined') {
async.setImmediate = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
}
else {
async.setImmediate = async.nextTick;
}
}
async.each = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
_each(arr, function (x) {
iterator(x, only_once(done) );
});
function done(err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback();
}
}
}
};
async.forEach = async.each;
async.eachSeries = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback();
}
else {
iterate();
}
}
});
};
iterate();
};
async.forEachSeries = async.eachSeries;
async.eachLimit = function (arr, limit, iterator, callback) {
var fn = _eachLimit(limit);
fn.apply(null, [arr, iterator, callback]);
};
async.forEachLimit = async.eachLimit;
var _eachLimit = function (limit) {
return function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length || limit <= 0) {
return callback();
}
var completed = 0;
var started = 0;
var running = 0;
(function replenish () {
if (completed >= arr.length) {
return callback();
}
while (running < limit && started < arr.length) {
started += 1;
running += 1;
iterator(arr[started - 1], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
running -= 1;
if (completed >= arr.length) {
callback();
}
else {
replenish();
}
}
});
}
})();
};
};
var doParallel = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.each].concat(args));
};
};
var doParallelLimit = function(limit, fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [_eachLimit(limit)].concat(args));
};
};
var doSeries = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.eachSeries].concat(args));
};
};
var _asyncMap = function (eachfn, arr, iterator, callback) {
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
if (!callback) {
eachfn(arr, function (x, callback) {
iterator(x.value, function (err) {
callback(err);
});
});
} else {
var results = [];
eachfn(arr, function (x, callback) {
iterator(x.value, function (err, v) {
results[x.index] = v;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
async.mapLimit = function (arr, limit, iterator, callback) {
return _mapLimit(limit)(arr, iterator, callback);
};
var _mapLimit = function(limit) {
return doParallelLimit(limit, _asyncMap);
};
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
async.reduce = function (arr, memo, iterator, callback) {
async.eachSeries(arr, function (x, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
});
}, function (err) {
callback(err, memo);
});
};
// inject alias
async.inject = async.reduce;
// foldl alias
async.foldl = async.reduce;
async.reduceRight = function (arr, memo, iterator, callback) {
var reversed = _map(arr, function (x) {
return x;
}).reverse();
async.reduce(reversed, memo, iterator, callback);
};
// foldr alias
async.foldr = async.reduceRight;
var _filter = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.filter = doParallel(_filter);
async.filterSeries = doSeries(_filter);
// select alias
async.select = async.filter;
async.selectSeries = async.filterSeries;
var _reject = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (!v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.reject = doParallel(_reject);
async.rejectSeries = doSeries(_reject);
var _detect = function (eachfn, arr, iterator, main_callback) {
eachfn(arr, function (x, callback) {
iterator(x, function (result) {
if (result) {
main_callback(x);
main_callback = function () {};
}
else {
callback();
}
});
}, function (err) {
main_callback();
});
};
async.detect = doParallel(_detect);
async.detectSeries = doSeries(_detect);
async.some = function (arr, iterator, main_callback) {
async.each(arr, function (x, callback) {
iterator(x, function (v) {
if (v) {
main_callback(true);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(false);
});
};
// any alias
async.any = async.some;
async.every = function (arr, iterator, main_callback) {
async.each(arr, function (x, callback) {
iterator(x, function (v) {
if (!v) {
main_callback(false);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(true);
});
};
// all alias
async.all = async.every;
async.sortBy = function (arr, iterator, callback) {
async.map(arr, function (x, callback) {
iterator(x, function (err, criteria) {
if (err) {
callback(err);
}
else {
callback(null, {value: x, criteria: criteria});
}
});
}, function (err, results) {
if (err) {
return callback(err);
}
else {
var fn = function (left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
};
callback(null, _map(results.sort(fn), function (x) {
return x.value;
}));
}
});
};
async.auto = function (tasks, callback) {
callback = callback || function () {};
var keys = _keys(tasks);
var remainingTasks = keys.length
if (!remainingTasks) {
return callback();
}
var results = {};
var listeners = [];
var addListener = function (fn) {
listeners.unshift(fn);
};
var removeListener = function (fn) {
for (var i = 0; i < listeners.length; i += 1) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
return;
}
}
};
var taskComplete = function () {
remainingTasks--
_each(listeners.slice(0), function (fn) {
fn();
});
};
addListener(function () {
if (!remainingTasks) {
var theCallback = callback;
// prevent final callback from calling itself if it errors
callback = function () {};
theCallback(null, results);
}
});
_each(keys, function (k) {
var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
var taskCallback = function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
if (err) {
var safeResults = {};
_each(_keys(results), function(rkey) {
safeResults[rkey] = results[rkey];
});
safeResults[k] = args;
callback(err, safeResults);
// stop subsequent errors hitting callback multiple times
callback = function () {};
}
else {
results[k] = args;
async.setImmediate(taskComplete);
}
};
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
var ready = function () {
return _reduce(requires, function (a, x) {
return (a && results.hasOwnProperty(x));
}, true) && !results.hasOwnProperty(k);
};
if (ready()) {
task[task.length - 1](taskCallback, results);
}
else {
var listener = function () {
if (ready()) {
removeListener(listener);
task[task.length - 1](taskCallback, results);
}
};
addListener(listener);
}
});
};
async.retry = function(times, task, callback) {
var DEFAULT_TIMES = 5;
var attempts = [];
// Use defaults if times not passed
if (typeof times === 'function') {
callback = task;
task = times;
times = DEFAULT_TIMES;
}
// Make sure times is a number
times = parseInt(times, 10) || DEFAULT_TIMES;
var wrappedTask = function(wrappedCallback, wrappedResults) {
var retryAttempt = function(task, finalAttempt) {
return function(seriesCallback) {
task(function(err, result){
seriesCallback(!err || finalAttempt, {err: err, result: result});
}, wrappedResults);
};
};
while (times) {
attempts.push(retryAttempt(task, !(times-=1)));
}
async.series(attempts, function(done, data){
data = data[data.length - 1];
(wrappedCallback || callback)(data.err, data.result);
});
}
// If a callback is passed, run this as a controll flow
return callback ? wrappedTask() : wrappedTask
};
async.waterfall = function (tasks, callback) {
callback = callback || function () {};
if (!_isArray(tasks)) {
var err = new Error('First argument to waterfall must be an array of functions');
return callback(err);
}
if (!tasks.length) {
return callback();
}
var wrapIterator = function (iterator) {
return function (err) {
if (err) {
callback.apply(null, arguments);
callback = function () {};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
async.setImmediate(function () {
iterator.apply(null, args);
});
}
};
};
wrapIterator(async.iterator(tasks))();
};
var _parallel = function(eachfn, tasks, callback) {
callback = callback || function () {};
if (_isArray(tasks)) {
eachfn.map(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args);
});
}
}, callback);
}
else {
var results = {};
eachfn.each(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.parallel = function (tasks, callback) {
_parallel({ map: async.map, each: async.each }, tasks, callback);
};
async.parallelLimit = function(tasks, limit, callback) {
_parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
};
async.series = function (tasks, callback) {
callback = callback || function () {};
if (_isArray(tasks)) {
async.mapSeries(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args);
});
}
}, callback);
}
else {
var results = {};
async.eachSeries(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.iterator = function (tasks) {
var makeCallback = function (index) {
var fn = function () {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
};
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
};
return makeCallback(0);
};
async.apply = function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(
null, args.concat(Array.prototype.slice.call(arguments))
);
};
};
var _concat = function (eachfn, arr, fn, callback) {
var r = [];
eachfn(arr, function (x, cb) {
fn(x, function (err, y) {
r = r.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, r);
});
};
async.concat = doParallel(_concat);
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
if (test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.whilst(test, iterator, callback);
});
}
else {
callback();
}
};
async.doWhilst = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
var args = Array.prototype.slice.call(arguments, 1);
if (test.apply(null, args)) {
async.doWhilst(iterator, test, callback);
}
else {
callback();
}
});
};
async.until = function (test, iterator, callback) {
if (!test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
});
}
else {
callback();
}
};
async.doUntil = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
var args = Array.prototype.slice.call(arguments, 1);
if (!test.apply(null, args)) {
async.doUntil(iterator, test, callback);
}
else {
callback();
}
});
};
async.queue = function (worker, concurrency) {
if (concurrency === undefined) {
concurrency = 1;
}
function _insert(q, data, pos, callback) {
if (!q.started){
q.started = true;
}
if (!_isArray(data)) {
data = [data];
}
if(data.length == 0) {
// call drain immediately if there are no tasks
return async.setImmediate(function() {
if (q.drain) {
q.drain();
}
});
}
_each(data, function(task) {
var item = {
data: task,
callback: typeof callback === 'function' ? callback : null
};
if (pos) {
q.tasks.unshift(item);
} else {
q.tasks.push(item);
}
if (q.saturated && q.tasks.length === q.concurrency) {
q.saturated();
}
async.setImmediate(q.process);
});
}
var workers = 0;
var q = {
tasks: [],
concurrency: concurrency,
saturated: null,
empty: null,
drain: null,
started: false,
paused: false,
push: function (data, callback) {
_insert(q, data, false, callback);
},
kill: function () {
q.drain = null;
q.tasks = [];
},
unshift: function (data, callback) {
_insert(q, data, true, callback);
},
process: function () {
if (!q.paused && workers < q.concurrency && q.tasks.length) {
var task = q.tasks.shift();
if (q.empty && q.tasks.length === 0) {
q.empty();
}
workers += 1;
var next = function () {
workers -= 1;
if (task.callback) {
task.callback.apply(task, arguments);
}
if (q.drain && q.tasks.length + workers === 0) {
q.drain();
}
q.process();
};
var cb = only_once(next);
worker(task.data, cb);
}
},
length: function () {
return q.tasks.length;
},
running: function () {
return workers;
},
idle: function() {
return q.tasks.length + workers === 0;
},
pause: function () {
if (q.paused === true) { return; }
q.paused = true;
q.process();
},
resume: function () {
if (q.paused === false) { return; }
q.paused = false;
q.process();
}
};
return q;
};
async.priorityQueue = function (worker, concurrency) {
function _compareTasks(a, b){
return a.priority - b.priority;
};
function _binarySearch(sequence, item, compare) {
var beg = -1,
end = sequence.length - 1;
while (beg < end) {
var mid = beg + ((end - beg + 1) >>> 1);
if (compare(item, sequence[mid]) >= 0) {
beg = mid;
} else {
end = mid - 1;
}
}
return beg;
}
function _insert(q, data, priority, callback) {
if (!q.started){
q.started = true;
}
if (!_isArray(data)) {
data = [data];
}
if(data.length == 0) {
// call drain immediately if there are no tasks
return async.setImmediate(function() {
if (q.drain) {
q.drain();
}
});
}
_each(data, function(task) {
var item = {
data: task,
priority: priority,
callback: typeof callback === 'function' ? callback : null
};
q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
if (q.saturated && q.tasks.length === q.concurrency) {
q.saturated();
}
async.setImmediate(q.process);
});
}
// Start with a normal queue
var q = async.queue(worker, concurrency);
// Override push to accept second parameter representing priority
q.push = function (data, priority, callback) {
_insert(q, data, priority, callback);
};
// Remove unshift function
delete q.unshift;
return q;
};
async.cargo = function (worker, payload) {
var working = false,
tasks = [];
var cargo = {
tasks: tasks,
payload: payload,
saturated: null,
empty: null,
drain: null,
drained: true,
push: function (data, callback) {
if (!_isArray(data)) {
data = [data];
}
_each(data, function(task) {
tasks.push({
data: task,
callback: typeof callback === 'function' ? callback : null
});
cargo.drained = false;
if (cargo.saturated && tasks.length === payload) {
cargo.saturated();
}
});
async.setImmediate(cargo.process);
},
process: function process() {
if (working) return;
if (tasks.length === 0) {
if(cargo.drain && !cargo.drained) cargo.drain();
cargo.drained = true;
return;
}
var ts = typeof payload === 'number'
? tasks.splice(0, payload)
: tasks.splice(0, tasks.length);
var ds = _map(ts, function (task) {
return task.data;
});
if(cargo.empty) cargo.empty();
working = true;
worker(ds, function () {
working = false;
var args = arguments;
_each(ts, function (data) {
if (data.callback) {
data.callback.apply(null, args);
}
});
process();
});
},
length: function () {
return tasks.length;
},
running: function () {
return working;
}
};
return cargo;
};
var _console_fn = function (name) {
return function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
fn.apply(null, args.concat([function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (typeof console !== 'undefined') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
_each(args, function (x) {
console[name](x);
});
}
}
}]));
};
};
async.log = _console_fn('log');
async.dir = _console_fn('dir');
/*async.info = _console_fn('info');
async.warn = _console_fn('warn');
async.error = _console_fn('error');*/
async.memoize = function (fn, hasher) {
var memo = {};
var queues = {};
hasher = hasher || function (x) {
return x;
};
var memoized = function () {
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var key = hasher.apply(null, args);
if (key in memo) {
async.nextTick(function () {
callback.apply(null, memo[key]);
});
}
else if (key in queues) {
queues[key].push(callback);
}
else {
queues[key] = [callback];
fn.apply(null, args.concat([function () {
memo[key] = arguments;
var q = queues[key];
delete queues[key];
for (var i = 0, l = q.length; i < l; i++) {
q[i].apply(null, arguments);
}
}]));
}
};
memoized.memo = memo;
memoized.unmemoized = fn;
return memoized;
};
async.unmemoize = function (fn) {
return function () {
return (fn.unmemoized || fn).apply(null, arguments);
};
};
async.times = function (count, iterator, callback) {
var counter = [];
for (var i = 0; i < count; i++) {
counter.push(i);
}
return async.map(counter, iterator, callback);
};
async.timesSeries = function (count, iterator, callback) {
var counter = [];
for (var i = 0; i < count; i++) {
counter.push(i);
}
return async.mapSeries(counter, iterator, callback);
};
async.seq = function (/* functions... */) {
var fns = arguments;
return function () {
var that = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
async.reduce(fns, args, function (newargs, fn, cb) {
fn.apply(that, newargs.concat([function () {
var err = arguments[0];
var nextargs = Array.prototype.slice.call(arguments, 1);
cb(err, nextargs);
}]))
},
function (err, results) {
callback.apply(that, [err].concat(results));
});
};
};
async.compose = function (/* functions... */) {
return async.seq.apply(null, Array.prototype.reverse.call(arguments));
};
var _applyEach = function (eachfn, fns /*args...*/) {
var go = function () {
var that = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
return eachfn(fns, function (fn, cb) {
fn.apply(that, args.concat([cb]));
},
callback);
};
if (arguments.length > 2) {
var args = Array.prototype.slice.call(arguments, 2);
return go.apply(this, args);
}
else {
return go;
}
};
async.applyEach = doParallel(_applyEach);
async.applyEachSeries = doSeries(_applyEach);
async.forever = function (fn, callback) {
function next(err) {
if (err) {
if (callback) {
return callback(err);
}
throw err;
}
fn(next);
}
next();
};
// Node.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
// AMD / RequireJS
else if (typeof define !== 'undefined' && define.amd) {
define([], function () {
return async;
});
}
// included directly via <script> tag
else {
root.async = async;
}
}());
}).call(this,require('_process'))
},{"_process":16}],7:[function(require,module,exports){
(function (process,global){
/**
* Highland: the high-level streams library
*
* Highland may be freely distributed under the Apache 2.0 license.
* http://github.com/caolan/highland
* Copyright (c) Caolan McMahon
*
*/
var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var Decoder = require('string_decoder').StringDecoder;
/**
* The Stream constructor, accepts an array of values or a generator function
* as an optional argument. This is typically the entry point to the Highland
* APIs, providing a convenient way of chaining calls together.
*
* **Arrays -** Streams created from Arrays will emit each value of the Array
* and then emit a [nil](#nil) value to signal the end of the Stream.
*
* **Generators -** These are functions which provide values for the Stream.
* They are lazy and can be infinite, they can also be asynchronous (for
* example, making a HTTP request). You emit values on the Stream by calling
* `push(err, val)`, much like a standard Node.js callback. Once it has been
* called, the generator function will not be called again unless you call
* `next()`. This call to `next()` will signal you've finished processing the
* current data and allow for the generator function to be called again. If the
* Stream is still being consumed the generator function will then be called
* again.
*
* You can also redirect a generator Stream by passing a new source Stream
* to read from to next. For example: `next(other_stream)` - then any subsequent
* calls will be made to the new source.
*
* **Node Readable Stream -** Pass in a Node Readable Stream object to wrap
* it with the Highland API. Reading from the resulting Highland Stream will
* begin piping the data from the Node Stream to the Highland Stream.
*
* **EventEmitter / jQuery Elements -** Pass in both an event name and an
* event emitter as the two arguments to the constructor and the first
* argument emitted to the event handler will be written to the new Stream.
*
* You can also pass as an optional third parameter a function, an array of strings
* or a number. In this case the event handler will try to wrap the arguments emitted
* to it and write this object to the new stream.
*
* **Promise -** Accepts an ES6 / jQuery style promise and returns a
* Highland Stream which will emit a single value (or an error).
*
* @id _(source)
* @section Stream Objects
* @name _(source)
* @param {Array | Function | Readable Stream | Promise} source - (optional) source to take values from from
* @api public
*
* // from an Array
* _([1, 2, 3, 4]);
*
* // using a generator function
* _(function (push, next) {
* push(null, 1);
* push(err);
* next();
* });
*
* // a stream with no source, can pipe node streams through it etc.
* var through = _();
*
* // wrapping a Node Readable Stream so you can easily manipulate it
* _(readable).filter(hasSomething).pipe(writeable);
*
* // creating a stream from events
* _('click', btn).each(handleEvent);
*
* // creating a stream from events with mapping
* _('request', httpServer, ['req', 'res']).each(handleEvent);
*
* // from a Promise object
* var foo = _($.getJSON('/api/foo'));
*/
exports = module.exports = function (/*optional*/xs, /*optional*/ee, /*optional*/ mappingHint) {
return new Stream(xs, ee, mappingHint);
};
var _ = exports;
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype,
ObjProto = Object.prototype;
// Create quick reference variables for speed access to core prototypes.
var slice = ArrayProto.slice,
toString = ObjProto.toString;
_.isFunction = function (x) {
return typeof x === 'function';
};
_.isObject = function (x) {
return typeof x === 'object' && x !== null;
};
_.isString = function (x) {
return typeof x === 'string';
};
_.isArray = Array.isArray || function (x) {
return toString.call(x) === '[object Array]';
};
// setImmediate implementation with browser and older node fallbacks
if (typeof setImmediate === 'undefined') {
if (typeof process === 'undefined' || !(process.nextTick)) {
_.setImmediate = function (fn) {
setTimeout(fn, 0);
};
}
else {
// use nextTick on old node versions
_.setImmediate = process.nextTick;
}
}
// check no process.stdout to detect browserify
else if (typeof process === 'undefined' || !(process.stdout)) {
// modern browser - but not a direct alias for IE10 compatibility
_.setImmediate = function (fn) {
setImmediate(fn);
};
}
else {
_.setImmediate = setImmediate;
}
/**
* The end of stream marker. This is sent along the data channel of a Stream
* to tell consumers that the Stream has ended. See the example map code for
* an example of detecting the end of a Stream.
*
* Note: `nil` is setup as a global where possible. This makes it convenient
* to access, but more importantly lets Streams from different Highland
* instances work together and detect end-of-stream properly. This is mostly
* useful for NPM where you may have many different Highland versions installed.
*
* @id nil
* @section Utils
* @name _.nil
* @api public
*
* var map = function (iter, source) {
* return source.consume(function (err, val, push, next) {
* if (err) {
* push(err);
* next();
* }
* else if (val === _.nil) {
* push(null, val);
* }
* else {
* push(null, iter(val));
* next();
* }
* });
* };
*/
// set up a global nil object in cases where you have multiple Highland
// instances installed (often via npm)
var _global = this;
if (typeof global !== 'undefined') {
_global = global;
}
else if (typeof window !== 'undefined') {
_global = window;
}
if (!_global.nil) {
_global.nil = {};
}
var nil = _.nil = _global.nil;
/**
* Transforms a function with specific arity (all arguments must be
* defined) in a way that it can be called as a chain of functions until
* the arguments list is saturated.
*
* This function is not itself curryable.
*
* @id curry
* @name curry(fn, [*arguments])
* @section Functions
* @param {Function} fn - the function to curry
* @param args.. - any number of arguments to pre-apply to the function
* @returns Function
* @api public
*
* fn = curry(function (a, b, c) {
* return a + b + c;
* });
*
* fn(1)(2)(3) == fn(1, 2, 3)
* fn(1, 2)(3) == fn(1, 2, 3)
* fn(1)(2, 3) == fn(1, 2, 3)
*/
_.curry = function (fn /* args... */) {
var args = slice.call(arguments);
return _.ncurry.apply(this, [fn.length].concat(args));
};
/**
* Same as `curry` but with a specific number of arguments. This can be
* useful when functions do not explicitly define all its parameters.
*
* This function is not itself curryable.
*
* @id ncurry
* @name ncurry(n, fn, [args...])
* @section Functions
* @param {Number} n - the number of arguments to wait for before apply fn
* @param {Function} fn - the function to curry
* @param args... - any number of arguments to pre-apply to the function
* @returns Function
* @api public
*
* fn = ncurry(3, function () {
* return Array.prototype.join.call(arguments, '.');
* });
*
* fn(1, 2, 3) == '1.2.3';
* fn(1, 2)(3) == '1.2.3';
* fn(1)(2)(3) == '1.2.3';
*/
_.ncurry = function (n, fn /* args... */) {
var largs = slice.call(arguments, 2);
if (largs.length >= n) {
return fn.apply(this, largs.slice(0, n));
}
return function () {
var args = largs.concat(slice.call(arguments));
if (args.length < n) {
return _.ncurry.apply(this, [n, fn].concat(args));
}
return fn.apply(this, args.slice(0, n));
};
};
/**
* Partially applies the function (regardless of whether it has had curry
* called on it). This will always postpone execution until at least the next
* call of the partially applied function.
*
* @id partial
* @name partial(fn, args...)
* @section Functions
* @param {Function} fn - function to partial apply
* @param args... - the arguments to apply to the function
* @api public
*
* var addAll = function () {
* var args = Array.prototype.slice.call(arguments);
* return foldl1(add, args);
* };
* var f = partial(addAll, 1, 2);
* f(3, 4) == 10
*/
_.partial = function (f /* args... */) {
var args = slice.call(arguments, 1);
return function () {
return f.apply(this, args.concat(slice.call(arguments)));
};
};
/**
* Evaluates the function `fn` with the argument positions swapped. Only
* works with functions that accept two arguments.
*
* @id flip
* @name flip(fn, [x, y])
* @section Functions
* @param {Function} f - function to flip argument application for
* @param x - parameter to apply to the right hand side of f
* @param y - parameter to apply to the left hand side of f
* @api public
*
* div(2, 4) == 0.5
* flip(div, 2, 4) == 2
* flip(div)(2, 4) == 2
*/
_.flip = _.curry(function (fn, x, y) { return fn(y, x); });
/**
* Creates a composite function, which is the application of function1 to
* the results of function2. You can pass an arbitrary number of arguments
* and have them composed. This means you can't partially apply the compose
* function itself.
*
* @id compose
* @name compose(fn1, fn2, ...)
* @section Functions
* @api public
*
* var add1 = add(1);
* var mul3 = mul(3);
*
* var add1mul3 = compose(mul3, add1);
* add1mul3(2) == 9
*/
_.compose = function (/*functions...*/) {
var fns = slice.call(arguments).reverse();
return _.seq.apply(null, fns);
};
/**
* The reversed version of compose. Where arguments are in the order of
* application.
*
* @id seq
* @name seq(fn1, fn2, ...)
* @section Functions
* @api public
*
* var add1 = add(1);
* var mul3 = mul(3);
*
* var add1mul3 = seq(add1, mul3);
* add1mul3(2) == 9
*/
_.seq = function () {
var fns = slice.call(arguments);
return function () {
if (!fns.length) {
return;
}
var r = fns[0].apply(this, arguments);
for (var i = 1; i < fns.length; i++) {
r = fns[i].call(this, r);
}
return r;
};
};
/**
* Actual Stream constructor wrapped the the main exported function
*/
function Stream(/*optional*/xs, /*optional*/ee, /*optional*/mappingHint) {
if (xs && _.isStream(xs)) {
// already a Stream
return xs;
}
EventEmitter.call(this);
var self = this;
// used to detect Highland Streams using isStream(x), this
// will work even in cases where npm has installed multiple
// versions, unlike an instanceof check
self.__HighlandStream__ = true;
self.id = ('' + Math.random()).substr(2, 6);
this.paused = true;
this._incoming = [];
this._outgoing = [];
this._consumers = [];
this._observers = [];
this._destructors = [];
this._send_events = false;
this._delegate = null;
this.source = null;
// Old-style node Stream.pipe() checks for this
this.writable = true;
self.on('newListener', function (ev) {
if (ev === 'data') {
self._send_events = true;
_.setImmediate(self.resume.bind(self));
}
else if (ev === 'end') {
// this property avoids us checking the length of the
// listners subscribed to each event on each _send() call
self._send_events = true;
}
});
// TODO: write test to cover this removeListener code
self.on('removeListener', function (ev) {
if (ev === 'end' || ev === 'data') {
var end_listeners = self.listeners('end').length;
var data_listeners = self.listeners('data').length;
if (end_listeners + data_listeners === 0) {
// stop emitting events
self._send_events = false;
}
}
});
if (xs === undefined) {
// nothing else to do
}
else if (_.isArray(xs)) {
self._incoming = xs.concat([nil]);
}
else if (typeof xs === 'function') {
this._generator = xs;
this._generator_push = function (err, x) {
self.write(err ? new StreamError(err): x);
};
this._generator_next = function (s) {
if (s) {
// we MUST pause to get the redirect object into the _incoming
// buffer otherwise it would be passed directly to _send(),
// which does not handle StreamRedirect objects!
var _paused = self.paused;
if (!_paused) {
self.pause();
}
self.write(new StreamRedirect(s));
if (!_paused) {
self.resume();
}
}
else {
self._generator_running = false;
}
if (!self.paused) {
self.resume();
}
};
}
else if (_.isObject(xs)) {
if (_.isFunction(xs.then)) {
// probably a promise
return _(function (push) {
xs.then(function (value) {
push(null, value);
return push(null, nil);
},
function (err) {
push(err);
return push(null, nil);
});
});
}
else {
// write any errors into the stream
xs.on('error', function (err) {
self.write(new StreamError(err));
});
// assume it's a pipeable stream as a source
xs.pipe(self);
}
}
else if (typeof xs === 'string') {
var mappingHintType = (typeof mappingHint);
var mapper;
if (mappingHintType === 'function') {
mapper = mappingHint;
} else if (mappingHintType === 'number') {
mapper = function () {
return slice.call(arguments, 0, mappingHint);
};
} else if (_.isArray(mappingHint)) {
mapper = function () {
var args = arguments;
return mappingHint.reduce(function (ctx, hint, idx) {
ctx[hint] = args[idx];
return ctx;
}, {});
};
} else {
mapper = function (x) { return x; };
}
ee.on(xs, function () {
var ctx = mapper.apply(this, arguments);
self.write(ctx);
});
}
else {
throw new Error(
'Unexpected argument type to Stream(): ' + (typeof xs)
);
}
}
inherits(Stream, EventEmitter);
/**
* adds a top-level _.foo(mystream) style export for Stream methods
*/
function exposeMethod(name) {
var f = Stream.prototype[name];
var n = f.length;
_[name] = _.ncurry(n + 1, function () {
var args = Array.prototype.slice.call(arguments);
var s = _(args.pop());
return f.apply(s, args);
});
}
/**
* Used as an Error marker when writing to a Stream's incoming buffer
*/
function StreamError(err) {
this.__HighlandStreamError__ = true;
this.error = err;
}
/**
* Used as a Redirect marker when writing to a Stream's incoming buffer
*/
function StreamRedirect(to) {
this.__HighlandStreamRedirect__ = true;
this.to = to;
}
/**
* Returns true if `x` is a Highland Stream.
*
* @id isStream
* @section Utils
* @name _.isStream(x)
* @param x - the object to test
* @api public
*
* _.isStream('foo') // => false
* _.isStream(_([1,2,3])) // => true
*/
_.isStream = function (x) {
return _.isObject(x) && x.__HighlandStream__;
};
_._isStreamError = function (x) {
return _.isObject(x) && x.__HighlandStreamError__;
};
_._isStreamRedirect = function (x) {
return _.isObject(x) && x.__HighlandStreamRedirect__;
};
/**
* Sends errors / data to consumers, observers and event handlers
*/
Stream.prototype._send = function (err, x) {
//console.log(['_send', this.id, err, x]);
if (x === nil) {
this.ended = true;
}
if (this._consumers.length) {
for (var i = 0, len = this._consumers.length; i < len; i++) {
var c = this._consumers[i];
if (err) {
c.write(new StreamError(err));
}
else {
c.write(x);
}
}
}
if (this._observers.length) {
for (var j = 0, len2 = this._observers.length; j < len2; j++) {
this._observers[j].write(x);
}
}
if (this._send_events) {
if (x === nil) {
this.emit('end');
}
else {
this.emit('data', x);
}
}
};
/**
* Pauses the stream. All Highland Streams start in the paused state.
*
* @id pause
* @section Stream Objects
* @name Stream.pause()
* @api public
*
* var xs = _(generator);
* xs.pause();
*/
Stream.prototype.pause = function () {
//console.log(['pause', this.id]);
this.paused = true;
if (this.source) {
this.source._checkBackPressure();
}
};
/**
* When there is a change in downstream consumers, it will often ask
* the parent Stream to re-check it's state and pause/resume accordingly.
*/
Stream.prototype._checkBackPressure = function () {
if (!this._consumers.length) {
return this.pause();
}
for (var i = 0, len = this._consumers.length; i < len; i++) {
if (this._consumers[i].paused) {
return this.pause();
}
}
return this.resume();
};
/**
* Starts pull values out of the incoming buffer and sending them downstream,
* this will exit early if this causes a downstream consumer to pause.
*/
Stream.prototype._readFromBuffer = function () {
//console.log(['_readFromBuffer', this.id, this.paused, this._incoming]);
var len = this._incoming.length;
var i = 0;
while (i < len && !this.paused) {
var x = this._incoming[i];
if (_._isStreamError(x)) {
this._send(x.error);
}
else if (_._isStreamRedirect(x)) {
this._redirect(x.to);
}
else {
this._send(null, x);
}
i++;
}
// remove processed data from _incoming buffer
this._incoming.splice(0, i);
};
/**
* Starts pull values out of the incoming buffer and sending them downstream,
* this will exit early if this causes a downstream consumer to pause.
*/
Stream.prototype._sendOutgoing = function () {
//console.log(['_sendOutgoing', this.id, this.paused, this._outgoing]);
var len = this._outgoing.length;
var i = 0;
while (i < len && !this.paused) {
var x = this._outgoing[i];
if (_._isStreamError(x)) {
Stream.prototype._send.call(this, x.error);
}
else if (_._isStreamRedirect(x)) {
this._redirect(x.to);
}
else {
Stream.prototype._send.call(this, null, x);
}
i++;
}
// remove processed data from _outgoing buffer
this._outgoing.splice(0, i);
};
/**
* Resumes a paused Stream. This will either read from the Stream's incoming
* buffer or request more data from an upstream source.
*
* @id resume
* @section Stream Objects
* @name Stream.resume()
* @api public
*
* var xs = _(generator);
* xs.resume();
*/
Stream.prototype.resume = function () {
//console.log(['resume', this.id]);
if (this._resume_running) {
//console.log(['resume already processing _incoming buffer, ignore resume call']);
// already processing _incoming buffer, ignore resume call
this._repeat_resume = true;
return;
}
this._resume_running = true;
do {
// use a repeat flag to avoid recursing resume() calls
this._repeat_resume = false;
this.paused = false;
// send values from outgoing buffer first
this._sendOutgoing();
// send values from incoming buffer before reading from source
this._readFromBuffer();
// we may have paused while reading from buffer
if (!this.paused) {
// ask parent for more data
if (this.source) {
//console.log(['ask parent for more data']);
this.source._checkBackPressure();
}
// run _generator to fill up _incoming buffer
else if (this._generator) {
//console.log(['run generator to fill up _incoming buffer']);
this._runGenerator();
}
else {
// perhaps a node stream is being piped in
this.emit('drain');
}
}
} while (this._repeat_resume);
this._resume_running = false;
};
/**
* Ends a Stream. This is the same as sending a [nil](#nil) value as data.
* You shouldn't need to call this directly, rather it will be called by
* any [Node Readable Streams](http://nodejs.org/api/stream.html#stream_class_stream_readable)
* you pipe in.
*
* @id end
* @section Stream Objects
* @name Stream.end()
* @api public
*
* mystream.end();
*/
Stream.prototype.end = function () {
this.write(nil);
};
/**
* Pipes a Highland Stream to a [Node Writable Stream](http://nodejs.org/api/stream.html#stream_class_stream_writable)
* (Highland Streams are also Node Writable Streams). This will pull all the
* data from the source Highland Stream and write it to the destination,
* automatically managing flow so that the destination is not overwhelmed
* by a fast source.
*
* This function returns the destination so you can chain together pipe calls.
*
* @id pipe
* @section Consumption
* @name Stream.pipe(dest)
* @param {Writable Stream} dest - the destination to write all data to
* @api public
*
* var source = _(generator);
* var dest = fs.createWriteStream('myfile.txt')
* source.pipe(dest);
*
* // chained call
* source.pipe(through).pipe(dest);
*/
Stream.prototype.pipe = function (dest) {
var self = this;
// stdout and stderr are special case writables that cannot be closed
var canClose = dest !== process.stdout && dest !== process.stderr;
var s = self.consume(function (err, x, push, next) {
if (err) {
self.emit('error', err);
return;
}
if (x === nil) {
if (canClose) {
dest.end();
}
}
else if (dest.write(x) !== false) {
next();
}
});
dest.on('drain', onConsumerDrain);
// Since we don't keep a reference to piped-to streams,
// save a callback that will unbind the event handler.
this._destructors.push(function () {
dest.removeListener('drain', onConsumerDrain);
});
s.resume();
return dest;
function onConsumerDrain() {
s.resume();
}
};
/**
* Destroys a stream by unlinking it from any consumers and sources. This will
* stop all consumers from receiving events from this stream and removes this
* stream as a consumer of any source stream.
*
* This function calls end() on the stream and unlinks it from any piped-to streams.
*
* @id destroy
* @section Stream Objects
* @name Stream.destroy()
* @api public
*/
Stream.prototype.destroy = function () {
var self = this;
this.end();
_(this._consumers).each(function (consumer) {
self._removeConsumer(consumer);
});
if (this.source) {
this.source._removeConsumer(this);
}
_(this._destructors).each(function (destructor) {
destructor();
});
};
/**
* Runs the generator function for this Stream. If the generator is already
* running (it has been called and not called next() yet) then this function
* will do nothing.
*/
Stream.prototype._runGenerator = function () {
//console.log(['_runGenerator', this.id]);
// if _generator already running, exit
if (this._generator_running) {
return;
}
this._generator_running = true;
this._generator(this._generator_push, this._generator_next);
};
/**
* Performs the redirect from one Stream to another. In order for the
* redirect to happen at the appropriate time, it is put on the incoming
* buffer as a StreamRedirect object, and this function is called
* once it is read from the buffer.
*/
Stream.prototype._redirect = function (to) {
//console.log(['_redirect', this.id, '=>', to.id]);
// coerce to Stream
to = _(to);
while (to._delegate) {
to = to._delegate;
}
to._consumers = this._consumers.map(function (c) {
c.source = to;
return c;
});
// TODO: copy _observers
this._consumers = [];
//[this.consume = function () {
// return to.consume.apply(to, arguments);
//};
//this._removeConsumer = function () {
// return to._removeConsumer.apply(to, arguments);
//};
// this will cause a memory leak as long as the root object is around
to._delegate_source = this._delegate_source || this;
to._delegate_source._delegate = to;
if (this.paused) {
to.pause();
}
else {
this.pause();
to._checkBackPressure();
}
};
/**
* Adds a new consumer Stream, which will accept data and provide backpressure
* to this Stream. Adding more than one consumer will cause an exception to be
* thrown as the backpressure strategy must be explicitly chosen by the
* developer (through calling fork or observe).
*/
Stream.prototype._addConsumer = function (s) {
if (this._consumers.length) {
throw new Error(
'Stream already being consumed, you must either fork() or observe()'
);
}
s.source = this;
this._consumers.push(s);
this._checkBackPressure();
};
/**
* Removes a consumer from this Stream.
*/
Stream.prototype._removeConsumer = function (s) {
var src = this;
while (src._delegate) {
src = src._delegate;
}
src._consumers = src._consumers.filter(function (c) {
return c !== s;
});
if (s.source === src) {
s.source = null;
}
src._checkBackPressure();
};
/**
* Consumes values from a Stream (once resumed) and returns a new Stream for
* you to optionally push values onto using the provided push / next functions.
*
* This function forms the basis of many higher-level Stream operations.
* It will not cause a paused stream to immediately resume, but behaves more
* like a 'through' stream, handling values as they are read.
*
* @id consume
* @section Transforms
* @name Stream.consume(f)
* @param {Function} f - the function to handle errors and values
* @api public
*
* var filter = function (f, source) {
* return source.consume(function (err, x, push, next) {
* if (err) {
* // pass errors along the stream and consume next value
* push(err);
* next();
* }
* else if (x === _.nil) {
* // pass nil (end event) along the stream
* push(null, x);
* }
* else {
* // pass on the value only if the value passes the predicate
* if (f(x)) {
* push(null, x);
* }
* next();
* }
* });
* };
*/
Stream.prototype.consume = function (f) {
var self = this;
while (self._delegate) {
self = self._delegate;
}
var s = new Stream();
var _send = s._send;
var push = function (err, x) {
//console.log(['push', err, x, s.paused]);
if (x === nil) {
// ended, remove consumer from source
self._removeConsumer(s);
}
if (s.paused) {
if (err) {
s._outgoing.push(new StreamError(err));
}
else {
s._outgoing.push(x);
}
}
else {
_send.call(s, err, x);
}
};
var async;
var next_called;
var next = function (s2) {
//console.log(['next', async]);
if (s2) {
// we MUST pause to get the redirect object into the _incoming
// buffer otherwise it would be passed directly to _send(),
// which does not handle StreamRedirect objects!
var _paused = s.paused;
if (!_paused) {
s.pause();
}
s.write(new StreamRedirect(s2));
if (!_paused) {
s.resume();
}
}
else if (async) {
s.resume();
}
else {
next_called = true;
}
};
s._send = function (err, x) {
async = false;
next_called = false;
f(err, x, push, next);
async = true;
if (!next_called) {
s.pause();
}
};
self._addConsumer(s);
return s;
};
exposeMethod('consume');
/**
* Consumes a single item from the Stream. Unlike consume, this function will
* not provide a new stream for you to push values onto, and it will unsubscribe
* as soon as it has a single error, value or nil from the source.
*
* You probably won't need to use this directly, but it is used internally by
* some functions in the Highland library.
*
* @id pull
* @section Consumption
* @name Stream.pull(f)
* @param {Function} f - the function to handle data
* @api public
*
* xs.pull(function (err, x) {
* // do something
* });
*/
Stream.prototype.pull = function (f) {
var s = this.consume(function (err, x) {
s.source._removeConsumer(s);
f(err, x);
});
s.id = 'pull:' + s.id;
s.resume();
};
/**
* Writes a value to the Stream. If the Stream is paused it will go into the
* Stream's incoming buffer, otherwise it will be immediately processed and
* sent to the Stream's consumers (if any). Returns false if the Stream is
* paused, true otherwise. This lets Node's pipe method handle back-pressure.
*
* You shouldn't need to call this yourself, but it may be called by Node
* functions which treat Highland Streams as a [Node Writable Stream](http://nodejs.org/api/stream.html#stream_class_stream_writable).
*
* @id write
* @section Stream Objects
* @name Stream.write(x)
* @param x - the value to write to the Stream
* @api public
*
* var xs = _();
* xs.write(1);
* xs.write(2);
* xs.end();
*
* xs.toArray(function (ys) {
* // ys will be [1, 2]
* });
*/
Stream.prototype.write = function (x) {
if (this.paused) {
this._incoming.push(x);
}
else {
if (_._isStreamError(x)) {
this._send(x.error);
}
else {
this._send(null, x);
}
}
return !this.paused;
};
/**
* Forks a stream, allowing you to add additional consumers with shared
* back-pressure. A stream forked to multiple consumers will only pull values
* from it's source as fast as the slowest consumer can handle them.
*
* @id fork
* @section Higher-order Streams
* @name Stream.fork()
* @api public
*
* var xs = _([1, 2, 3, 4]);
* var ys = xs.fork();
* var zs = xs.fork();
*
* // no values will be pulled from xs until zs also resume
* ys.resume();
*
* // now both ys and zs will get values from xs
* zs.resume();
*/
Stream.prototype.fork = function () {
var s = new Stream();
s.id = 'fork:' + s.id;
s.source = this;
this._consumers.push(s);
this._checkBackPressure();
return s;
};
/**
* Observes a stream, allowing you to handle values as they are emitted, without
* adding back-pressure or causing data to be pulled from the source. This can
* be useful when you are performing two related queries on a stream where one
* would block the other. Just be aware that a slow observer could fill up it's
* buffer and cause memory issues. Where possible, you should use [fork](#fork).
*
* @id observe
* @section Higher-order Streams
* @name Stream.observe()
* @api public
*
* var xs = _([1, 2, 3, 4]);
* var ys = xs.fork();
* var zs = xs.observe();
*
* // now both zs and ys will receive data as fast as ys can handle it
* ys.resume();
*/
Stream.prototype.observe = function () {
var s = new Stream();
s.id = 'observe:' + s.id;
s.source = this;
this._observers.push(s);
return s;
};
/**
* Extracts errors from a Stream and applies them to an error handler
* function. Returns a new Stream with the errors removed (unless the error
* handler chooses to rethrow them using `push`). Errors can also be
* transformed and put back onto the Stream as values.
*
* @id errors
* @section Transforms
* @name Stream.errors(f)
* @param {Function} f - the function to pass all errors to
* @api public
*
* getDocument.errors(function (err, push) {
* if (err.statusCode === 404) {
* // not found, return empty doc
* push(null, {});
* }
* else {
* // otherwise, re-throw the error
* push(err);
* }
* });
*/
Stream.prototype.errors = function (f) {
return this.consume(function (err, x, push, next) {
if (err) {
f(err, push);
next();
}
else if (x === nil) {
push(null, nil);
}
else {
push(null, x);
next();
}
});
};
exposeMethod('errors');
/**
* Like the [errors](#errors) method, but emits a Stream end marker after
* an Error is encountered.
*
* @id stopOnError
* @section Transforms
* @name Stream.stopOnError(f)
* @param {Function} f - the function to handle an error
* @api public
*
* brokenStream.stopOnError(function (err) {
* //console.error('Something broke: ' + err);
* });
*/
Stream.prototype.stopOnError = function (f) {
return this.consume(function (err, x, push, next) {
if (err) {
f(err, push);
push(null, nil);
}
else if (x === nil) {
push(null, nil);
}
else {
push(null, x);
next();
}
});
};
exposeMethod('stopOnError');
/**
* Iterates over every value from the Stream, calling the iterator function
* on each of them. This function causes a **thunk**.
*
* If an error from the Stream reaches the `each` call, it will emit an
* error event (which will cause it to throw if unhandled).
*
* @id each
* @section Consumption
* @name Stream.each(f)
* @param {Function} f - the iterator function
* @api public
*
* _([1, 2, 3, 4]).each(function (x) {
* // will be called 4 times with x being 1, 2, 3 and 4
* });
*/
Stream.prototype.each = function (f) {
var self = this;
return this.consume(function (err, x, push, next) {
if (err) {
self.emit('error', err);
}
else if (x !== nil) {
f(x);
next();
}
}).resume();
};
exposeMethod('each');
/**
* Applies results from a Stream as arguments to a function
*
* @id apply
* @section Consumption
* @name Stream.apply(f)
* @param {Function} f - the function to apply arguments to
* @api public
*
* _([1, 2, 3]).apply(function (a, b, c) {
* // a === 1
* // b === 2
* // c === 3
* });
*/
Stream.prototype.apply = function (f) {
return this.toArray(function (args) {
f.apply(null, args);
});
};
exposeMethod('apply');
/**
* Collects all values from a Stream into an Array and calls a function with
* once with the result. This function causes a **thunk**.
*
* If an error from the Stream reaches the `toArray` call, it will emit an
* error event (which will cause it to throw if unhandled).
*
* @id toArray
* @section Consumption
* @name Stream.toArray(f)
* @param {Function} f - the callback to provide the completed Array to
* @api public
*
* _([1, 2, 3, 4]).toArray(function (x) {
* // parameter x will be [1,2,3,4]
* });
*/
Stream.prototype.toArray = function (f) {
var self = this;
return this.collect().pull(function (err, x) {
if (err) {
self.emit('error', err);
}
else {
f(x);
}
});
};
/**
* Creates a new Stream of transformed values by applying a function to each
* value from the source. The transformation function can be replaced with
* a non-function value for convenience, and it will emit that value
* for every data event on the source Stream.
*
* @id map
* @section Transforms
* @name Stream.map(f)
* @param f - the transformation function or value to map to
* @api public
*
* var doubled = _([1, 2, 3, 4]).map(function (x) {
* return x * 2;
* });
*
* _([1, 2, 3]).map('hi') // => 'hi', 'hi', 'hi'
*/
Stream.prototype.map = function (f) {
if (!_.isFunction(f)) {
var val = f;
f = function () {
return val;
};
}
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
}
else if (x === nil) {
push(err, x);
}
else {
var fnVal, fnErr;
try {
fnVal = f(x);
} catch (e) {
fnErr = e;
}
push(fnErr, fnVal);
next();
}
});
};
exposeMethod('map');
/**
* Creates a new Stream which applies a function to each value from the source
* and re-emits the source value. Useful when you want to mutate the value or
* perform side effects
*
* @id doto
* @section Transforms
* @name Stream.doto(f)
* @param f - the function to apply
* @api public
*
* var appended = _([[1], [2], [3], [4]]).doto(function (x) {
* x.push(1);
* });
*
* _([1, 2, 3]).doto(console.log)
* // 1
* // 2
* // 3
* // => 1, 2, 3
*/
Stream.prototype.doto = function (f) {
return this.map(function (x) {
f(x);
return x;
});
};
exposeMethod('doto');
/**
* Limits number of values through the stream to a maximum of number of values
* per window. Errors are not limited but allowed to pass through as soon as
* they are read from the source.
*
* @id ratelimit
* @section Transforms
* @name Stream.ratelimit(num, ms)
* @param {Number} num - the number of operations to perform per window
* @param {Number} ms - the window of time to limit the operations in (in ms)
* @api public
*
* _([1, 2, 3, 4, 5]).ratelimit(2, 100);
*
* // after 0ms => 1, 2
* // after 100ms => 1, 2, 3, 4
* // after 200ms => 1, 2, 3, 4, 5
*/
Stream.prototype.ratelimit = function (num, ms) {
if (num < 1) {
throw new Error('Invalid number of operations per ms: ' + num);
}
var sent = 0;
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
}
else if (x === nil) {
push(null, nil);
}
else {
if (sent < num) {
sent++;
push(null, x);
next();
}
else {
setTimeout(function () {
sent = 1;
push(null, x);
next();
}, ms);
}
}
});
};
exposeMethod('ratelimit');
/**
* Creates a new Stream of values by applying each item in a Stream to an
* iterator function which must return a (possibly empty) Stream. Each item on
* these result Streams are then emitted on a single output Stream.
*
* @id flatMap
* @section Higher-order Streams
* @name Stream.flatMap(f)
* @param {Function} f - the iterator function
* @api public
*
* filenames.flatMap(readFile)
*/
Stream.prototype.flatMap = function (f) {
return this.map(f).sequence();
};
exposeMethod('flatMap');
/**
* Retrieves values associated with a given property from all elements in
* the collection.
*
* @id pluck
* @section Transforms
* @name Stream.pluck(property)
* @param {String} prop - the property to which values should be associated
* @api public
*
* var docs = [
* {type: 'blogpost', title: 'foo'},
* {type: 'blogpost', title: 'bar'},
* {type: 'comment', title: 'baz'}
* ];
*
* _(docs).pluck('title').toArray(function (xs) {
* // xs is now ['foo', 'bar', 'baz']
* });
*/
Stream.prototype.pluck = function (prop) {
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
}
else if (x === nil) {
push(err, x);
}
else if (_.isObject(x)) {
push(null, x[prop]);
next();
}
else {
push(new Error(
'Expected Object, got ' + (typeof x)
));
next();
}
});
};
exposeMethod('pluck');
/**
* Creates a new Stream including only the values which pass a truth test.
*
* @id filter
* @section Transforms
* @name Stream.filter(f)
* @param f - the truth test function
* @api public
*
* var evens = _([1, 2, 3, 4]).filter(function (x) {
* return x % 2 === 0;
* });
*/
Stream.prototype.filter = function (f) {
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
}
else if (x === nil) {
push(err, x);
}
else {
var fnVal, fnErr;
try {
fnVal = f(x);
} catch (e) {
fnErr = e;
}
if (fnErr) {
push(fnErr);
} else if (fnVal) {
push(null, x);
}
next();
}
});
};
exposeMethod('filter');
/**
* Filters using a predicate which returns a Stream. If you need to check
* against an asynchronous data source when filtering a Stream, this can
* be convenient. The Stream returned from the filter function should have
* a Boolean as it's first value (all other values on the Stream will be
* disregarded).
*
* @id flatFilter
* @section Higher-order Streams
* @name Stream.flatFilter(f)
* @param {Function} f - the truth test function which returns a Stream
* @api public
*
* var checkExists = _.wrapCallback(fs.exists);
* filenames.flatFilter(checkExists)
*/
Stream.prototype.flatFilter = function (f) {
return this.flatMap(function (x) {
return f(x).take(1).otherwise(errorStream())
.flatMap(function (bool) {
return _(bool ? [x] : []);
});
});
function errorStream() {
return _(function (push) {
push(new Error('Stream returned by function was empty.'));
push(null, _.nil);
});
}
};
exposeMethod('flatFilter');
/**
* The inverse of [filter](#filter).
*
* @id reject
* @section Transforms
* @name Stream.reject(f)
* @param {Function} f - the truth test function
* @api public
*
* var odds = _([1, 2, 3, 4]).reject(function (x) {
* return x % 2 === 0;
* });
*/
Stream.prototype.reject = function (f) {
return this.filter(_.compose(_.not, f));
};
exposeMethod('reject');
/**
* A convenient form of filter, which returns the first object from a
* Stream that passes the provided truth test
*
* @id find
* @section Transforms
* @name Stream.find(f)
* @param {Function} f - the truth test function which returns a Stream
* @api public
*
* var docs = [
* {type: 'blogpost', title: 'foo'},
* {type: 'blogpost', title: 'bar'},
* {type: 'comment', title: 'foo'}
* ];
*
* var f = function (x) {
* return x.type == 'blogpost';
* };
*
* _(docs).find(f);
* // => {type: 'blogpost', title: 'foo'}
*
* // example with partial application
* var firstBlogpost = _.find(f);
*
* firstBlogpost(docs)
* // => {type: 'blogpost', title: 'foo'}
*/
Stream.prototype.find = function (f) {
return this.filter(f).take(1);
};
exposeMethod('find');
/**
* A convenient form of where, which returns the first object from a
* Stream that matches a set of property values. findWhere is to where as find is to filter.
*
* @id findWhere
* @section Transforms
* @name Stream.findWhere(props)
* @param {Object} props - the properties to match against
* @api public
*
* var docs = [
* {type: 'blogpost', title: 'foo'},
* {type: 'blogpost', title: 'bar'},
* {type: 'comment', title: 'foo'}
* ];
*
* _(docs).findWhere({type: 'blogpost'})
* // => {type: 'blogpost', title: 'foo'}
*
* // example with partial application
* var firstBlogpost = _.findWhere({type: 'blogpost'});
*
* firstBlogpost(docs)
* // => {type: 'blogpost', title: 'foo'}
*/
Stream.prototype.findWhere = function (props) {
return this.where(props).take(1);
};
exposeMethod('findWhere');
/**
* A convenient form of reduce, which groups items based on a function or property name
*
* @id group
* @section Transforms
* @name Stream.group(f)
* @param {Function|String} f - the function or property name on which to group,
* toString() is called on the result of a function.
* @api public
*
* var docs = [
* {type: 'blogpost', title: 'foo'},
* {type: 'blogpost', title: 'bar'},
* {type: 'comment', title: 'foo'}
* ];
*
* var f = function (x) {
* return x.type;
* };
*
* _(docs).group(f); OR _(docs).group('type');
* // => {
* // => 'blogpost': [{type: 'blogpost', title: 'foo'}, {type: 'blogpost', title: 'bar'}]
* // => 'comment': [{type: 'comment', title: 'foo'}]
* // => }
*
*/
Stream.prototype.group = function (f) {
var lambda = _.isString(f) ? _.get(f) : f;
return this.reduce({}, function (m, o) {
var key = lambda(o);
if (!m.hasOwnProperty(key)) { m[key] = []; }
m[key].push(o);
return m;
}.bind(this));
};
exposeMethod('group');
/**
* Filters a Stream to drop all non-truthy values.
*
* @id compact
* @section Transforms
* @name Stream.compact()
* @api public
*
* var compacted = _([0, 1, false, 3, null, undefined, 6]).compact();
* // => 1, 3, 6
*/
Stream.prototype.compact = function () {
return this.filter(function (x) {
return x;
});
};
exposeMethod('compact');
/**
* A convenient form of filter, which returns all objects from a Stream
* which match a set of property values.
*
* @id where
* @section Transforms
* @name Stream.where(props)
* @param {Object} props - the properties to match against
* @api public
*
* var docs = [
* {type: 'blogpost', title: 'foo'},
* {type: 'blogpost', title: 'bar'},
* {type: 'comment', title: 'foo'}
* ];
*
* _(docs).where({title: 'foo'})
* // => {type: 'blogpost', title: 'foo'}
* // => {type: 'comment', title: 'foo'}
*
* // example with partial application
* var getBlogposts = _.where({type: 'blogpost'});
*
* getBlogposts(docs)
* // => {type: 'blogpost', title: 'foo'}
* // => {type: 'blogpost', title: 'bar'}
*/
Stream.prototype.where = function (props) {
return this.filter(function (x) {
for (var k in props) {
if (x[k] !== props[k]) {
return false;
}
}
return true;
});
};
exposeMethod('where');
/**
* Takes two Streams and returns a Stream of corresponding pairs.
*
* @id zip
* @section Higher-order Streams
* @name Stream.zip(ys)
* @param {Array | Stream} ys - the other stream to combine values with
* @api public
*
* _(['a', 'b', 'c']).zip([1, 2, 3]) // => ['a', 1], ['b', 2], ['c', 3]
*/
Stream.prototype.zip = function (ys) {
ys = _(ys);
var xs = this;
var returned = 0;
var z = [];
function nextValue(index, max, src, push, next) {
src.pull(function (err, x) {
if (err) {
push(err);
nextValue(index, max, src, push, next);
}
else if (x === _.nil) {
push(null, nil);
}
else {
returned++;
z[index] = x;
if (returned === max) {
push(null, z);
next();
}
}
});
}
return _(function (push, next) {
returned = 0;
z = [];
nextValue(0, 2, xs, push, next);
nextValue(1, 2, ys, push, next);
});
};
exposeMethod('zip');
/**
* Takes one Stream and batches incoming data into arrays of given length
*
* @id batch
* @section Transforms
* @name Stream.batch(n)
* @param {Number} n - length of the array to batch
* @api public
*
* _([1, 2, 3, 4, 5]).batch(2) // => [1, 2], [3, 4], [5]
*/
Stream.prototype.batch = function (n) {
var batched = [];
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
} else if (x === nil) {
if (batched.length > 0) {
push(null, batched);
}
push(null, nil);
} else {
batched.push(x);
if (batched.length === n) {
push(null, batched);
batched = [];
}
next();
}
});
};
exposeMethod('batch');
/**
* Creates a new Stream with the separator interspersed between the elements of the source.
*
* intersperse is effectively the inverse of [splitBy](#splitBy).
*
* @id intersperse
* @section Transforms
* @name Stream.intersperse(sep)
* @param sep - the value to intersperse between the source elements
* @api public
*
* _(['ba', 'a', 'a']).intersperse('n') // => ba, n, a, n, a
* _(['mississippi']).splitBy('ss').intersperse('ss') // => mi, ss, i, ss, ippi
* _(['foo']).intersperse('bar') // => foo
*/
Stream.prototype.intersperse = function (separator) {
var started = false;
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
} else if (x === nil) {
push(null, nil);
} else {
if (started) {
push(null, separator);
} else {
started = true;
}
push(null, x);
next();
}
});
};
exposeMethod('intersperse');
/**
* Splits the source Stream by a separator and emits the pieces in between, much like splitting a string.
*
* splitBy is effectively the inverse of [intersperse](#intersperse).
*
* @id splitBy
* @section Transforms
* @name Stream.splitBy(sep)
* @param sep - the separator to split on
* @api public
*
* _(['mis', 'si', 's', 'sippi']).splitBy('ss') // => mi, i, ippi
* _(['ba', 'a', 'a']).intersperse('n').splitBy('n') // => ba, a, a
* _(['foo']).splitBy('bar') // => foo
*/
Stream.prototype.splitBy = function (sep) {
var decoder = new Decoder();
var buffer = '';
function drain(x, push) {
buffer = buffer + decoder.write(x);
var pieces = buffer.split(sep);
buffer = pieces.pop();
pieces.forEach(function (piece) {
push(null, piece);
});
}
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
} else if (x === nil) {
drain(decoder.end(), push);
if (buffer) push(null, buffer);
push(null, nil);
} else {
drain(x, push);
next();
}
});
};
exposeMethod('splitBy');
/**
* [splitBy](#splitBy) over newlines.
*
* @id split
* @section Transforms
* @name Stream.split()
* @api public
*
* _(['a\n', 'b\nc\n', 'd', '\ne']).split() // => a, b, c, d, e
* _(['a\r\nb\nc']]).split() // => a, b, c
*/
Stream.prototype.split = function () {
return this.splitBy(/\r?\n/);
};
exposeMethod('split');
/**
* Creates a new Stream with the first `n` values from the source.
*
* @id take
* @section Transforms
* @name Stream.take(n)
* @param {Number} n - integer representing number of values to read from source
* @api public
*
* _([1, 2, 3, 4]).take(2) // => 1, 2
*/
Stream.prototype.take = function (n) {
if (n === 0) {
return _([]);
}
var s = this.consume(function (err, x, push, next) {
//console.log(['take', err, x, n]);
if (err) {
push(err);
if (n > 0) {
next();
}
else {
push(null, nil);
}
}
else if (x === nil) {
push(null, nil);
}
else {
n--;
push(null, x);
if (n > 0) {
next();
}
else {
push(null, nil);
}
}
});
s.id = 'take:' + s.id;
return s;
};
exposeMethod('take');
/**
* Creates a new Stream with only the first value from the source.
*
* @id head
* @section Transforms
* @name Stream.head()
* @api public
*
* _([1, 2, 3, 4]).head() // => 1
*/
Stream.prototype.head = function () {
return this.take(1);
};
exposeMethod('head');
/**
* Drops all values from the Stream apart from the last one (if any).
*
* @id last
* @section Transforms
* @name Stream.last()
* @api public
*
* _([1, 2, 3, 4]).last() // => 4
*/
Stream.prototype.last = function () {
var nothing = {};
var prev = nothing;
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
}
else if (x === nil) {
if (prev !== nothing) {
push(null, prev);
}
push(null, nil);
}
else {
prev = x;
next();
}
});
};
exposeMethod('last');
/**
* Passes the current Stream to a function, returning the result. Can also
* be used to pipe the current Stream through another Stream. It will always
* return a Highland Stream (instead of the piped to target directly as in
* Node.js).
*
* @id through
* @section Higher-order Streams
* @name Stream.through(target)
* @api public
*
* function oddDoubler(s) {
* return s.filter(function (x) {
* return x % 2; // odd numbers only
* })
* .map(function (x) {
* return x * 2;
* });
* }
*
* _([1, 2, 3, 4]).through(oddDoubler).toArray(function (xs) {
* // xs will be [2, 6]
* });
*
* // Can also be used with Node Through Streams
* _(filenames).through(jsonParser).map(function (obj) {
* // ...
* });
*/
Stream.prototype.through = function (target) {
if (_.isFunction(target)) {
return target(this);
}
else {
var output = _();
target.pause();
this.pipe(target).pipe(output);
return output;
}
};
exposeMethod('through');
/**
* Creates a 'Through Stream', which passes data through a pipeline
* of functions or other through Streams. This is particularly useful
* when combined with partial application of Highland functions to expose a
* Node-compatible Through Stream.
*
* This is not a method on a Stream, and it only exposed at the top-level
* as `_.pipeline`. It takes an arbitrary number of arguments.
*
* @id pipeline
* @section Higher-order Streams
* @name _.pipeline(...)
* @api public
*
* var through = _.pipeline(
* _.map(parseJSON),
* _.filter(isBlogpost),
* _.reduce(collectCategories)
* _.through(otherPipeline)
* );
*
* readStream.pipe(through).pipe(outStream);
*
* // Alternatively, you can use pipeline to manipulate a stream in
* // the chained method call style:
*
* var through2 = _.pipeline(function (s) {
* return s.map(parseJSON).filter(isBlogpost); // etc.
* });
*/
_.pipeline = function (/*through...*/) {
if (!arguments.length) {
return _();
}
var start = arguments[0], rest;
if (!_.isStream(start) && !_.isFunction(start.resume)) {
// not a Highland stream or Node stream, start with empty stream
start = _();
rest = slice.call(arguments);
}
else {
// got a stream as first argument, co-erce to Highland stream
start = _(start);
rest = slice.call(arguments, 1);
}
var end = rest.reduce(function (src, dest) {
return src.through(dest);
}, start);
var wrapper = _(function (push, next) {
end.pull(function (err, x) {
if (err) {
wrapper._send(err);
next();
}
else if (x === nil) {
wrapper._send(null, nil);
}
else {
wrapper._send(null, x);
next();
}
});
});
wrapper.write = function (x) {
start.write(x);
};
return wrapper;
};
/**
* Reads values from a Stream of Streams, emitting them on a Single output
* Stream. This can be thought of as a flatten, just one level deep. Often
* used for resolving asynchronous actions such as a HTTP request or reading
* a file.
*
* @id sequence
* @section Higher-order Streams
* @name Stream.sequence()
* @api public
*
* var nums = _([
* _([1, 2, 3]),
* _([4, 5, 6])
* ]);
*
* nums.sequence() // => 1, 2, 3, 4, 5, 6
*
* // using sequence to read from files in series
* filenames.map(readFile).sequence()
*/
Stream.prototype.sequence = function () {
var original = this;
var curr = this;
return _(function (push, next) {
curr.pull(function (err, x) {
if (err) {
push(err);
return next();
}
else if (_.isArray(x)) {
if (onOriginalStream()) {
// just send all values from array directly
x.forEach(function (y) {
push(null, y);
});
} else {
push(null, x);
}
return next();
}
else if (_.isStream(x)) {
if (onOriginalStream()) {
// switch to reading new stream
curr = x;
return next();
}
else {
// sequence only goes 1 level deep
push(null, x);
return next();
}
}
else if (x === nil) {
if (onOriginalStream()) {
push(null, nil);
}
else {
// resume reading from original
curr = original;
return next();
}
}
else {
if (onOriginalStream()) {
// we shouldn't be getting non-stream (or array)
// values from the top-level stream
push(new Error(
'Expected Stream, got ' + (typeof x)
));
return next();
}
else {
push(null, x);
return next();
}
}
});
});
function onOriginalStream() {
return curr === original;
}
};
exposeMethod('sequence');
/**
* An alias for the [sequence](#sequence) method.
*
* @id series
* @section Higher-order Streams
* @name Stream.series()
* @api public
*
* filenames.map(readFile).series()
*/
Stream.prototype.series = Stream.prototype.sequence;
_.series = _.sequence;
/**
* Recursively reads values from a Stream which may contain nested Streams
* or Arrays. As values or errors are encountered, they are emitted on a
* single output Stream.
*
* @id flatten
* @section Higher-order Streams
* @name Stream.flatten()
* @api public
*
* _([1, [2, 3], [[4]]]).flatten(); // => 1, 2, 3, 4
*
* var nums = _(
* _([1, 2, 3]),
* _([4, _([5, 6]) ])
* );
*
* nums.flatten(); // => 1, 2, 3, 4, 5, 6
*/
Stream.prototype.flatten = function () {
var curr = this;
var stack = [];
return _(function (push, next) {
curr.pull(function (err, x) {
if (err) {
push(err);
return next();
}
if (_.isArray(x)) {
x = _(x);
}
if (_.isStream(x)) {
stack.push(curr);
curr = x;
next();
}
else if (x === nil) {
if (stack.length) {
curr = stack.pop();
next();
}
else {
push(null, nil);
}
}
else {
push(null, x);
next();
}
});
});
};
exposeMethod('flatten');
/**
* Takes a Stream of Streams and reads from them in parallel, buffering
* the results until they can be returned to the consumer in their original
* order.
*
* @id parallel
* @section Higher-order Streams
* @name Stream.parallel(n)
* @param {Number} n - the maximum number of concurrent reads/buffers
* @api public
*
* var readFile = _.wrapCallback(fs.readFile);
* var filenames = _(['foo.txt', 'bar.txt', 'baz.txt']);
*
* // read from up to 10 files at once
* filenames.map(readFile).parallel(10);
*/
Stream.prototype.parallel = function (n) {
var source = this;
var running = [];
var ended = false;
var reading_source = false;
return _(function (push, next) {
if (running.length && running[0].buffer.length) {
// send buffered data
var buf = running[0].buffer;
for (var i = 0; i < buf.length; i++) {
if (buf[i][1] === nil) {
// this stream has ended
running.shift();
return next();
}
else {
// send the buffered output
push.apply(null, buf[i]);
}
}
// still waiting for more data before we can shift
// the running array...
}
else if (running.length < n && !ended && !reading_source) {
// get another stream if not already waiting for one
reading_source = true;
source.pull(function (err, x) {
reading_source = false;
if (err) {
push(err);
}
else if (x === nil) {
ended = true;
}
else {
// got a new source, add it to the running array
var run = {stream: x, buffer: []};
running.push(run);
x.consume(function (err, y, _push, _next) {
if (running[0] === run) {
// current output stream
if (y === nil) {
// remove self from running and check
// to see if we need to read from source again
running.shift();
next();
}
else {
// push directly onto parallel output stream
push(err, y);
}
}
else {
// we're reading ahead, buffer the output
run.buffer.push([err, y]);
}
if (y !== nil) {
// keep reading until we hit nil
_next();
}
}).resume();
}
// check if we need to get any more streams
return next();
});
}
else if (!running.length && ended) {
// nothing more to do
push(null, nil);
}
else {
// wait for more data to arrive from running streams
}
});
};
exposeMethod('parallel');
/**
* Switches source to an alternate Stream if the current Stream is empty.
*
* @id otherwise
* @section Higher-order Streams
* @name Stream.otherwise(ys)
* @param {Stream} ys - alternate stream to use if this stream is empty
* @api public
*
* _([1,2,3]).otherwise(['foo']) // => 1, 2, 3
* _([]).otherwise(['foo']) // => 'foo'
*
* _.otherwise(_(['foo']), _([1,2,3])) // => 1, 2, 3
* _.otherwise(_(['foo']), _([])) // => 'foo'
*/
Stream.prototype.otherwise = function (ys) {
var xs = this;
return xs.consume(function (err, x, push, next) {
if (err) {
// got an error, just keep going
push(err);
next();
} else if (x === nil) {
// hit the end without redirecting to xs, use alternative
next(ys);
}
else {
// got a value, push it, then redirect to xs
push(null, x);
next(xs);
}
});
};
exposeMethod('otherwise');
/**
* Adds a value to the end of a Stream.
*
* @id append
* @section Transforms
* @name Stream.append(y)
* @param y - the value to append to the Stream
* @api public
*
* _([1, 2, 3]).append(4) // => 1, 2, 3, 4
*/
Stream.prototype.append = function (y) {
return this.consume(function (err, x, push, next) {
if (x === nil) {
push(null, y);
push(null, _.nil);
}
else {
push(err, x);
next();
}
});
};
exposeMethod('append');
/**
* Boils down a Stream to a single value. The memo is the initial state
* of the reduction, and each successive step of it should be returned by
* the iterator function. The iterator is passed two arguments:
* the memo and the next value.
*
* If the iterator throws an error, the reduction stops and the resulting
* stream will emit that error instead of a value.
*
* @id reduce
* @section Transforms
* @name Stream.reduce(memo, iterator)
* @param memo - the initial state of the reduction
* @param {Function} iterator - the function which reduces the values
* @api public
*
* var add = function (a, b) {
* return a + b;
* };
*
* _([1, 2, 3, 4]).reduce(0, add) // => 10
*/
Stream.prototype.reduce = function (z, f) {
// This can't be implemented with scan(), because we don't know if the
// errors that we see from the scan were thrown by the iterator or just
// passed through from the source stream.
return this.consume(function (err, x, push, next) {
if (x === nil) {
push(null, z);
push(null, _.nil);
}
else if (err) {
push(err);
next();
}
else {
try {
z = f(z, x);
} catch (e) {
push(e);
push(null, _.nil);
return;
}
next();
}
});
};
exposeMethod('reduce');
/**
* Same as [reduce](#reduce), but uses the first element as the initial
* state instead of passing in a `memo` value.
*
* @id reduce1
* @section Transforms
* @name Stream.reduce1(iterator)
* @param {Function} iterator - the function which reduces the values
* @api public
*
* _([1, 2, 3, 4]).reduce1(add) // => 10
*/
Stream.prototype.reduce1 = function (f) {
var self = this;
return _(function (push, next) {
self.pull(function (err, x) {
if (err) {
push(err);
next();
} else if (x === nil) {
push(null, nil);
}
else {
next(self.reduce(x, f));
}
});
});
};
exposeMethod('reduce1');
/**
* Groups all values into an Array and passes down the stream as a single
* data event. This is a bit like doing [toArray](#toArray), but instead
* of accepting a callback and causing a *thunk*, it passes the value on.
*
* @id collect
* @section Transforms
* @name Stream.collect()
* @api public
*
* _(['foo', 'bar']).collect().toArray(function (xs) {
* // xs will be [['foo', 'bar']]
* });
*/
Stream.prototype.collect = function () {
var xs = [];
return this.consume(function (err, x, push, next) {
if (err) {
push(err);
next();
}
else if (x === nil) {
push(null, xs);
push(null, nil);
}
else {
xs.push(x);
next();
}
});
};
exposeMethod('collect');
/**
* Like [reduce](#reduce), but emits each intermediate value of the
* reduction as it is calculated.
*
* If the iterator throws an error, the scan will stop and the stream will
* emit that error. Any intermediate values that were produced before the
* error will still be emitted.
*
* @id scan
* @section Transforms
* @name Stream.scan(memo, iterator)
* @param memo - the initial state of the reduction
* @param {Function} iterator - the function which reduces the values
* @api public
*
* _([1, 2, 3, 4]).scan(0, add) // => 0, 1, 3, 6, 10
*/
Stream.prototype.scan = function (z, f) {
var self = this;
return _([z]).concat(
self.consume(function (err, x, push, next) {
if (x === nil) {
push(null, _.nil);
}
else if (err) {
push(err);
next();
}
else {
try {
z = f(z, x);
} catch (e) {
push(e);
push(null, _.nil);
return;
}
push(null, z);
next();
}
})
);
};
exposeMethod('scan');
/**
* Same as [scan](#scan), but uses the first element as the initial
* state instead of passing in a `memo` value.
*
* @id scan1
* @section Transforms
* @name Stream.scan1(iterator)
* @param {Function} iterator - the function which reduces the values
* @api public
*
* _([1, 2, 3, 4]).scan1(add) // => 1, 3, 6, 10
*/
Stream.prototype.scan1 = function (f) {
var self = this;
return _(function (push, next) {
self.pull(function (err, x) {
if (err) {
push(err);
next();
} else if (x === nil) {
push(null, nil);
}
else {
next(self.scan(x, f));
}
});
});
};
exposeMethod('scan1');
/**
* Concatenates a Stream to the end of this Stream.
*
* Be aware that in the top-level export, the args may be in the reverse
* order to what you'd expect `_([a], [b]) => b, a`, as this follows the
* convention of other top-level exported functions which do `x` to `y`.
*
* @id concat
* @section Higher-order Streams
* @name Stream.concat(ys)
* @params {Stream | Array} ys - the values to concatenate onto this Stream
* @api public
*
* _([1, 2]).concat([3, 4]) // => 1, 2, 3, 4
* _.concat([3, 4], [1, 2]) // => 1, 2, 3, 4
*/
Stream.prototype.concat = function (ys) {
ys = _(ys);
return this.consume(function (err, x, push, next) {
if (x === nil) {
next(ys);
}
else {
push(err, x);
next();
}
});
};
exposeMethod('concat');
/**
* Takes a Stream of Streams and merges their values and errors into a
* single new Stream. The merged stream ends when all source streams have
* ended.
*
* Note that no guarantee is made with respect to the order in which
* values for each stream end up in the merged stream. Values in the
* merged stream will, however, respect the order they were emitted from
* their respective streams.
*
* @id merge
* @section Higher-order Streams
* @name Stream.merge()
* @api public
*
* var txt = _(['foo.txt', 'bar.txt']).map(readFile)
* var md = _(['baz.md']).map(readFile)
*
* _([txt, md]).merge();
* // => contents of foo.txt, bar.txt and baz.txt in the order they were read
*/
Stream.prototype.merge = function () {
var self = this;
var resuming = false;
var go_next = false;
var srcs;
return _(function (push, next) {
var safeNext = function () {
if (!resuming) {
next();
}
else {
go_next = true;
}
};
if (!srcs) {
self.errors(push).toArray(function (xs) {
srcs = xs;
srcs.forEach(function (src) {
src.on('end', function () {
srcs = srcs.filter(function (s) {
return s !== src;
});
safeNext();
});
src.on('data', function (x) {
src.pause();
push(null, x);
safeNext();
});
src.on('error', function (err) {
push(err);
safeNext();
});
});
next();
});
}
else if (srcs.length === 0) {
push(null, nil);
}
else {
go_next = false;
resuming = true;
srcs.forEach(function (src) {
src.resume();
});
resuming = false;
if (go_next) {
next();
}
}
});
};
exposeMethod('merge');
/**
* Calls a named method on each object from the Stream - returning
* a new stream with the result of those calls.
*
* @id invoke
* @section Transforms
* @name Stream.invoke(method, args)
* @param {String} method - the method name to call
* @param {Array} args - the arguments to call the method with
* @api public
*
* _(['foo', 'bar']).invoke('toUpperCase', []) // => FOO, BAR
*
* filenames.map(readFile).sequence().invoke('toString', ['utf8']);
*/
Stream.prototype.invoke = function (method, args) {
return this.map(function (x) {
return x[method].apply(x, args);
});
};
exposeMethod('invoke');
/**
* Ensures that only one data event is push downstream (or into the buffer)
* every `ms` milliseconds, any other values are dropped.
*
* @id throttle
* @section Transforms
* @name Stream.throttle(ms)
* @param {Number} ms - the minimum milliseconds between each value
* @api public
*
* _('mousemove', document).throttle(1000);
*/
Stream.prototype.throttle = function (ms) {
var s = new Stream();
var last = 0 - ms;
var _write = s.write;
s.write = function (x) {
var now = new Date().getTime();
if (_._isStreamError(x) || x === nil) {
return _write.apply(this, arguments);
}
else if (now - ms >= last) {
last = now;
return _write.apply(this, arguments);
}
};
this._addConsumer(s);
return s;
};
exposeMethod('throttle');
/**
* Holds off pushing data events downstream until there has been no more
* data for `ms` milliseconds. Sends the last value that occurred before
* the delay, discarding all other values.
*
* @id debounce
* @section Transforms
* @name Stream.debounce(ms)
* @param {Number} ms - the milliseconds to wait before sending data
* @api public
*
* // sends last keyup event after user has stopped typing for 1 second
* $('keyup', textbox).debounce(1000);
*/
Stream.prototype.debounce = function (ms) {
var s = new Stream();
var t = null;
var nothing = {};
var last = nothing;
var _write = s.write;
s.write = function (x) {
if (_._isStreamError(x)) {
// let errors through regardless
return _write.apply(this, arguments);
}
else if (x === nil) {
if (t) {
clearTimeout(t);
}
if (last !== nothing) {
_write.call(s, last);
}
return _write.apply(this, arguments);
}
else {
last = x;
if (t) {
clearTimeout(t);
}
t = setTimeout(function () {
_write.call(s, last);
}, ms);
return !this.paused;
}
};
this._addConsumer(s);
return s;
};
exposeMethod('debounce');
/**
* Creates a new Stream, which when read from, only returns the last
* seen value from the source. The source stream does not experience
* back-pressure. Useful if you're using a Stream to model a changing
* property which you need to query periodically.
*
* @id latest
* @section Transforms
* @name Stream.latest()
* @api public
*
* // slowThing will always get the last known mouse position
* // when it asks for more data from the mousePosition stream
* mousePosition.latest().map(slowThing)
*/
Stream.prototype.latest = function () {
var s = new Stream();
var _write = s.write;
s.pause = function () {
this.paused = true;
// do not force parent to checkBackpressure
};
s.write = function (x) {
if (_._isStreamError(x)) {
// pass errors straight through
_write.call(this, x);
}
else if (x === nil) {
_write.call(this, x);
}
else {
if (this.paused) {
this._incoming = this._incoming.filter(function (x) {
// remove any existing values from buffer
return _._isStreamError(x) || x === nil;
});
this._incoming.push(x);
}
else {
_write.call(this, x);
}
}
// never push back
return true;
};
this._addConsumer(s);
s.resume();
return s;
};
exposeMethod('latest');
/**
* Returns values from an Object as a Stream. Reads properties
* lazily, so if you don't read from all keys on an object, not
* all properties will be read from (may have an effect where getters
* are used).
*
* @id values
* @section Objects
* @name _.values(obj)
* @param {Object} obj - the object to return values from
* @api public
*
* _.values({foo: 1, bar: 2, baz: 3}) // => 1, 2, 3
*/
_.values = function (obj) {
return _.keys(obj).map(function (k) {
return obj[k];
});
};
/**
* Returns keys from an Object as a Stream.
*
* @id keys
* @section Objects
* @name _.keys(obj)
* @param {Object} obj - the object to return keys from
* @api public
*
* _.keys({foo: 1, bar: 2, baz: 3}) // => 'foo', 'bar', 'baz'
*/
_.keys = function (obj) {
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return _(keys);
};
/**
* Returns key/value pairs for an Object as a Stream. Reads properties
* lazily, so if you don't read from all keys on an object, not
* all properties will be read from (may have an effect where getters
* are used).
*
* @id pairs
* @section Objects
* @name _.pairs(obj)
* @param {Object} obj - the object to return key/value pairs from
* @api public
*
* _.pairs({foo: 1, bar: 2}) // => ['foo', 1], ['bar', 2]
*/
_.pairs = function (obj) {
return _.keys(obj).map(function (k) {
return [k, obj[k]];
});
};
/**
* Extends one object with the properties of another. **Note:** The
* arguments are in the reverse order of other libraries such as
* underscore. This is so it follows the convention of other functions in
* this library and so you can more meaningfully partially apply it.
*
* @id extend
* @section Objects
* @name _.extend(a, b)
* @param {Object} a - the properties to extend b with
* @param {Object} b - the original object to extend
* @api public
*
* _.extend({name: 'bar'}, {name: 'foo', price: 20})
* // => {name: 'bar', price: 20}
*
* // example of partial application
* var publish = _.extend({published: true});
*
* publish({title: 'test post'})
* // => {title: 'test post', published: true}
*/
_.extend = _.curry(function (extensions, target) {
for (var k in extensions) {
if (extensions.hasOwnProperty(k)) {
target[k] = extensions[k];
}
}
return target;
});
/**
* Returns a property from an object.
*
* @id get
* @section Objects
* @name _.get(prop, obj)
* @param {String} prop - the property to return
* @param {Object} obj - the object to read properties from
* @api public
*
* var obj = {foo: 'bar', baz: 123};
* _.get('foo', obj) // => 'bar'
*
* // making use of partial application
* var posts = [
* {title: 'one'},
* {title: 'two'},
* {title: 'three'}
* ];
*
* _(posts).map(_.get('title')) // => 'one', 'two', 'three'
*/
_.get = _.curry(function (prop, obj) {
return obj[prop];
});
/**
* Updates a property on an object, returning the updated object.
*
* @id set
* @section Objects
* @name _.set(prop, value, obj)
* @param {String} prop - the property to return
* @param value - the value to set the property to
* @param {Object} obj - the object to set properties on
* @api public
*
* var obj = {foo: 'bar', baz: 123};
* _.set('foo', 'wheeee', obj) // => {foo: 'wheeee', baz: 123}
*
* // making use of partial application
* var publish = _.set('published', true);
*
* publish({title: 'example'}) // => {title: 'example', published: true}
*/
_.set = _.curry(function (prop, val, obj) {
obj[prop] = val;
return obj;
});
/**
* Logs values to the console, a simple wrapper around `console.log` that
* it suitable for passing to other functions by reference without having to
* call `bind`.
*
* @id log
* @section Utils
* @name _.log(args..)
* @api public
*
* _.log('Hello, world!');
*
* _([1, 2, 3, 4]).each(_.log);
*/
_.log = function () {
console.log.apply(console, arguments);
};
/**
* Wraps a node-style async function which accepts a callback, transforming
* it to a function which accepts the same arguments minus the callback and
* returns a Highland Stream instead. Only the first argument to the
* callback (or an error) will be pushed onto the Stream.
*
* @id wrapCallback
* @section Utils
* @name _.wrapCallback(f)
* @param {Function} f - the node-style function to wrap
* @api public
*
* var fs = require('fs');
*
* var readFile = _.wrapCallback(fs.readFile);
*
* readFile('example.txt').apply(function (data) {
* // data is now the contents of example.txt
* });
*/
_.wrapCallback = function (f) {
return function () {
var args = slice.call(arguments);
return _(function (push) {
var cb = function (err, x) {
if (err) {
push(err);
}
else {
push(null, x);
}
push(null, nil);
};
f.apply(null, args.concat([cb]));
});
};
};
/**
* Add two values. Can be partially applied.
*
* @id add
* @section Operators
* @name _.add(a, b)
* @api public
*
* add(1, 2) === 3
* add(1)(5) === 6
*/
_.add = _.curry(function (a, b) {
return a + b;
});
/**
* Perform logical negation on a value. If `x` is truthy then returns false,
* otherwise returns true.
*
* @id not
* @section Operators
* @name _.not(x)
* @param x - the value to negate
* @api public
*
* _.not(true) // => false
* _.not(false) // => true
*/
_.not = function (x) {
return !x;
};
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"_process":16,"events":12,"string_decoder":30,"util":32}],8:[function(require,module,exports){
},{}],9:[function(require,module,exports){
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <[email protected]> <http://feross.org>
* @license MIT
*/
var base64 = require('base64-js')
var ieee754 = require('ieee754')
exports.Buffer = Buffer
exports.SlowBuffer = Buffer
exports.INSPECT_MAX_BYTES = 50
Buffer.poolSize = 8192
/**
* If `TYPED_ARRAY_SUPPORT`:
* === true Use Uint8Array implementation (fastest)
* === false Use Object implementation (most compatible, even IE6)
*
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
* Opera 11.6+, iOS 4.2+.
*
* Note:
*
* - Implementation must support adding new properties to `Uint8Array` instances.
* Firefox 4-29 lacked support, fixed in Firefox 30+.
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
*
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
*
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
* incorrect length in some situations.
*
* We detect these buggy browsers and set `TYPED_ARRAY_SUPPORT` to `false` so they will
* get the Object implementation, which is slower but will work correctly.
*/
var TYPED_ARRAY_SUPPORT = (function () {
try {
var buf = new ArrayBuffer(0)
var arr = new Uint8Array(buf)
arr.foo = function () { return 42 }
return 42 === arr.foo() && // typed array instances can be augmented
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
new Uint8Array(1).subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
} catch (e) {
return false
}
})()
/**
* Class: Buffer
* =============
*
* The Buffer constructor returns instances of `Uint8Array` that are augmented
* with function properties for all the node `Buffer` API functions. We use
* `Uint8Array` so that square bracket notation works as expected -- it returns
* a single octet.
*
* By augmenting the instances, we can avoid modifying the `Uint8Array`
* prototype.
*/
function Buffer (subject, encoding, noZero) {
if (!(this instanceof Buffer))
return new Buffer(subject, encoding, noZero)
var type = typeof subject
// Find the length
var length
if (type === 'number')
length = subject > 0 ? subject >>> 0 : 0
else if (type === 'string') {
if (encoding === 'base64')
subject = base64clean(subject)
length = Buffer.byteLength(subject, encoding)
} else if (type === 'object' && subject !== null) { // assume object is array-like
if (subject.type === 'Buffer' && isArray(subject.data))
subject = subject.data
length = +subject.length > 0 ? Math.floor(+subject.length) : 0
} else
throw new Error('First argument needs to be a number, array or string.')
var buf
if (TYPED_ARRAY_SUPPORT) {
// Preferred: Return an augmented `Uint8Array` instance for best performance
buf = Buffer._augment(new Uint8Array(length))
} else {
// Fallback: Return THIS instance of Buffer (created by `new`)
buf = this
buf.length = length
buf._isBuffer = true
}
var i
if (TYPED_ARRAY_SUPPORT && typeof subject.byteLength === 'number') {
// Speed optimization -- use set if we're copying from a typed array
buf._set(subject)
} else if (isArrayish(subject)) {
// Treat array-ish objects as a byte array
if (Buffer.isBuffer(subject)) {
for (i = 0; i < length; i++)
buf[i] = subject.readUInt8(i)
} else {
for (i = 0; i < length; i++)
buf[i] = ((subject[i] % 256) + 256) % 256
}
} else if (type === 'string') {
buf.write(subject, 0, encoding)
} else if (type === 'number' && !TYPED_ARRAY_SUPPORT && !noZero) {
for (i = 0; i < length; i++) {
buf[i] = 0
}
}
return buf
}
// STATIC METHODS
// ==============
Buffer.isEncoding = function (encoding) {
switch (String(encoding).toLowerCase()) {
case 'hex':
case 'utf8':
case 'utf-8':
case 'ascii':
case 'binary':
case 'base64':
case 'raw':
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return true
default:
return false
}
}
Buffer.isBuffer = function (b) {
return !!(b != null && b._isBuffer)
}
Buffer.byteLength = function (str, encoding) {
var ret
str = str.toString()
switch (encoding || 'utf8') {
case 'hex':
ret = str.length / 2
break
case 'utf8':
case 'utf-8':
ret = utf8ToBytes(str).length
break
case 'ascii':
case 'binary':
case 'raw':
ret = str.length
break
case 'base64':
ret = base64ToBytes(str).length
break
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
ret = str.length * 2
break
default:
throw new Error('Unknown encoding')
}
return ret
}
Buffer.concat = function (list, totalLength) {
assert(isArray(list), 'Usage: Buffer.concat(list[, length])')
if (list.length === 0) {
return new Buffer(0)
} else if (list.length === 1) {
return list[0]
}
var i
if (totalLength === undefined) {
totalLength = 0
for (i = 0; i < list.length; i++) {
totalLength += list[i].length
}
}
var buf = new Buffer(totalLength)
var pos = 0
for (i = 0; i < list.length; i++) {
var item = list[i]
item.copy(buf, pos)
pos += item.length
}
return buf
}
Buffer.compare = function (a, b) {
assert(Buffer.isBuffer(a) && Buffer.isBuffer(b), 'Arguments must be Buffers')
var x = a.length
var y = b.length
for (var i = 0, len = Math.min(x, y); i < len && a[i] === b[i]; i++) {}
if (i !== len) {
x = a[i]
y = b[i]
}
if (x < y) {
return -1
}
if (y < x) {
return 1
}
return 0
}
// BUFFER INSTANCE METHODS
// =======================
function hexWrite (buf, string, offset, length) {
offset = Number(offset) || 0
var remaining = buf.length - offset
if (!length) {
length = remaining
} else {
length = Number(length)
if (length > remaining) {
length = remaining
}
}
// must be an even number of digits
var strLen = string.length
assert(strLen % 2 === 0, 'Invalid hex string')
if (length > strLen / 2) {
length = strLen / 2
}
for (var i = 0; i < length; i++) {
var byte = parseInt(string.substr(i * 2, 2), 16)
assert(!isNaN(byte), 'Invalid hex string')
buf[offset + i] = byte
}
return i
}
function utf8Write (buf, string, offset, length) {
var charsWritten = blitBuffer(utf8ToBytes(string), buf, offset, length)
return charsWritten
}
function asciiWrite (buf, string, offset, length) {
var charsWritten = blitBuffer(asciiToBytes(string), buf, offset, length)
return charsWritten
}
function binaryWrite (buf, string, offset, length) {
return asciiWrite(buf, string, offset, length)
}
function base64Write (buf, string, offset, length) {
var charsWritten = blitBuffer(base64ToBytes(string), buf, offset, length)
return charsWritten
}
function utf16leWrite (buf, string, offset, length) {
var charsWritten = blitBuffer(utf16leToBytes(string), buf, offset, length)
return charsWritten
}
Buffer.prototype.write = function (string, offset, length, encoding) {
// Support both (string, offset, length, encoding)
// and the legacy (string, encoding, offset, length)
if (isFinite(offset)) {
if (!isFinite(length)) {
encoding = length
length = undefined
}
} else { // legacy
var swap = encoding
encoding = offset
offset = length
length = swap
}
offset = Number(offset) || 0
var remaining = this.length - offset
if (!length) {
length = remaining
} else {
length = Number(length)
if (length > remaining) {
length = remaining
}
}
encoding = String(encoding || 'utf8').toLowerCase()
var ret
switch (encoding) {
case 'hex':
ret = hexWrite(this, string, offset, length)
break
case 'utf8':
case 'utf-8':
ret = utf8Write(this, string, offset, length)
break
case 'ascii':
ret = asciiWrite(this, string, offset, length)
break
case 'binary':
ret = binaryWrite(this, string, offset, length)
break
case 'base64':
ret = base64Write(this, string, offset, length)
break
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
ret = utf16leWrite(this, string, offset, length)
break
default:
throw new Error('Unknown encoding')
}
return ret
}
Buffer.prototype.toString = function (encoding, start, end) {
var self = this
encoding = String(encoding || 'utf8').toLowerCase()
start = Number(start) || 0
end = (end === undefined) ? self.length : Number(end)
// Fastpath empty strings
if (end === start)
return ''
var ret
switch (encoding) {
case 'hex':
ret = hexSlice(self, start, end)
break
case 'utf8':
case 'utf-8':
ret = utf8Slice(self, start, end)
break
case 'ascii':
ret = asciiSlice(self, start, end)
break
case 'binary':
ret = binarySlice(self, start, end)
break
case 'base64':
ret = base64Slice(self, start, end)
break
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
ret = utf16leSlice(self, start, end)
break
default:
throw new Error('Unknown encoding')
}
return ret
}
Buffer.prototype.toJSON = function () {
return {
type: 'Buffer',
data: Array.prototype.slice.call(this._arr || this, 0)
}
}
Buffer.prototype.equals = function (b) {
assert(Buffer.isBuffer(b), 'Argument must be a Buffer')
return Buffer.compare(this, b) === 0
}
Buffer.prototype.compare = function (b) {
assert(Buffer.isBuffer(b), 'Argument must be a Buffer')
return Buffer.compare(this, b)
}
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer.prototype.copy = function (target, target_start, start, end) {
var source = this
if (!start) start = 0
if (!end && end !== 0) end = this.length
if (!target_start) target_start = 0
// Copy 0 bytes; we're done
if (end === start) return
if (target.length === 0 || source.length === 0) return
// Fatal error conditions
assert(end >= start, 'sourceEnd < sourceStart')
assert(target_start >= 0 && target_start < target.length,
'targetStart out of bounds')
assert(start >= 0 && start < source.length, 'sourceStart out of bounds')
assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds')
// Are we oob?
if (end > this.length)
end = this.length
if (target.length - target_start < end - start)
end = target.length - target_start + start
var len = end - start
if (len < 100 || !TYPED_ARRAY_SUPPORT) {
for (var i = 0; i < len; i++) {
target[i + target_start] = this[i + start]
}
} else {
target._set(this.subarray(start, start + len), target_start)
}
}
function base64Slice (buf, start, end) {
if (start === 0 && end === buf.length) {
return base64.fromByteArray(buf)
} else {
return base64.fromByteArray(buf.slice(start, end))
}
}
function utf8Slice (buf, start, end) {
var res = ''
var tmp = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; i++) {
if (buf[i] <= 0x7F) {
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
tmp = ''
} else {
tmp += '%' + buf[i].toString(16)
}
}
return res + decodeUtf8Char(tmp)
}
function asciiSlice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; i++) {
ret += String.fromCharCode(buf[i])
}
return ret
}
function binarySlice (buf, start, end) {
return asciiSlice(buf, start, end)
}
function hexSlice (buf, start, end) {
var len = buf.length
if (!start || start < 0) start = 0
if (!end || end < 0 || end > len) end = len
var out = ''
for (var i = start; i < end; i++) {
out += toHex(buf[i])
}
return out
}
function utf16leSlice (buf, start, end) {
var bytes = buf.slice(start, end)
var res = ''
for (var i = 0; i < bytes.length; i += 2) {
res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
}
return res
}
Buffer.prototype.slice = function (start, end) {
var len = this.length
start = ~~start
end = end === undefined ? len : ~~end
if (start < 0) {
start += len;
if (start < 0)
start = 0
} else if (start > len) {
start = len
}
if (end < 0) {
end += len
if (end < 0)
end = 0
} else if (end > len) {
end = len
}
if (end < start)
end = start
if (TYPED_ARRAY_SUPPORT) {
return Buffer._augment(this.subarray(start, end))
} else {
var sliceLen = end - start
var newBuf = new Buffer(sliceLen, undefined, true)
for (var i = 0; i < sliceLen; i++) {
newBuf[i] = this[i + start]
}
return newBuf
}
}
// `get` will be removed in Node 0.13+
Buffer.prototype.get = function (offset) {
console.log('.get() is deprecated. Access using array indexes instead.')
return this.readUInt8(offset)
}
// `set` will be removed in Node 0.13+
Buffer.prototype.set = function (v, offset) {
console.log('.set() is deprecated. Access using array indexes instead.')
return this.writeUInt8(v, offset)
}
Buffer.prototype.readUInt8 = function (offset, noAssert) {
if (!noAssert) {
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset < this.length, 'Trying to read beyond buffer length')
}
if (offset >= this.length)
return
return this[offset]
}
function readUInt16 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val
if (littleEndian) {
val = buf[offset]
if (offset + 1 < len)
val |= buf[offset + 1] << 8
} else {
val = buf[offset] << 8
if (offset + 1 < len)
val |= buf[offset + 1]
}
return val
}
Buffer.prototype.readUInt16LE = function (offset, noAssert) {
return readUInt16(this, offset, true, noAssert)
}
Buffer.prototype.readUInt16BE = function (offset, noAssert) {
return readUInt16(this, offset, false, noAssert)
}
function readUInt32 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val
if (littleEndian) {
if (offset + 2 < len)
val = buf[offset + 2] << 16
if (offset + 1 < len)
val |= buf[offset + 1] << 8
val |= buf[offset]
if (offset + 3 < len)
val = val + (buf[offset + 3] << 24 >>> 0)
} else {
if (offset + 1 < len)
val = buf[offset + 1] << 16
if (offset + 2 < len)
val |= buf[offset + 2] << 8
if (offset + 3 < len)
val |= buf[offset + 3]
val = val + (buf[offset] << 24 >>> 0)
}
return val
}
Buffer.prototype.readUInt32LE = function (offset, noAssert) {
return readUInt32(this, offset, true, noAssert)
}
Buffer.prototype.readUInt32BE = function (offset, noAssert) {
return readUInt32(this, offset, false, noAssert)
}
Buffer.prototype.readInt8 = function (offset, noAssert) {
if (!noAssert) {
assert(offset !== undefined && offset !== null,
'missing offset')
assert(offset < this.length, 'Trying to read beyond buffer length')
}
if (offset >= this.length)
return
var neg = this[offset] & 0x80
if (neg)
return (0xff - this[offset] + 1) * -1
else
return this[offset]
}
function readInt16 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val = readUInt16(buf, offset, littleEndian, true)
var neg = val & 0x8000
if (neg)
return (0xffff - val + 1) * -1
else
return val
}
Buffer.prototype.readInt16LE = function (offset, noAssert) {
return readInt16(this, offset, true, noAssert)
}
Buffer.prototype.readInt16BE = function (offset, noAssert) {
return readInt16(this, offset, false, noAssert)
}
function readInt32 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val = readUInt32(buf, offset, littleEndian, true)
var neg = val & 0x80000000
if (neg)
return (0xffffffff - val + 1) * -1
else
return val
}
Buffer.prototype.readInt32LE = function (offset, noAssert) {
return readInt32(this, offset, true, noAssert)
}
Buffer.prototype.readInt32BE = function (offset, noAssert) {
return readInt32(this, offset, false, noAssert)
}
function readFloat (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
}
return ieee754.read(buf, offset, littleEndian, 23, 4)
}
Buffer.prototype.readFloatLE = function (offset, noAssert) {
return readFloat(this, offset, true, noAssert)
}
Buffer.prototype.readFloatBE = function (offset, noAssert) {
return readFloat(this, offset, false, noAssert)
}
function readDouble (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset + 7 < buf.length, 'Trying to read beyond buffer length')
}
return ieee754.read(buf, offset, littleEndian, 52, 8)
}
Buffer.prototype.readDoubleLE = function (offset, noAssert) {
return readDouble(this, offset, true, noAssert)
}
Buffer.prototype.readDoubleBE = function (offset, noAssert) {
return readDouble(this, offset, false, noAssert)
}
Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset < this.length, 'trying to write beyond buffer length')
verifuint(value, 0xff)
}
if (offset >= this.length) return
this[offset] = value
return offset + 1
}
function writeUInt16 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'trying to write beyond buffer length')
verifuint(value, 0xffff)
}
var len = buf.length
if (offset >= len)
return
for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) {
buf[offset + i] =
(value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
(littleEndian ? i : 1 - i) * 8
}
return offset + 2
}
Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
return writeUInt16(this, value, offset, true, noAssert)
}
Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
return writeUInt16(this, value, offset, false, noAssert)
}
function writeUInt32 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'trying to write beyond buffer length')
verifuint(value, 0xffffffff)
}
var len = buf.length
if (offset >= len)
return
for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) {
buf[offset + i] =
(value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
}
return offset + 4
}
Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
return writeUInt32(this, value, offset, true, noAssert)
}
Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
return writeUInt32(this, value, offset, false, noAssert)
}
Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset < this.length, 'Trying to write beyond buffer length')
verifsint(value, 0x7f, -0x80)
}
if (offset >= this.length)
return
if (value >= 0)
this.writeUInt8(value, offset, noAssert)
else
this.writeUInt8(0xff + value + 1, offset, noAssert)
return offset + 1
}
function writeInt16 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'Trying to write beyond buffer length')
verifsint(value, 0x7fff, -0x8000)
}
var len = buf.length
if (offset >= len)
return
if (value >= 0)
writeUInt16(buf, value, offset, littleEndian, noAssert)
else
writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert)
return offset + 2
}
Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
return writeInt16(this, value, offset, true, noAssert)
}
Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
return writeInt16(this, value, offset, false, noAssert)
}
function writeInt32 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
verifsint(value, 0x7fffffff, -0x80000000)
}
var len = buf.length
if (offset >= len)
return
if (value >= 0)
writeUInt32(buf, value, offset, littleEndian, noAssert)
else
writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert)
return offset + 4
}
Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
return writeInt32(this, value, offset, true, noAssert)
}
Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
return writeInt32(this, value, offset, false, noAssert)
}
function writeFloat (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38)
}
var len = buf.length
if (offset >= len)
return
ieee754.write(buf, value, offset, littleEndian, 23, 4)
return offset + 4
}
Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
return writeFloat(this, value, offset, true, noAssert)
}
Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
return writeFloat(this, value, offset, false, noAssert)
}
function writeDouble (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 7 < buf.length,
'Trying to write beyond buffer length')
verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308)
}
var len = buf.length
if (offset >= len)
return
ieee754.write(buf, value, offset, littleEndian, 52, 8)
return offset + 8
}
Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
return writeDouble(this, value, offset, true, noAssert)
}
Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
return writeDouble(this, value, offset, false, noAssert)
}
// fill(value, start=0, end=buffer.length)
Buffer.prototype.fill = function (value, start, end) {
if (!value) value = 0
if (!start) start = 0
if (!end) end = this.length
assert(end >= start, 'end < start')
// Fill 0 bytes; we're done
if (end === start) return
if (this.length === 0) return
assert(start >= 0 && start < this.length, 'start out of bounds')
assert(end >= 0 && end <= this.length, 'end out of bounds')
var i
if (typeof value === 'number') {
for (i = start; i < end; i++) {
this[i] = value
}
} else {
var bytes = utf8ToBytes(value.toString())
var len = bytes.length
for (i = start; i < end; i++) {
this[i] = bytes[i % len]
}
}
return this
}
Buffer.prototype.inspect = function () {
var out = []
var len = this.length
for (var i = 0; i < len; i++) {
out[i] = toHex(this[i])
if (i === exports.INSPECT_MAX_BYTES) {
out[i + 1] = '...'
break
}
}
return '<Buffer ' + out.join(' ') + '>'
}
/**
* Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
* Added in Node 0.12. Only available in browsers that support ArrayBuffer.
*/
Buffer.prototype.toArrayBuffer = function () {
if (typeof Uint8Array !== 'undefined') {
if (TYPED_ARRAY_SUPPORT) {
return (new Buffer(this)).buffer
} else {
var buf = new Uint8Array(this.length)
for (var i = 0, len = buf.length; i < len; i += 1) {
buf[i] = this[i]
}
return buf.buffer
}
} else {
throw new Error('Buffer.toArrayBuffer not supported in this browser')
}
}
// HELPER FUNCTIONS
// ================
var BP = Buffer.prototype
/**
* Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
*/
Buffer._augment = function (arr) {
arr._isBuffer = true
// save reference to original Uint8Array get/set methods before overwriting
arr._get = arr.get
arr._set = arr.set
// deprecated, will be removed in node 0.13+
arr.get = BP.get
arr.set = BP.set
arr.write = BP.write
arr.toString = BP.toString
arr.toLocaleString = BP.toString
arr.toJSON = BP.toJSON
arr.equals = BP.equals
arr.compare = BP.compare
arr.copy = BP.copy
arr.slice = BP.slice
arr.readUInt8 = BP.readUInt8
arr.readUInt16LE = BP.readUInt16LE
arr.readUInt16BE = BP.readUInt16BE
arr.readUInt32LE = BP.readUInt32LE
arr.readUInt32BE = BP.readUInt32BE
arr.readInt8 = BP.readInt8
arr.readInt16LE = BP.readInt16LE
arr.readInt16BE = BP.readInt16BE
arr.readInt32LE = BP.readInt32LE
arr.readInt32BE = BP.readInt32BE
arr.readFloatLE = BP.readFloatLE
arr.readFloatBE = BP.readFloatBE
arr.readDoubleLE = BP.readDoubleLE
arr.readDoubleBE = BP.readDoubleBE
arr.writeUInt8 = BP.writeUInt8
arr.writeUInt16LE = BP.writeUInt16LE
arr.writeUInt16BE = BP.writeUInt16BE
arr.writeUInt32LE = BP.writeUInt32LE
arr.writeUInt32BE = BP.writeUInt32BE
arr.writeInt8 = BP.writeInt8
arr.writeInt16LE = BP.writeInt16LE
arr.writeInt16BE = BP.writeInt16BE
arr.writeInt32LE = BP.writeInt32LE
arr.writeInt32BE = BP.writeInt32BE
arr.writeFloatLE = BP.writeFloatLE
arr.writeFloatBE = BP.writeFloatBE
arr.writeDoubleLE = BP.writeDoubleLE
arr.writeDoubleBE = BP.writeDoubleBE
arr.fill = BP.fill
arr.inspect = BP.inspect
arr.toArrayBuffer = BP.toArrayBuffer
return arr
}
var INVALID_BASE64_RE = /[^+\/0-9A-z]/g
function base64clean (str) {
// Node strips out invalid characters like \n and \t from the string, base64-js does not
str = stringtrim(str).replace(INVALID_BASE64_RE, '')
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
while (str.length % 4 !== 0) {
str = str + '='
}
return str
}
function stringtrim (str) {
if (str.trim) return str.trim()
return str.replace(/^\s+|\s+$/g, '')
}
function isArray (subject) {
return (Array.isArray || function (subject) {
return Object.prototype.toString.call(subject) === '[object Array]'
})(subject)
}
function isArrayish (subject) {
return isArray(subject) || Buffer.isBuffer(subject) ||
subject && typeof subject === 'object' &&
typeof subject.length === 'number'
}
function toHex (n) {
if (n < 16) return '0' + n.toString(16)
return n.toString(16)
}
function utf8ToBytes (str) {
var byteArray = []
for (var i = 0; i < str.length; i++) {
var b = str.charCodeAt(i)
if (b <= 0x7F) {
byteArray.push(b)
} else {
var start = i
if (b >= 0xD800 && b <= 0xDFFF) i++
var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%')
for (var j = 0; j < h.length; j++) {
byteArray.push(parseInt(h[j], 16))
}
}
}
return byteArray
}
function asciiToBytes (str) {
var byteArray = []
for (var i = 0; i < str.length; i++) {
// Node's code seems to be doing this and not & 0x7F..
byteArray.push(str.charCodeAt(i) & 0xFF)
}
return byteArray
}
function utf16leToBytes (str) {
var c, hi, lo
var byteArray = []
for (var i = 0; i < str.length; i++) {
c = str.charCodeAt(i)
hi = c >> 8
lo = c % 256
byteArray.push(lo)
byteArray.push(hi)
}
return byteArray
}
function base64ToBytes (str) {
return base64.toByteArray(str)
}
function blitBuffer (src, dst, offset, length) {
for (var i = 0; i < length; i++) {
if ((i + offset >= dst.length) || (i >= src.length))
break
dst[i + offset] = src[i]
}
return i
}
function decodeUtf8Char (str) {
try {
return decodeURIComponent(str)
} catch (err) {
return String.fromCharCode(0xFFFD) // UTF 8 invalid char
}
}
/*
* We have to make sure that the value is a valid integer. This means that it
* is non-negative. It has no fractional component and that it does not
* exceed the maximum allowed value.
*/
function verifuint (value, max) {
assert(typeof value === 'number', 'cannot write a non-number as a number')
assert(value >= 0, 'specified a negative value for writing an unsigned value')
assert(value <= max, 'value is larger than maximum value for type')
assert(Math.floor(value) === value, 'value has a fractional component')
}
function verifsint (value, max, min) {
assert(typeof value === 'number', 'cannot write a non-number as a number')
assert(value <= max, 'value larger than maximum allowed value')
assert(value >= min, 'value smaller than minimum allowed value')
assert(Math.floor(value) === value, 'value has a fractional component')
}
function verifIEEE754 (value, max, min) {
assert(typeof value === 'number', 'cannot write a non-number as a number')
assert(value <= max, 'value larger than maximum allowed value')
assert(value >= min, 'value smaller than minimum allowed value')
}
function assert (test, message) {
if (!test) throw new Error(message || 'Failed assertion')
}
},{"base64-js":10,"ieee754":11}],10:[function(require,module,exports){
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
;(function (exports) {
'use strict';
var Arr = (typeof Uint8Array !== 'undefined')
? Uint8Array
: Array
var PLUS = '+'.charCodeAt(0)
var SLASH = '/'.charCodeAt(0)
var NUMBER = '0'.charCodeAt(0)
var LOWER = 'a'.charCodeAt(0)
var UPPER = 'A'.charCodeAt(0)
function decode (elt) {
var code = elt.charCodeAt(0)
if (code === PLUS)
return 62 // '+'
if (code === SLASH)
return 63 // '/'
if (code < NUMBER)
return -1 //no match
if (code < NUMBER + 10)
return code - NUMBER + 26 + 26
if (code < UPPER + 26)
return code - UPPER
if (code < LOWER + 26)
return code - LOWER + 26
}
function b64ToByteArray (b64) {
var i, j, l, tmp, placeHolders, arr
if (b64.length % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
// the number of equal signs (place holders)
// if there are two placeholders, than the two characters before it
// represent one byte
// if there is only one, then the three characters before it represent 2 bytes
// this is just a cheap hack to not do indexOf twice
var len = b64.length
placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
// base64 is 4/3 + up to two characters of the original data
arr = new Arr(b64.length * 3 / 4 - placeHolders)
// if there are placeholders, only get up to the last complete 4 chars
l = placeHolders > 0 ? b64.length - 4 : b64.length
var L = 0
function push (v) {
arr[L++] = v
}
for (i = 0, j = 0; i < l; i += 4, j += 3) {
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
push((tmp & 0xFF0000) >> 16)
push((tmp & 0xFF00) >> 8)
push(tmp & 0xFF)
}
if (placeHolders === 2) {
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
push(tmp & 0xFF)
} else if (placeHolders === 1) {
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
push((tmp >> 8) & 0xFF)
push(tmp & 0xFF)
}
return arr
}
function uint8ToBase64 (uint8) {
var i,
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
output = "",
temp, length
function encode (num) {
return lookup.charAt(num)
}
function tripletToBase64 (num) {
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
}
// go through the array every three bytes, we'll deal with trailing stuff later
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
output += tripletToBase64(temp)
}
// pad the end with zeros, but make sure to not forget the extra bytes
switch (extraBytes) {
case 1:
temp = uint8[uint8.length - 1]
output += encode(temp >> 2)
output += encode((temp << 4) & 0x3F)
output += '=='
break
case 2:
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
output += encode(temp >> 10)
output += encode((temp >> 4) & 0x3F)
output += encode((temp << 2) & 0x3F)
output += '='
break
}
return output
}
exports.toByteArray = b64ToByteArray
exports.fromByteArray = uint8ToBase64
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
},{}],11:[function(require,module,exports){
exports.read = function(buffer, offset, isLE, mLen, nBytes) {
var e, m,
eLen = nBytes * 8 - mLen - 1,
eMax = (1 << eLen) - 1,
eBias = eMax >> 1,
nBits = -7,
i = isLE ? (nBytes - 1) : 0,
d = isLE ? -1 : 1,
s = buffer[offset + i];
i += d;
e = s & ((1 << (-nBits)) - 1);
s >>= (-nBits);
nBits += eLen;
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
m = e & ((1 << (-nBits)) - 1);
e >>= (-nBits);
nBits += mLen;
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
if (e === 0) {
e = 1 - eBias;
} else if (e === eMax) {
return m ? NaN : ((s ? -1 : 1) * Infinity);
} else {
m = m + Math.pow(2, mLen);
e = e - eBias;
}
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
};
exports.write = function(buffer, value, offset, isLE, mLen, nBytes) {
var e, m, c,
eLen = nBytes * 8 - mLen - 1,
eMax = (1 << eLen) - 1,
eBias = eMax >> 1,
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
i = isLE ? 0 : (nBytes - 1),
d = isLE ? 1 : -1,
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
value = Math.abs(value);
if (isNaN(value) || value === Infinity) {
m = isNaN(value) ? 1 : 0;
e = eMax;
} else {
e = Math.floor(Math.log(value) / Math.LN2);
if (value * (c = Math.pow(2, -e)) < 1) {
e--;
c *= 2;
}
if (e + eBias >= 1) {
value += rt / c;
} else {
value += rt * Math.pow(2, 1 - eBias);
}
if (value * c >= 2) {
e++;
c /= 2;
}
if (e + eBias >= eMax) {
m = 0;
e = eMax;
} else if (e + eBias >= 1) {
m = (value * c - 1) * Math.pow(2, mLen);
e = e + eBias;
} else {
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
e = 0;
}
}
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
e = (e << mLen) | m;
eLen += mLen;
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
buffer[offset + i - d] |= s * 128;
};
},{}],12:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
throw TypeError('Uncaught, unspecified "error" event.');
}
return false;
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, args);
}
} else if (isObject(handler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.listenerCount = function(emitter, type) {
var ret;
if (!emitter._events || !emitter._events[type])
ret = 0;
else if (isFunction(emitter._events[type]))
ret = 1;
else
ret = emitter._events[type].length;
return ret;
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}],13:[function(require,module,exports){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
},{}],14:[function(require,module,exports){
module.exports = Array.isArray || function (arr) {
return Object.prototype.toString.call(arr) == '[object Array]';
};
},{}],15:[function(require,module,exports){
(function (process){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
function normalizeArray(parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for (var i = parts.length - 1; i >= 0; i--) {
var last = parts[i];
if (last === '.') {
parts.splice(i, 1);
} else if (last === '..') {
parts.splice(i, 1);
up++;
} else if (up) {
parts.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {
for (; up--; up) {
parts.unshift('..');
}
}
return parts;
}
// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe =
/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
var splitPath = function(filename) {
return splitPathRe.exec(filename).slice(1);
};
// path.resolve([from ...], to)
// posix version
exports.resolve = function() {
var resolvedPath = '',
resolvedAbsolute = false;
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path = (i >= 0) ? arguments[i] : process.cwd();
// Skip empty and invalid entries
if (typeof path !== 'string') {
throw new TypeError('Arguments to path.resolve must be strings');
} else if (!path) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path.charAt(0) === '/';
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
return !!p;
}), !resolvedAbsolute).join('/');
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
};
// path.normalize(path)
// posix version
exports.normalize = function(path) {
var isAbsolute = exports.isAbsolute(path),
trailingSlash = substr(path, -1) === '/';
// Normalize the path
path = normalizeArray(filter(path.split('/'), function(p) {
return !!p;
}), !isAbsolute).join('/');
if (!path && !isAbsolute) {
path = '.';
}
if (path && trailingSlash) {
path += '/';
}
return (isAbsolute ? '/' : '') + path;
};
// posix version
exports.isAbsolute = function(path) {
return path.charAt(0) === '/';
};
// posix version
exports.join = function() {
var paths = Array.prototype.slice.call(arguments, 0);
return exports.normalize(filter(paths, function(p, index) {
if (typeof p !== 'string') {
throw new TypeError('Arguments to path.join must be strings');
}
return p;
}).join('/'));
};
// path.relative(from, to)
// posix version
exports.relative = function(from, to) {
from = exports.resolve(from).substr(1);
to = exports.resolve(to).substr(1);
function trim(arr) {
var start = 0;
for (; start < arr.length; start++) {
if (arr[start] !== '') break;
}
var end = arr.length - 1;
for (; end >= 0; end--) {
if (arr[end] !== '') break;
}
if (start > end) return [];
return arr.slice(start, end - start + 1);
}
var fromParts = trim(from.split('/'));
var toParts = trim(to.split('/'));
var length = Math.min(fromParts.length, toParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {
if (fromParts[i] !== toParts[i]) {
samePartsLength = i;
break;
}
}
var outputParts = [];
for (var i = samePartsLength; i < fromParts.length; i++) {
outputParts.push('..');
}
outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('/');
};
exports.sep = '/';
exports.delimiter = ':';
exports.dirname = function(path) {
var result = splitPath(path),
root = result[0],
dir = result[1];
if (!root && !dir) {
// No dirname whatsoever
return '.';
}
if (dir) {
// It has a dirname, strip trailing slash
dir = dir.substr(0, dir.length - 1);
}
return root + dir;
};
exports.basename = function(path, ext) {
var f = splitPath(path)[2];
// TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
};
exports.extname = function(path) {
return splitPath(path)[3];
};
function filter (xs, f) {
if (xs.filter) return xs.filter(f);
var res = [];
for (var i = 0; i < xs.length; i++) {
if (f(xs[i], i, xs)) res.push(xs[i]);
}
return res;
}
// String.prototype.substr - negative index don't work in IE8
var substr = 'ab'.substr(-1) === 'b'
? function (str, start, len) { return str.substr(start, len) }
: function (str, start, len) {
if (start < 0) start = str.length + start;
return str.substr(start, len);
}
;
}).call(this,require('_process'))
},{"_process":16}],16:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
process.nextTick = (function () {
var canSetImmediate = typeof window !== 'undefined'
&& window.setImmediate;
var canPost = typeof window !== 'undefined'
&& window.postMessage && window.addEventListener
;
if (canSetImmediate) {
return function (f) { return window.setImmediate(f) };
}
if (canPost) {
var queue = [];
window.addEventListener('message', function (ev) {
var source = ev.source;
if ((source === window || source === null) && ev.data === 'process-tick') {
ev.stopPropagation();
if (queue.length > 0) {
var fn = queue.shift();
fn();
}
}
}, true);
return function nextTick(fn) {
queue.push(fn);
window.postMessage('process-tick', '*');
};
}
return function nextTick(fn) {
setTimeout(fn, 0);
};
})();
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.binding = function (name) {
throw new Error('process.binding is not supported');
}
// TODO(shtylman)
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
},{}],17:[function(require,module,exports){
module.exports = require("./lib/_stream_duplex.js")
},{"./lib/_stream_duplex.js":18}],18:[function(require,module,exports){
(function (process){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// a duplex stream is just a stream that is both readable and writable.
// Since JS doesn't have multiple prototypal inheritance, this class
// prototypally inherits from Readable, and then parasitically from
// Writable.
module.exports = Duplex;
/*<replacement>*/
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) keys.push(key);
return keys;
}
/*</replacement>*/
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
var Readable = require('./_stream_readable');
var Writable = require('./_stream_writable');
util.inherits(Duplex, Readable);
forEach(objectKeys(Writable.prototype), function(method) {
if (!Duplex.prototype[method])
Duplex.prototype[method] = Writable.prototype[method];
});
function Duplex(options) {
if (!(this instanceof Duplex))
return new Duplex(options);
Readable.call(this, options);
Writable.call(this, options);
if (options && options.readable === false)
this.readable = false;
if (options && options.writable === false)
this.writable = false;
this.allowHalfOpen = true;
if (options && options.allowHalfOpen === false)
this.allowHalfOpen = false;
this.once('end', onend);
}
// the no-half-open enforcer
function onend() {
// if we allow half-open state, or if the writable side ended,
// then we're ok.
if (this.allowHalfOpen || this._writableState.ended)
return;
// no more data can be written.
// But allow more writes to happen in this tick.
process.nextTick(this.end.bind(this));
}
function forEach (xs, f) {
for (var i = 0, l = xs.length; i < l; i++) {
f(xs[i], i);
}
}
}).call(this,require('_process'))
},{"./_stream_readable":20,"./_stream_writable":22,"_process":16,"core-util-is":23,"inherits":13}],19:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// a passthrough stream.
// basically just the most minimal sort of Transform stream.
// Every written chunk gets output as-is.
module.exports = PassThrough;
var Transform = require('./_stream_transform');
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
util.inherits(PassThrough, Transform);
function PassThrough(options) {
if (!(this instanceof PassThrough))
return new PassThrough(options);
Transform.call(this, options);
}
PassThrough.prototype._transform = function(chunk, encoding, cb) {
cb(null, chunk);
};
},{"./_stream_transform":21,"core-util-is":23,"inherits":13}],20:[function(require,module,exports){
(function (process){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
module.exports = Readable;
/*<replacement>*/
var isArray = require('isarray');
/*</replacement>*/
/*<replacement>*/
var Buffer = require('buffer').Buffer;
/*</replacement>*/
Readable.ReadableState = ReadableState;
var EE = require('events').EventEmitter;
/*<replacement>*/
if (!EE.listenerCount) EE.listenerCount = function(emitter, type) {
return emitter.listeners(type).length;
};
/*</replacement>*/
var Stream = require('stream');
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
var StringDecoder;
util.inherits(Readable, Stream);
function ReadableState(options, stream) {
options = options || {};
// the point at which it stops calling _read() to fill the buffer
// Note: 0 is a valid value, means "don't call _read preemptively ever"
var hwm = options.highWaterMark;
this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024;
// cast to ints.
this.highWaterMark = ~~this.highWaterMark;
this.buffer = [];
this.length = 0;
this.pipes = null;
this.pipesCount = 0;
this.flowing = false;
this.ended = false;
this.endEmitted = false;
this.reading = false;
// In streams that never have any data, and do push(null) right away,
// the consumer can miss the 'end' event if they do some I/O before
// consuming the stream. So, we don't emit('end') until some reading
// happens.
this.calledRead = false;
// a flag to be able to tell if the onwrite cb is called immediately,
// or on a later tick. We set this to true at first, becuase any
// actions that shouldn't happen until "later" should generally also
// not happen before the first write call.
this.sync = true;
// whenever we return null, then we set a flag to say
// that we're awaiting a 'readable' event emission.
this.needReadable = false;
this.emittedReadable = false;
this.readableListening = false;
// object stream flag. Used to make read(n) ignore n and to
// make all the buffer merging and length checks go away
this.objectMode = !!options.objectMode;
// Crypto is kind of old and crusty. Historically, its default string
// encoding is 'binary' so we have to make this configurable.
// Everything else in the universe uses 'utf8', though.
this.defaultEncoding = options.defaultEncoding || 'utf8';
// when piping, we only care about 'readable' events that happen
// after read()ing all the bytes and not getting any pushback.
this.ranOut = false;
// the number of writers that are awaiting a drain event in .pipe()s
this.awaitDrain = 0;
// if true, a maybeReadMore has been scheduled
this.readingMore = false;
this.decoder = null;
this.encoding = null;
if (options.encoding) {
if (!StringDecoder)
StringDecoder = require('string_decoder/').StringDecoder;
this.decoder = new StringDecoder(options.encoding);
this.encoding = options.encoding;
}
}
function Readable(options) {
if (!(this instanceof Readable))
return new Readable(options);
this._readableState = new ReadableState(options, this);
// legacy
this.readable = true;
Stream.call(this);
}
// Manually shove something into the read() buffer.
// This returns true if the highWaterMark has not been hit yet,
// similar to how Writable.write() returns true if you should
// write() some more.
Readable.prototype.push = function(chunk, encoding) {
var state = this._readableState;
if (typeof chunk === 'string' && !state.objectMode) {
encoding = encoding || state.defaultEncoding;
if (encoding !== state.encoding) {
chunk = new Buffer(chunk, encoding);
encoding = '';
}
}
return readableAddChunk(this, state, chunk, encoding, false);
};
// Unshift should *always* be something directly out of read()
Readable.prototype.unshift = function(chunk) {
var state = this._readableState;
return readableAddChunk(this, state, chunk, '', true);
};
function readableAddChunk(stream, state, chunk, encoding, addToFront) {
var er = chunkInvalid(state, chunk);
if (er) {
stream.emit('error', er);
} else if (chunk === null || chunk === undefined) {
state.reading = false;
if (!state.ended)
onEofChunk(stream, state);
} else if (state.objectMode || chunk && chunk.length > 0) {
if (state.ended && !addToFront) {
var e = new Error('stream.push() after EOF');
stream.emit('error', e);
} else if (state.endEmitted && addToFront) {
var e = new Error('stream.unshift() after end event');
stream.emit('error', e);
} else {
if (state.decoder && !addToFront && !encoding)
chunk = state.decoder.write(chunk);
// update the buffer info.
state.length += state.objectMode ? 1 : chunk.length;
if (addToFront) {
state.buffer.unshift(chunk);
} else {
state.reading = false;
state.buffer.push(chunk);
}
if (state.needReadable)
emitReadable(stream);
maybeReadMore(stream, state);
}
} else if (!addToFront) {
state.reading = false;
}
return needMoreData(state);
}
// if it's past the high water mark, we can push in some more.
// Also, if we have no data yet, we can stand some
// more bytes. This is to work around cases where hwm=0,
// such as the repl. Also, if the push() triggered a
// readable event, and the user called read(largeNumber) such that
// needReadable was set, then we ought to push more, so that another
// 'readable' event will be triggered.
function needMoreData(state) {
return !state.ended &&
(state.needReadable ||
state.length < state.highWaterMark ||
state.length === 0);
}
// backwards compatibility.
Readable.prototype.setEncoding = function(enc) {
if (!StringDecoder)
StringDecoder = require('string_decoder/').StringDecoder;
this._readableState.decoder = new StringDecoder(enc);
this._readableState.encoding = enc;
};
// Don't raise the hwm > 128MB
var MAX_HWM = 0x800000;
function roundUpToNextPowerOf2(n) {
if (n >= MAX_HWM) {
n = MAX_HWM;
} else {
// Get the next highest power of 2
n--;
for (var p = 1; p < 32; p <<= 1) n |= n >> p;
n++;
}
return n;
}
function howMuchToRead(n, state) {
if (state.length === 0 && state.ended)
return 0;
if (state.objectMode)
return n === 0 ? 0 : 1;
if (isNaN(n) || n === null) {
// only flow one buffer at a time
if (state.flowing && state.buffer.length)
return state.buffer[0].length;
else
return state.length;
}
if (n <= 0)
return 0;
// If we're asking for more than the target buffer level,
// then raise the water mark. Bump up to the next highest
// power of 2, to prevent increasing it excessively in tiny
// amounts.
if (n > state.highWaterMark)
state.highWaterMark = roundUpToNextPowerOf2(n);
// don't have that much. return null, unless we've ended.
if (n > state.length) {
if (!state.ended) {
state.needReadable = true;
return 0;
} else
return state.length;
}
return n;
}
// you can override either this method, or the async _read(n) below.
Readable.prototype.read = function(n) {
var state = this._readableState;
state.calledRead = true;
var nOrig = n;
if (typeof n !== 'number' || n > 0)
state.emittedReadable = false;
// if we're doing read(0) to trigger a readable event, but we
// already have a bunch of data in the buffer, then just trigger
// the 'readable' event and move on.
if (n === 0 &&
state.needReadable &&
(state.length >= state.highWaterMark || state.ended)) {
emitReadable(this);
return null;
}
n = howMuchToRead(n, state);
// if we've ended, and we're now clear, then finish it up.
if (n === 0 && state.ended) {
if (state.length === 0)
endReadable(this);
return null;
}
// All the actual chunk generation logic needs to be
// *below* the call to _read. The reason is that in certain
// synthetic stream cases, such as passthrough streams, _read
// may be a completely synchronous operation which may change
// the state of the read buffer, providing enough data when
// before there was *not* enough.
//
// So, the steps are:
// 1. Figure out what the state of things will be after we do
// a read from the buffer.
//
// 2. If that resulting state will trigger a _read, then call _read.
// Note that this may be asynchronous, or synchronous. Yes, it is
// deeply ugly to write APIs this way, but that still doesn't mean
// that the Readable class should behave improperly, as streams are
// designed to be sync/async agnostic.
// Take note if the _read call is sync or async (ie, if the read call
// has returned yet), so that we know whether or not it's safe to emit
// 'readable' etc.
//
// 3. Actually pull the requested chunks out of the buffer and return.
// if we need a readable event, then we need to do some reading.
var doRead = state.needReadable;
// if we currently have less than the highWaterMark, then also read some
if (state.length - n <= state.highWaterMark)
doRead = true;
// however, if we've ended, then there's no point, and if we're already
// reading, then it's unnecessary.
if (state.ended || state.reading)
doRead = false;
if (doRead) {
state.reading = true;
state.sync = true;
// if the length is currently zero, then we *need* a readable event.
if (state.length === 0)
state.needReadable = true;
// call internal read method
this._read(state.highWaterMark);
state.sync = false;
}
// If _read called its callback synchronously, then `reading`
// will be false, and we need to re-evaluate how much data we
// can return to the user.
if (doRead && !state.reading)
n = howMuchToRead(nOrig, state);
var ret;
if (n > 0)
ret = fromList(n, state);
else
ret = null;
if (ret === null) {
state.needReadable = true;
n = 0;
}
state.length -= n;
// If we have nothing in the buffer, then we want to know
// as soon as we *do* get something into the buffer.
if (state.length === 0 && !state.ended)
state.needReadable = true;
// If we happened to read() exactly the remaining amount in the
// buffer, and the EOF has been seen at this point, then make sure
// that we emit 'end' on the very next tick.
if (state.ended && !state.endEmitted && state.length === 0)
endReadable(this);
return ret;
};
function chunkInvalid(state, chunk) {
var er = null;
if (!Buffer.isBuffer(chunk) &&
'string' !== typeof chunk &&
chunk !== null &&
chunk !== undefined &&
!state.objectMode &&
!er) {
er = new TypeError('Invalid non-string/buffer chunk');
}
return er;
}
function onEofChunk(stream, state) {
if (state.decoder && !state.ended) {
var chunk = state.decoder.end();
if (chunk && chunk.length) {
state.buffer.push(chunk);
state.length += state.objectMode ? 1 : chunk.length;
}
}
state.ended = true;
// if we've ended and we have some data left, then emit
// 'readable' now to make sure it gets picked up.
if (state.length > 0)
emitReadable(stream);
else
endReadable(stream);
}
// Don't emit readable right away in sync mode, because this can trigger
// another read() call => stack overflow. This way, it might trigger
// a nextTick recursion warning, but that's not so bad.
function emitReadable(stream) {
var state = stream._readableState;
state.needReadable = false;
if (state.emittedReadable)
return;
state.emittedReadable = true;
if (state.sync)
process.nextTick(function() {
emitReadable_(stream);
});
else
emitReadable_(stream);
}
function emitReadable_(stream) {
stream.emit('readable');
}
// at this point, the user has presumably seen the 'readable' event,
// and called read() to consume some data. that may have triggered
// in turn another _read(n) call, in which case reading = true if
// it's in progress.
// However, if we're not ended, or reading, and the length < hwm,
// then go ahead and try to read some more preemptively.
function maybeReadMore(stream, state) {
if (!state.readingMore) {
state.readingMore = true;
process.nextTick(function() {
maybeReadMore_(stream, state);
});
}
}
function maybeReadMore_(stream, state) {
var len = state.length;
while (!state.reading && !state.flowing && !state.ended &&
state.length < state.highWaterMark) {
stream.read(0);
if (len === state.length)
// didn't get any data, stop spinning.
break;
else
len = state.length;
}
state.readingMore = false;
}
// abstract method. to be overridden in specific implementation classes.
// call cb(er, data) where data is <= n in length.
// for virtual (non-string, non-buffer) streams, "length" is somewhat
// arbitrary, and perhaps not very meaningful.
Readable.prototype._read = function(n) {
this.emit('error', new Error('not implemented'));
};
Readable.prototype.pipe = function(dest, pipeOpts) {
var src = this;
var state = this._readableState;
switch (state.pipesCount) {
case 0:
state.pipes = dest;
break;
case 1:
state.pipes = [state.pipes, dest];
break;
default:
state.pipes.push(dest);
break;
}
state.pipesCount += 1;
var doEnd = (!pipeOpts || pipeOpts.end !== false) &&
dest !== process.stdout &&
dest !== process.stderr;
var endFn = doEnd ? onend : cleanup;
if (state.endEmitted)
process.nextTick(endFn);
else
src.once('end', endFn);
dest.on('unpipe', onunpipe);
function onunpipe(readable) {
if (readable !== src) return;
cleanup();
}
function onend() {
dest.end();
}
// when the dest drains, it reduces the awaitDrain counter
// on the source. This would be more elegant with a .once()
// handler in flow(), but adding and removing repeatedly is
// too slow.
var ondrain = pipeOnDrain(src);
dest.on('drain', ondrain);
function cleanup() {
// cleanup event handlers once the pipe is broken
dest.removeListener('close', onclose);
dest.removeListener('finish', onfinish);
dest.removeListener('drain', ondrain);
dest.removeListener('error', onerror);
dest.removeListener('unpipe', onunpipe);
src.removeListener('end', onend);
src.removeListener('end', cleanup);
// if the reader is waiting for a drain event from this
// specific writer, then it would cause it to never start
// flowing again.
// So, if this is awaiting a drain, then we just call it now.
// If we don't know, then assume that we are waiting for one.
if (!dest._writableState || dest._writableState.needDrain)
ondrain();
}
// if the dest has an error, then stop piping into it.
// however, don't suppress the throwing behavior for this.
function onerror(er) {
unpipe();
dest.removeListener('error', onerror);
if (EE.listenerCount(dest, 'error') === 0)
dest.emit('error', er);
}
// This is a brutally ugly hack to make sure that our error handler
// is attached before any userland ones. NEVER DO THIS.
if (!dest._events || !dest._events.error)
dest.on('error', onerror);
else if (isArray(dest._events.error))
dest._events.error.unshift(onerror);
else
dest._events.error = [onerror, dest._events.error];
// Both close and finish should trigger unpipe, but only once.
function onclose() {
dest.removeListener('finish', onfinish);
unpipe();
}
dest.once('close', onclose);
function onfinish() {
dest.removeListener('close', onclose);
unpipe();
}
dest.once('finish', onfinish);
function unpipe() {
src.unpipe(dest);
}
// tell the dest that it's being piped to
dest.emit('pipe', src);
// start the flow if it hasn't been started already.
if (!state.flowing) {
// the handler that waits for readable events after all
// the data gets sucked out in flow.
// This would be easier to follow with a .once() handler
// in flow(), but that is too slow.
this.on('readable', pipeOnReadable);
state.flowing = true;
process.nextTick(function() {
flow(src);
});
}
return dest;
};
function pipeOnDrain(src) {
return function() {
var dest = this;
var state = src._readableState;
state.awaitDrain--;
if (state.awaitDrain === 0)
flow(src);
};
}
function flow(src) {
var state = src._readableState;
var chunk;
state.awaitDrain = 0;
function write(dest, i, list) {
var written = dest.write(chunk);
if (false === written) {
state.awaitDrain++;
}
}
while (state.pipesCount && null !== (chunk = src.read())) {
if (state.pipesCount === 1)
write(state.pipes, 0, null);
else
forEach(state.pipes, write);
src.emit('data', chunk);
// if anyone needs a drain, then we have to wait for that.
if (state.awaitDrain > 0)
return;
}
// if every destination was unpiped, either before entering this
// function, or in the while loop, then stop flowing.
//
// NB: This is a pretty rare edge case.
if (state.pipesCount === 0) {
state.flowing = false;
// if there were data event listeners added, then switch to old mode.
if (EE.listenerCount(src, 'data') > 0)
emitDataEvents(src);
return;
}
// at this point, no one needed a drain, so we just ran out of data
// on the next readable event, start it over again.
state.ranOut = true;
}
function pipeOnReadable() {
if (this._readableState.ranOut) {
this._readableState.ranOut = false;
flow(this);
}
}
Readable.prototype.unpipe = function(dest) {
var state = this._readableState;
// if we're not piping anywhere, then do nothing.
if (state.pipesCount === 0)
return this;
// just one destination. most common case.
if (state.pipesCount === 1) {
// passed in one, but it's not the right one.
if (dest && dest !== state.pipes)
return this;
if (!dest)
dest = state.pipes;
// got a match.
state.pipes = null;
state.pipesCount = 0;
this.removeListener('readable', pipeOnReadable);
state.flowing = false;
if (dest)
dest.emit('unpipe', this);
return this;
}
// slow case. multiple pipe destinations.
if (!dest) {
// remove all.
var dests = state.pipes;
var len = state.pipesCount;
state.pipes = null;
state.pipesCount = 0;
this.removeListener('readable', pipeOnReadable);
state.flowing = false;
for (var i = 0; i < len; i++)
dests[i].emit('unpipe', this);
return this;
}
// try to find the right one.
var i = indexOf(state.pipes, dest);
if (i === -1)
return this;
state.pipes.splice(i, 1);
state.pipesCount -= 1;
if (state.pipesCount === 1)
state.pipes = state.pipes[0];
dest.emit('unpipe', this);
return this;
};
// set up data events if they are asked for
// Ensure readable listeners eventually get something
Readable.prototype.on = function(ev, fn) {
var res = Stream.prototype.on.call(this, ev, fn);
if (ev === 'data' && !this._readableState.flowing)
emitDataEvents(this);
if (ev === 'readable' && this.readable) {
var state = this._readableState;
if (!state.readableListening) {
state.readableListening = true;
state.emittedReadable = false;
state.needReadable = true;
if (!state.reading) {
this.read(0);
} else if (state.length) {
emitReadable(this, state);
}
}
}
return res;
};
Readable.prototype.addListener = Readable.prototype.on;
// pause() and resume() are remnants of the legacy readable stream API
// If the user uses them, then switch into old mode.
Readable.prototype.resume = function() {
emitDataEvents(this);
this.read(0);
this.emit('resume');
};
Readable.prototype.pause = function() {
emitDataEvents(this, true);
this.emit('pause');
};
function emitDataEvents(stream, startPaused) {
var state = stream._readableState;
if (state.flowing) {
// https://github.com/isaacs/readable-stream/issues/16
throw new Error('Cannot switch to old mode now.');
}
var paused = startPaused || false;
var readable = false;
// convert to an old-style stream.
stream.readable = true;
stream.pipe = Stream.prototype.pipe;
stream.on = stream.addListener = Stream.prototype.on;
stream.on('readable', function() {
readable = true;
var c;
while (!paused && (null !== (c = stream.read())))
stream.emit('data', c);
if (c === null) {
readable = false;
stream._readableState.needReadable = true;
}
});
stream.pause = function() {
paused = true;
this.emit('pause');
};
stream.resume = function() {
paused = false;
if (readable)
process.nextTick(function() {
stream.emit('readable');
});
else
this.read(0);
this.emit('resume');
};
// now make it start, just in case it hadn't already.
stream.emit('readable');
}
// wrap an old-style stream as the async data source.
// This is *not* part of the readable stream interface.
// It is an ugly unfortunate mess of history.
Readable.prototype.wrap = function(stream) {
var state = this._readableState;
var paused = false;
var self = this;
stream.on('end', function() {
if (state.decoder && !state.ended) {
var chunk = state.decoder.end();
if (chunk && chunk.length)
self.push(chunk);
}
self.push(null);
});
stream.on('data', function(chunk) {
if (state.decoder)
chunk = state.decoder.write(chunk);
if (!chunk || !state.objectMode && !chunk.length)
return;
var ret = self.push(chunk);
if (!ret) {
paused = true;
stream.pause();
}
});
// proxy all the other methods.
// important when wrapping filters and duplexes.
for (var i in stream) {
if (typeof stream[i] === 'function' &&
typeof this[i] === 'undefined') {
this[i] = function(method) { return function() {
return stream[method].apply(stream, arguments);
}}(i);
}
}
// proxy certain important events.
var events = ['error', 'close', 'destroy', 'pause', 'resume'];
forEach(events, function(ev) {
stream.on(ev, self.emit.bind(self, ev));
});
// when we try to consume some more bytes, simply unpause the
// underlying stream.
self._read = function(n) {
if (paused) {
paused = false;
stream.resume();
}
};
return self;
};
// exposed for testing purposes only.
Readable._fromList = fromList;
// Pluck off n bytes from an array of buffers.
// Length is the combined lengths of all the buffers in the list.
function fromList(n, state) {
var list = state.buffer;
var length = state.length;
var stringMode = !!state.decoder;
var objectMode = !!state.objectMode;
var ret;
// nothing in the list, definitely empty.
if (list.length === 0)
return null;
if (length === 0)
ret = null;
else if (objectMode)
ret = list.shift();
else if (!n || n >= length) {
// read it all, truncate the array.
if (stringMode)
ret = list.join('');
else
ret = Buffer.concat(list, length);
list.length = 0;
} else {
// read just some of it.
if (n < list[0].length) {
// just take a part of the first list item.
// slice is the same for buffers and strings.
var buf = list[0];
ret = buf.slice(0, n);
list[0] = buf.slice(n);
} else if (n === list[0].length) {
// first list is a perfect match
ret = list.shift();
} else {
// complex case.
// we have enough to cover it, but it spans past the first buffer.
if (stringMode)
ret = '';
else
ret = new Buffer(n);
var c = 0;
for (var i = 0, l = list.length; i < l && c < n; i++) {
var buf = list[0];
var cpy = Math.min(n - c, buf.length);
if (stringMode)
ret += buf.slice(0, cpy);
else
buf.copy(ret, c, 0, cpy);
if (cpy < buf.length)
list[0] = buf.slice(cpy);
else
list.shift();
c += cpy;
}
}
}
return ret;
}
function endReadable(stream) {
var state = stream._readableState;
// If we get here before consuming all the bytes, then that is a
// bug in node. Should never happen.
if (state.length > 0)
throw new Error('endReadable called on non-empty stream');
if (!state.endEmitted && state.calledRead) {
state.ended = true;
process.nextTick(function() {
// Check that we didn't get one last unshift.
if (!state.endEmitted && state.length === 0) {
state.endEmitted = true;
stream.readable = false;
stream.emit('end');
}
});
}
}
function forEach (xs, f) {
for (var i = 0, l = xs.length; i < l; i++) {
f(xs[i], i);
}
}
function indexOf (xs, x) {
for (var i = 0, l = xs.length; i < l; i++) {
if (xs[i] === x) return i;
}
return -1;
}
}).call(this,require('_process'))
},{"_process":16,"buffer":9,"core-util-is":23,"events":12,"inherits":13,"isarray":14,"stream":29,"string_decoder/":24}],21:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// a transform stream is a readable/writable stream where you do
// something with the data. Sometimes it's called a "filter",
// but that's not a great name for it, since that implies a thing where
// some bits pass through, and others are simply ignored. (That would
// be a valid example of a transform, of course.)
//
// While the output is causally related to the input, it's not a
// necessarily symmetric or synchronous transformation. For example,
// a zlib stream might take multiple plain-text writes(), and then
// emit a single compressed chunk some time in the future.
//
// Here's how this works:
//
// The Transform stream has all the aspects of the readable and writable
// stream classes. When you write(chunk), that calls _write(chunk,cb)
// internally, and returns false if there's a lot of pending writes
// buffered up. When you call read(), that calls _read(n) until
// there's enough pending readable data buffered up.
//
// In a transform stream, the written data is placed in a buffer. When
// _read(n) is called, it transforms the queued up data, calling the
// buffered _write cb's as it consumes chunks. If consuming a single
// written chunk would result in multiple output chunks, then the first
// outputted bit calls the readcb, and subsequent chunks just go into
// the read buffer, and will cause it to emit 'readable' if necessary.
//
// This way, back-pressure is actually determined by the reading side,
// since _read has to be called to start processing a new chunk. However,
// a pathological inflate type of transform can cause excessive buffering
// here. For example, imagine a stream where every byte of input is
// interpreted as an integer from 0-255, and then results in that many
// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in
// 1kb of data being output. In this case, you could write a very small
// amount of input, and end up with a very large amount of output. In
// such a pathological inflating mechanism, there'd be no way to tell
// the system to stop doing the transform. A single 4MB write could
// cause the system to run out of memory.
//
// However, even in such a pathological case, only a single written chunk
// would be consumed, and then the rest would wait (un-transformed) until
// the results of the previous transformed chunk were consumed.
module.exports = Transform;
var Duplex = require('./_stream_duplex');
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
util.inherits(Transform, Duplex);
function TransformState(options, stream) {
this.afterTransform = function(er, data) {
return afterTransform(stream, er, data);
};
this.needTransform = false;
this.transforming = false;
this.writecb = null;
this.writechunk = null;
}
function afterTransform(stream, er, data) {
var ts = stream._transformState;
ts.transforming = false;
var cb = ts.writecb;
if (!cb)
return stream.emit('error', new Error('no writecb in Transform class'));
ts.writechunk = null;
ts.writecb = null;
if (data !== null && data !== undefined)
stream.push(data);
if (cb)
cb(er);
var rs = stream._readableState;
rs.reading = false;
if (rs.needReadable || rs.length < rs.highWaterMark) {
stream._read(rs.highWaterMark);
}
}
function Transform(options) {
if (!(this instanceof Transform))
return new Transform(options);
Duplex.call(this, options);
var ts = this._transformState = new TransformState(options, this);
// when the writable side finishes, then flush out anything remaining.
var stream = this;
// start out asking for a readable event once data is transformed.
this._readableState.needReadable = true;
// we have implemented the _read method, and done the other things
// that Readable wants before the first _read call, so unset the
// sync guard flag.
this._readableState.sync = false;
this.once('finish', function() {
if ('function' === typeof this._flush)
this._flush(function(er) {
done(stream, er);
});
else
done(stream);
});
}
Transform.prototype.push = function(chunk, encoding) {
this._transformState.needTransform = false;
return Duplex.prototype.push.call(this, chunk, encoding);
};
// This is the part where you do stuff!
// override this function in implementation classes.
// 'chunk' is an input chunk.
//
// Call `push(newChunk)` to pass along transformed output
// to the readable side. You may call 'push' zero or more times.
//
// Call `cb(err)` when you are done with this chunk. If you pass
// an error, then that'll put the hurt on the whole operation. If you
// never call cb(), then you'll never get another chunk.
Transform.prototype._transform = function(chunk, encoding, cb) {
throw new Error('not implemented');
};
Transform.prototype._write = function(chunk, encoding, cb) {
var ts = this._transformState;
ts.writecb = cb;
ts.writechunk = chunk;
ts.writeencoding = encoding;
if (!ts.transforming) {
var rs = this._readableState;
if (ts.needTransform ||
rs.needReadable ||
rs.length < rs.highWaterMark)
this._read(rs.highWaterMark);
}
};
// Doesn't matter what the args are here.
// _transform does all the work.
// That we got here means that the readable side wants more data.
Transform.prototype._read = function(n) {
var ts = this._transformState;
if (ts.writechunk !== null && ts.writecb && !ts.transforming) {
ts.transforming = true;
this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
} else {
// mark that we need a transform, so that any data that comes in
// will get processed, now that we've asked for it.
ts.needTransform = true;
}
};
function done(stream, er) {
if (er)
return stream.emit('error', er);
// if there's nothing in the write buffer, then that means
// that nothing more will ever be provided
var ws = stream._writableState;
var rs = stream._readableState;
var ts = stream._transformState;
if (ws.length)
throw new Error('calling transform done when ws.length != 0');
if (ts.transforming)
throw new Error('calling transform done when still transforming');
return stream.push(null);
}
},{"./_stream_duplex":18,"core-util-is":23,"inherits":13}],22:[function(require,module,exports){
(function (process){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// A bit simpler than readable streams.
// Implement an async ._write(chunk, cb), and it'll handle all
// the drain event emission and buffering.
module.exports = Writable;
/*<replacement>*/
var Buffer = require('buffer').Buffer;
/*</replacement>*/
Writable.WritableState = WritableState;
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
var Stream = require('stream');
util.inherits(Writable, Stream);
function WriteReq(chunk, encoding, cb) {
this.chunk = chunk;
this.encoding = encoding;
this.callback = cb;
}
function WritableState(options, stream) {
options = options || {};
// the point at which write() starts returning false
// Note: 0 is a valid value, means that we always return false if
// the entire buffer is not flushed immediately on write()
var hwm = options.highWaterMark;
this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024;
// object stream flag to indicate whether or not this stream
// contains buffers or objects.
this.objectMode = !!options.objectMode;
// cast to ints.
this.highWaterMark = ~~this.highWaterMark;
this.needDrain = false;
// at the start of calling end()
this.ending = false;
// when end() has been called, and returned
this.ended = false;
// when 'finish' is emitted
this.finished = false;
// should we decode strings into buffers before passing to _write?
// this is here so that some node-core streams can optimize string
// handling at a lower level.
var noDecode = options.decodeStrings === false;
this.decodeStrings = !noDecode;
// Crypto is kind of old and crusty. Historically, its default string
// encoding is 'binary' so we have to make this configurable.
// Everything else in the universe uses 'utf8', though.
this.defaultEncoding = options.defaultEncoding || 'utf8';
// not an actual buffer we keep track of, but a measurement
// of how much we're waiting to get pushed to some underlying
// socket or file.
this.length = 0;
// a flag to see when we're in the middle of a write.
this.writing = false;
// a flag to be able to tell if the onwrite cb is called immediately,
// or on a later tick. We set this to true at first, becuase any
// actions that shouldn't happen until "later" should generally also
// not happen before the first write call.
this.sync = true;
// a flag to know if we're processing previously buffered items, which
// may call the _write() callback in the same tick, so that we don't
// end up in an overlapped onwrite situation.
this.bufferProcessing = false;
// the callback that's passed to _write(chunk,cb)
this.onwrite = function(er) {
onwrite(stream, er);
};
// the callback that the user supplies to write(chunk,encoding,cb)
this.writecb = null;
// the amount that is being written when _write is called.
this.writelen = 0;
this.buffer = [];
// True if the error was already emitted and should not be thrown again
this.errorEmitted = false;
}
function Writable(options) {
var Duplex = require('./_stream_duplex');
// Writable ctor is applied to Duplexes, though they're not
// instanceof Writable, they're instanceof Readable.
if (!(this instanceof Writable) && !(this instanceof Duplex))
return new Writable(options);
this._writableState = new WritableState(options, this);
// legacy.
this.writable = true;
Stream.call(this);
}
// Otherwise people can pipe Writable streams, which is just wrong.
Writable.prototype.pipe = function() {
this.emit('error', new Error('Cannot pipe. Not readable.'));
};
function writeAfterEnd(stream, state, cb) {
var er = new Error('write after end');
// TODO: defer error events consistently everywhere, not just the cb
stream.emit('error', er);
process.nextTick(function() {
cb(er);
});
}
// If we get something that is not a buffer, string, null, or undefined,
// and we're not in objectMode, then that's an error.
// Otherwise stream chunks are all considered to be of length=1, and the
// watermarks determine how many objects to keep in the buffer, rather than
// how many bytes or characters.
function validChunk(stream, state, chunk, cb) {
var valid = true;
if (!Buffer.isBuffer(chunk) &&
'string' !== typeof chunk &&
chunk !== null &&
chunk !== undefined &&
!state.objectMode) {
var er = new TypeError('Invalid non-string/buffer chunk');
stream.emit('error', er);
process.nextTick(function() {
cb(er);
});
valid = false;
}
return valid;
}
Writable.prototype.write = function(chunk, encoding, cb) {
var state = this._writableState;
var ret = false;
if (typeof encoding === 'function') {
cb = encoding;
encoding = null;
}
if (Buffer.isBuffer(chunk))
encoding = 'buffer';
else if (!encoding)
encoding = state.defaultEncoding;
if (typeof cb !== 'function')
cb = function() {};
if (state.ended)
writeAfterEnd(this, state, cb);
else if (validChunk(this, state, chunk, cb))
ret = writeOrBuffer(this, state, chunk, encoding, cb);
return ret;
};
function decodeChunk(state, chunk, encoding) {
if (!state.objectMode &&
state.decodeStrings !== false &&
typeof chunk === 'string') {
chunk = new Buffer(chunk, encoding);
}
return chunk;
}
// if we're already writing something, then just put this
// in the queue, and wait our turn. Otherwise, call _write
// If we return false, then we need a drain event, so set that flag.
function writeOrBuffer(stream, state, chunk, encoding, cb) {
chunk = decodeChunk(state, chunk, encoding);
if (Buffer.isBuffer(chunk))
encoding = 'buffer';
var len = state.objectMode ? 1 : chunk.length;
state.length += len;
var ret = state.length < state.highWaterMark;
// we must ensure that previous needDrain will not be reset to false.
if (!ret)
state.needDrain = true;
if (state.writing)
state.buffer.push(new WriteReq(chunk, encoding, cb));
else
doWrite(stream, state, len, chunk, encoding, cb);
return ret;
}
function doWrite(stream, state, len, chunk, encoding, cb) {
state.writelen = len;
state.writecb = cb;
state.writing = true;
state.sync = true;
stream._write(chunk, encoding, state.onwrite);
state.sync = false;
}
function onwriteError(stream, state, sync, er, cb) {
if (sync)
process.nextTick(function() {
cb(er);
});
else
cb(er);
stream._writableState.errorEmitted = true;
stream.emit('error', er);
}
function onwriteStateUpdate(state) {
state.writing = false;
state.writecb = null;
state.length -= state.writelen;
state.writelen = 0;
}
function onwrite(stream, er) {
var state = stream._writableState;
var sync = state.sync;
var cb = state.writecb;
onwriteStateUpdate(state);
if (er)
onwriteError(stream, state, sync, er, cb);
else {
// Check if we're actually ready to finish, but don't emit yet
var finished = needFinish(stream, state);
if (!finished && !state.bufferProcessing && state.buffer.length)
clearBuffer(stream, state);
if (sync) {
process.nextTick(function() {
afterWrite(stream, state, finished, cb);
});
} else {
afterWrite(stream, state, finished, cb);
}
}
}
function afterWrite(stream, state, finished, cb) {
if (!finished)
onwriteDrain(stream, state);
cb();
if (finished)
finishMaybe(stream, state);
}
// Must force callback to be called on nextTick, so that we don't
// emit 'drain' before the write() consumer gets the 'false' return
// value, and has a chance to attach a 'drain' listener.
function onwriteDrain(stream, state) {
if (state.length === 0 && state.needDrain) {
state.needDrain = false;
stream.emit('drain');
}
}
// if there's something in the buffer waiting, then process it
function clearBuffer(stream, state) {
state.bufferProcessing = true;
for (var c = 0; c < state.buffer.length; c++) {
var entry = state.buffer[c];
var chunk = entry.chunk;
var encoding = entry.encoding;
var cb = entry.callback;
var len = state.objectMode ? 1 : chunk.length;
doWrite(stream, state, len, chunk, encoding, cb);
// if we didn't call the onwrite immediately, then
// it means that we need to wait until it does.
// also, that means that the chunk and cb are currently
// being processed, so move the buffer counter past them.
if (state.writing) {
c++;
break;
}
}
state.bufferProcessing = false;
if (c < state.buffer.length)
state.buffer = state.buffer.slice(c);
else
state.buffer.length = 0;
}
Writable.prototype._write = function(chunk, encoding, cb) {
cb(new Error('not implemented'));
};
Writable.prototype.end = function(chunk, encoding, cb) {
var state = this._writableState;
if (typeof chunk === 'function') {
cb = chunk;
chunk = null;
encoding = null;
} else if (typeof encoding === 'function') {
cb = encoding;
encoding = null;
}
if (typeof chunk !== 'undefined' && chunk !== null)
this.write(chunk, encoding);
// ignore unnecessary end() calls.
if (!state.ending && !state.finished)
endWritable(this, state, cb);
};
function needFinish(stream, state) {
return (state.ending &&
state.length === 0 &&
!state.finished &&
!state.writing);
}
function finishMaybe(stream, state) {
var need = needFinish(stream, state);
if (need) {
state.finished = true;
stream.emit('finish');
}
return need;
}
function endWritable(stream, state, cb) {
state.ending = true;
finishMaybe(stream, state);
if (cb) {
if (state.finished)
process.nextTick(cb);
else
stream.once('finish', cb);
}
state.ended = true;
}
}).call(this,require('_process'))
},{"./_stream_duplex":18,"_process":16,"buffer":9,"core-util-is":23,"inherits":13,"stream":29}],23:[function(require,module,exports){
(function (Buffer){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
function isBuffer(arg) {
return Buffer.isBuffer(arg);
}
exports.isBuffer = isBuffer;
function objectToString(o) {
return Object.prototype.toString.call(o);
}
}).call(this,require("buffer").Buffer)
},{"buffer":9}],24:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var Buffer = require('buffer').Buffer;
var isBufferEncoding = Buffer.isEncoding
|| function(encoding) {
switch (encoding && encoding.toLowerCase()) {
case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true;
default: return false;
}
}
function assertEncoding(encoding) {
if (encoding && !isBufferEncoding(encoding)) {
throw new Error('Unknown encoding: ' + encoding);
}
}
var StringDecoder = exports.StringDecoder = function(encoding) {
this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
assertEncoding(encoding);
switch (this.encoding) {
case 'utf8':
// CESU-8 represents each of Surrogate Pair by 3-bytes
this.surrogateSize = 3;
break;
case 'ucs2':
case 'utf16le':
// UTF-16 represents each of Surrogate Pair by 2-bytes
this.surrogateSize = 2;
this.detectIncompleteChar = utf16DetectIncompleteChar;
break;
case 'base64':
// Base-64 stores 3 bytes in 4 chars, and pads the remainder.
this.surrogateSize = 3;
this.detectIncompleteChar = base64DetectIncompleteChar;
break;
default:
this.write = passThroughWrite;
return;
}
this.charBuffer = new Buffer(6);
this.charReceived = 0;
this.charLength = 0;
};
StringDecoder.prototype.write = function(buffer) {
var charStr = '';
var offset = 0;
// if our last write ended with an incomplete multibyte character
while (this.charLength) {
// determine how many remaining bytes this buffer has to offer for this char
var i = (buffer.length >= this.charLength - this.charReceived) ?
this.charLength - this.charReceived :
buffer.length;
// add the new bytes to the char buffer
buffer.copy(this.charBuffer, this.charReceived, offset, i);
this.charReceived += (i - offset);
offset = i;
if (this.charReceived < this.charLength) {
// still not enough chars in this buffer? wait for more ...
return '';
}
// get the character that was split
charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
// lead surrogate (D800-DBFF) is also the incomplete character
var charCode = charStr.charCodeAt(charStr.length - 1);
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
this.charLength += this.surrogateSize;
charStr = '';
continue;
}
this.charReceived = this.charLength = 0;
// if there are no more bytes in this buffer, just emit our char
if (i == buffer.length) return charStr;
// otherwise cut off the characters end from the beginning of this buffer
buffer = buffer.slice(i, buffer.length);
break;
}
var lenIncomplete = this.detectIncompleteChar(buffer);
var end = buffer.length;
if (this.charLength) {
// buffer the incomplete character bytes we got
buffer.copy(this.charBuffer, 0, buffer.length - lenIncomplete, end);
this.charReceived = lenIncomplete;
end -= lenIncomplete;
}
charStr += buffer.toString(this.encoding, 0, end);
var end = charStr.length - 1;
var charCode = charStr.charCodeAt(end);
// lead surrogate (D800-DBFF) is also the incomplete character
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
var size = this.surrogateSize;
this.charLength += size;
this.charReceived += size;
this.charBuffer.copy(this.charBuffer, size, 0, size);
this.charBuffer.write(charStr.charAt(charStr.length - 1), this.encoding);
return charStr.substring(0, end);
}
// or just emit the charStr
return charStr;
};
StringDecoder.prototype.detectIncompleteChar = function(buffer) {
// determine how many bytes we have to check at the end of this buffer
var i = (buffer.length >= 3) ? 3 : buffer.length;
// Figure out if one of the last i bytes of our buffer announces an
// incomplete char.
for (; i > 0; i--) {
var c = buffer[buffer.length - i];
// See http://en.wikipedia.org/wiki/UTF-8#Description
// 110XXXXX
if (i == 1 && c >> 5 == 0x06) {
this.charLength = 2;
break;
}
// 1110XXXX
if (i <= 2 && c >> 4 == 0x0E) {
this.charLength = 3;
break;
}
// 11110XXX
if (i <= 3 && c >> 3 == 0x1E) {
this.charLength = 4;
break;
}
}
return i;
};
StringDecoder.prototype.end = function(buffer) {
var res = '';
if (buffer && buffer.length)
res = this.write(buffer);
if (this.charReceived) {
var cr = this.charReceived;
var buf = this.charBuffer;
var enc = this.encoding;
res += buf.slice(0, cr).toString(enc);
}
return res;
};
function passThroughWrite(buffer) {
return buffer.toString(this.encoding);
}
function utf16DetectIncompleteChar(buffer) {
var incomplete = this.charReceived = buffer.length % 2;
this.charLength = incomplete ? 2 : 0;
return incomplete;
}
function base64DetectIncompleteChar(buffer) {
var incomplete = this.charReceived = buffer.length % 3;
this.charLength = incomplete ? 3 : 0;
return incomplete;
}
},{"buffer":9}],25:[function(require,module,exports){
module.exports = require("./lib/_stream_passthrough.js")
},{"./lib/_stream_passthrough.js":19}],26:[function(require,module,exports){
exports = module.exports = require('./lib/_stream_readable.js');
exports.Readable = exports;
exports.Writable = require('./lib/_stream_writable.js');
exports.Duplex = require('./lib/_stream_duplex.js');
exports.Transform = require('./lib/_stream_transform.js');
exports.PassThrough = require('./lib/_stream_passthrough.js');
},{"./lib/_stream_duplex.js":18,"./lib/_stream_passthrough.js":19,"./lib/_stream_readable.js":20,"./lib/_stream_transform.js":21,"./lib/_stream_writable.js":22}],27:[function(require,module,exports){
module.exports = require("./lib/_stream_transform.js")
},{"./lib/_stream_transform.js":21}],28:[function(require,module,exports){
module.exports = require("./lib/_stream_writable.js")
},{"./lib/_stream_writable.js":22}],29:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
module.exports = Stream;
var EE = require('events').EventEmitter;
var inherits = require('inherits');
inherits(Stream, EE);
Stream.Readable = require('readable-stream/readable.js');
Stream.Writable = require('readable-stream/writable.js');
Stream.Duplex = require('readable-stream/duplex.js');
Stream.Transform = require('readable-stream/transform.js');
Stream.PassThrough = require('readable-stream/passthrough.js');
// Backwards-compat with node 0.4.x
Stream.Stream = Stream;
// old-style streams. Note that the pipe method (the only relevant
// part of this class) is overridden in the Readable class.
function Stream() {
EE.call(this);
}
Stream.prototype.pipe = function(dest, options) {
var source = this;
function ondata(chunk) {
if (dest.writable) {
if (false === dest.write(chunk) && source.pause) {
source.pause();
}
}
}
source.on('data', ondata);
function ondrain() {
if (source.readable && source.resume) {
source.resume();
}
}
dest.on('drain', ondrain);
// If the 'end' option is not supplied, dest.end() will be called when
// source gets the 'end' or 'close' events. Only dest.end() once.
if (!dest._isStdio && (!options || options.end !== false)) {
source.on('end', onend);
source.on('close', onclose);
}
var didOnEnd = false;
function onend() {
if (didOnEnd) return;
didOnEnd = true;
dest.end();
}
function onclose() {
if (didOnEnd) return;
didOnEnd = true;
if (typeof dest.destroy === 'function') dest.destroy();
}
// don't leave dangling pipes when there are errors.
function onerror(er) {
cleanup();
if (EE.listenerCount(this, 'error') === 0) {
throw er; // Unhandled stream error in pipe.
}
}
source.on('error', onerror);
dest.on('error', onerror);
// remove all the event listeners that were added.
function cleanup() {
source.removeListener('data', ondata);
dest.removeListener('drain', ondrain);
source.removeListener('end', onend);
source.removeListener('close', onclose);
source.removeListener('error', onerror);
dest.removeListener('error', onerror);
source.removeListener('end', cleanup);
source.removeListener('close', cleanup);
dest.removeListener('close', cleanup);
}
source.on('end', cleanup);
source.on('close', cleanup);
dest.on('close', cleanup);
dest.emit('pipe', source);
// Allow for unix-like usage: A.pipe(B).pipe(C)
return dest;
};
},{"events":12,"inherits":13,"readable-stream/duplex.js":17,"readable-stream/passthrough.js":25,"readable-stream/readable.js":26,"readable-stream/transform.js":27,"readable-stream/writable.js":28}],30:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var Buffer = require('buffer').Buffer;
function assertEncoding(encoding) {
if (encoding && !Buffer.isEncoding(encoding)) {
throw new Error('Unknown encoding: ' + encoding);
}
}
var StringDecoder = exports.StringDecoder = function(encoding) {
this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
assertEncoding(encoding);
switch (this.encoding) {
case 'utf8':
// CESU-8 represents each of Surrogate Pair by 3-bytes
this.surrogateSize = 3;
break;
case 'ucs2':
case 'utf16le':
// UTF-16 represents each of Surrogate Pair by 2-bytes
this.surrogateSize = 2;
this.detectIncompleteChar = utf16DetectIncompleteChar;
break;
case 'base64':
// Base-64 stores 3 bytes in 4 chars, and pads the remainder.
this.surrogateSize = 3;
this.detectIncompleteChar = base64DetectIncompleteChar;
break;
default:
this.write = passThroughWrite;
return;
}
this.charBuffer = new Buffer(6);
this.charReceived = 0;
this.charLength = 0;
};
StringDecoder.prototype.write = function(buffer) {
var charStr = '';
var offset = 0;
// if our last write ended with an incomplete multibyte character
while (this.charLength) {
// determine how many remaining bytes this buffer has to offer for this char
var i = (buffer.length >= this.charLength - this.charReceived) ?
this.charLength - this.charReceived :
buffer.length;
// add the new bytes to the char buffer
buffer.copy(this.charBuffer, this.charReceived, offset, i);
this.charReceived += (i - offset);
offset = i;
if (this.charReceived < this.charLength) {
// still not enough chars in this buffer? wait for more ...
return '';
}
// get the character that was split
charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
// lead surrogate (D800-DBFF) is also the incomplete character
var charCode = charStr.charCodeAt(charStr.length - 1);
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
this.charLength += this.surrogateSize;
charStr = '';
continue;
}
this.charReceived = this.charLength = 0;
// if there are no more bytes in this buffer, just emit our char
if (i == buffer.length) return charStr;
// otherwise cut off the characters end from the beginning of this buffer
buffer = buffer.slice(i, buffer.length);
break;
}
var lenIncomplete = this.detectIncompleteChar(buffer);
var end = buffer.length;
if (this.charLength) {
// buffer the incomplete character bytes we got
buffer.copy(this.charBuffer, 0, buffer.length - lenIncomplete, end);
this.charReceived = lenIncomplete;
end -= lenIncomplete;
}
charStr += buffer.toString(this.encoding, 0, end);
var end = charStr.length - 1;
var charCode = charStr.charCodeAt(end);
// lead surrogate (D800-DBFF) is also the incomplete character
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
var size = this.surrogateSize;
this.charLength += size;
this.charReceived += size;
this.charBuffer.copy(this.charBuffer, size, 0, size);
this.charBuffer.write(charStr.charAt(charStr.length - 1), this.encoding);
return charStr.substring(0, end);
}
// or just emit the charStr
return charStr;
};
StringDecoder.prototype.detectIncompleteChar = function(buffer) {
// determine how many bytes we have to check at the end of this buffer
var i = (buffer.length >= 3) ? 3 : buffer.length;
// Figure out if one of the last i bytes of our buffer announces an
// incomplete char.
for (; i > 0; i--) {
var c = buffer[buffer.length - i];
// See http://en.wikipedia.org/wiki/UTF-8#Description
// 110XXXXX
if (i == 1 && c >> 5 == 0x06) {
this.charLength = 2;
break;
}
// 1110XXXX
if (i <= 2 && c >> 4 == 0x0E) {
this.charLength = 3;
break;
}
// 11110XXX
if (i <= 3 && c >> 3 == 0x1E) {
this.charLength = 4;
break;
}
}
return i;
};
StringDecoder.prototype.end = function(buffer) {
var res = '';
if (buffer && buffer.length)
res = this.write(buffer);
if (this.charReceived) {
var cr = this.charReceived;
var buf = this.charBuffer;
var enc = this.encoding;
res += buf.slice(0, cr).toString(enc);
}
return res;
};
function passThroughWrite(buffer) {
return buffer.toString(this.encoding);
}
function utf16DetectIncompleteChar(buffer) {
var incomplete = this.charReceived = buffer.length % 2;
this.charLength = incomplete ? 2 : 0;
return incomplete;
}
function base64DetectIncompleteChar(buffer) {
var incomplete = this.charReceived = buffer.length % 3;
this.charLength = incomplete ? 3 : 0;
return incomplete;
}
},{"buffer":9}],31:[function(require,module,exports){
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
},{}],32:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = require('./support/isBuffer');
function objectToString(o) {
return Object.prototype.toString.call(o);
}
function pad(n) {
return n < 10 ? '0' + n.toString(10) : n.toString(10);
}
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'];
// 26 Feb 16:19:34
function timestamp() {
var d = new Date();
var time = [pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds())].join(':');
return [d.getDate(), months[d.getMonth()], time].join(' ');
}
// log is just a thin wrapper to console.log that prepends a timestamp
exports.log = function() {
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
};
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
exports.inherits = require('inherits');
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
if (!add || !isObject(add)) return origin;
var keys = Object.keys(add);
var i = keys.length;
while (i--) {
origin[keys[i]] = add[keys[i]];
}
return origin;
};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./support/isBuffer":31,"_process":16,"inherits":13}]},{},[2])(2)
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment