<commit_before>import {
    stopInfo,
    lineInfo,
    linesForStop,
    stopsForLine,
    stopVisits,
    placesForName,
    closestStops,
    areaStops
} from './ruter-fetcher';

import {
    GraphQLEnumType,
    GraphQLInterfaceType,
    GraphQLInputObjectType,
    GraphQLObjectType,
    GraphQLList,
    GraphQLNonNull,
    GraphQLSchema,
    GraphQLString,
    GraphQLInt,
    GraphQLFloat,
    GraphQLBoolean,
} from 'graphql';

import {
    assoc,
    groupBy,
    head,
    map as mapObj,
    map,
    pick,
    prop,
    toPairs,
    values,
    zip
} from 'ramda';

import {fromLatLon} from 'utm';

const GeoLocationInput = new GraphQLInputObjectType({
  name: 'GeoLocationInput',
  fields: {
    lat: { type: new GraphQLNonNull(GraphQLFloat) },
    lng: { type: new GraphQLNonNull(GraphQLFloat) },
  }
});

const UtmLocationInput = new GraphQLInputObjectType({
  name: 'UtmLocationInput',
  fields: {
    x: { type: new GraphQLNonNull(GraphQLFloat) },
    y: { type: new GraphQLNonNull(GraphQLFloat) },
  }
});

const HybridLocationInput = new GraphQLInputObjectType({
  name: 'HybridLocationInput',
  description: "Either UTM, with .x and .y, or .lat and .lon. Exists because UnionTypes are not InputObjectTypes yet",
  fields: {
    lat: { type: GraphQLFloat },
    lng: { type: GraphQLFloat },
    x: { type: GraphQLFloat },
    y: { type: GraphQLFloat }
  }
});

const TransitType = new GraphQLEnumType({
    name: 'TransitType',
    description: 'One of the types of transit operated by ruter',
    values: {
        TRAM: {
            value: 7,
            description: 'Tram'
        },
        BUS: {
            value: 2,
            description: 'Bus'
        },
        SUBWAY: {
            value: 8,
            description: 'Subway'
        },
        FERRY: {
            value: 1,
            description: 'Ferry'
        }
    }
});

const PlaceType = new GraphQLEnumType({
    name: 'PlaceType',
    description: 'A kind of place',
    values: {
        AREA: {
            value: "Area",
            description: "An area"
        },
        STOP: {
            value: "Stop",
            description: "A public transportation stop"
        },
        STREET: {
            value: "Street",
            description: "A street"
        },
        POI: {
            value: "POI",
            description: "Point of interest"
        }
    }
});

const PlaceInterface = new GraphQLInterfaceType({
    name: 'PlaceInterface',
    description: 'A place of some kind',
    fields: {
       id: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'Unique ID for a place'
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Name of place'
        },
        district: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'District place belongs to'
        },
        placeType: {
            type: new GraphQLNonNull(PlaceType),
            description: 'Type of place'
        }
    }
});

const GeoLocation = new GraphQLObjectType({
    name: 'GeoLocation',
    description: 'geo type',
    fields: {
        latitude: {
            type: GraphQLFloat,
            description: 'latitude'
        },
        longitude: {
            type: GraphQLFloat,
            description: 'longitude'
        }
    }
});

const Line = new GraphQLObjectType({
    name: 'Line',
    description: 'A public transit line',
    fields: () => ({
        id: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'The id of the line.',
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'The name of the line.',
        },
        transitType: {
            type: new GraphQLNonNull(TransitType),
            description: 'The type or transport of the line.',
        },
        color: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'The color of the line.',
        },
        stops: {
            type: new GraphQLList(new GraphQLNonNull(Stop)),
            description: 'Stops serviced by this line',
            resolve: ({id}, args, source) => stopsForLine(id)
        },
        endPoints: {
            type: GraphQLString,
            description: 'End points for line',
            resolve: ({id}) => stopsForLine(id).then(e => {
                return e[0].name + ' / ' + e[e.length - 1].name;
            })

        }
    }),
    interfaces: [ ]
});

const Deviation = new GraphQLObjectType({
    name: 'Deviation',
    description: 'Notice about a deviation from regular service',
    fields: {
        id: {
            type: new GraphQLNonNull(GraphQLInt),
        },
        header: {
            type: new GraphQLNonNull(GraphQLString),
            description: "Short summary of deviation"
        }
    }
});

const Stop = new GraphQLObjectType({
    name: 'Stop',
    description: 'A stop',
    interfaces: [ PlaceInterface ],
    isTypeOf: e => e.placeType == "Stop", // fixme, use enum somehow
    fields: () => ({

        // fields for PlaceInterface
        id: {
            type: new GraphQLNonNull(GraphQLInt),
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
        },
        placeType: {
            type: new GraphQLNonNull(PlaceType),
        },
        district: {
            type: new GraphQLNonNull(GraphQLString),
        },

        // Other fields
        shortName: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'desc'
        },
        zone: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'desc'
        },
        isHub: {
            type: new GraphQLNonNull(GraphQLBoolean),
            description: 'desc'
        },
        utmX: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'desc'
        },
        utmY: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'desc'
        },
        geoLocation: {
            type: GeoLocation,
            description: 'geo point'
        },
        lines: {
            type: new GraphQLList(Line),
            description: 'lines serviced by from stop by type',
            args: {
                transitType: {
                    name: 'transitType',
                    type: new GraphQLList(TransitType)
                },
                id: {
                    name: 'id',
                    type: new GraphQLList(GraphQLInt),
                }
            },
            resolve: ({id: stopId}, {transitType, id: lineId}) => {
                let p = linesForStop(stopId);

                if (transitType) {
                    p = p.then(e => e.filter(y => transitType.indexOf(y.transitType) != -1));
                }

                if (lineId) {
                    p = p.then(e => {
                        return e.filter(y => lineId.indexOf(y.id) != -1 );
                    })
                }

                return p;

            }
        },
        departures: {
            type: new GraphQLList(StopVisit),
            description: 'Pending visits for stop. This is the reealtime info',
            resolve: function({id}) {
                return stopVisits(id);
            }
        },

        realtime: {
            type: Realtime,
            resolve: ({id}) => stopVisits(id)
        }
    })
});

const RealtimeDestination = new GraphQLObjectType({
    name: 'RealtimeDestination',
    description: 'A line, as reprsented by the realtime system',
    fields: () => ({
        // also pointer to actual line?
        // also pointer to actual stop?
        // also, deviations ?
        // also, fix RealtimeVisit to be same as other visit stuff
        name: {
            type: new GraphQLNonNull(GraphQLString)
        },
        lineId: {
            type: new GraphQLNonNull(GraphQLInt)
        },
        stopId: {
            type: new GraphQLNonNull(GraphQLInt)
        },
        destinationName: {
            type: new GraphQLNonNull(GraphQLString)
        },
        visits: {
            type: new GraphQLList(RealtimeVisit)
        }
    })
});

function visitsToDestinations(visits) {
    const grouper = e => `${e.lineId}:${e.destinationName}`;
    const lineVisits = values(groupBy(grouper, visits));
    const lineInfo = lineVisits
                        .map(head)
                        .map(pick(['stopId', 'lineId', 'name', 'destinationName']));
    return zip(lineInfo, lineVisits).map(([i, v]) => assoc('visits', v, i));
}

const RealtimePlatform = new GraphQLObjectType({
    name: 'RealtimePlatform',
    description: 'A platform connected to a stop, valid for realtime departure info only, thus volatile based on time of day etc.',
    fields: () => ({
        name: {
            type: GraphQLString
        },
        visits: {
            type: new GraphQLList(RealtimeVisit)
        },
        destinations: {
            type: new GraphQLList(RealtimeDestination),
            resolve: ({visits}) => visitsToDestinations(visits)
        }
    })
});

function platformsFromVisits(visits) {
    visits = visits.filter(prop('platform'));
    const platformVisits = groupBy(prop('platform'), visits);
    return toPairs(platformVisits)
            .map(([name, visits]) => ({name, visits}));
}

const Realtime = new GraphQLObjectType({
    name: 'Realtime',
    description: 'Bag of holding for realtime info attached to a stop',
    fields: () => ({
        visits: {
            type: new GraphQLList(RealtimeVisit),
            resolve: (visits) => visits
        },
        platforms: {
            type: new GraphQLList(RealtimePlatform),
            resolve: (visits) => platformsFromVisits(visits)
        },
        destinations: {
            type: new GraphQLList(RealtimeDestination),
            resolve: (visits) => visitsToDestinations(visits)
        }
    })
});

const RealtimeVisit = new GraphQLObjectType({
    name: 'RealtimeVisit',
    description: 'Realtime visit, that is realtime data for a transport visiting a stop',
    fields: () => ({
        expectedArrival: {
            type: new GraphQLNonNull(GraphQLString),
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
        },
        destinationName: {
            type: new GraphQLNonNull(GraphQLString),
        }
    })

});

const StopVisit = new GraphQLObjectType({
    name: 'StopVisit',
    description: 'Stop visit',
    fields: () => ({
        expectedArrival: {
            type: new GraphQLNonNull(GraphQLString),
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
        },
        destinationName: {
            type: new GraphQLNonNull(GraphQLString),
        },
        stop: {
            type: new GraphQLNonNull(Stop),
            resolve: ({stopId}) => stopInfo(stopId)
        },
        line: {
            type: new GraphQLNonNull(Line),
            resolve: ({lineId}) => lineInfo(lineId)
        },
        destinationName: {
            type: new GraphQLNonNull(GraphQLString)
        },
        direction: {
            type: GraphQLString
        },
        platform: {
            type: GraphQLString
        },
        deviations: {
            type: new GraphQLList(Deviation)
        }
    })
});

const Place = new GraphQLObjectType({
    name: 'Place',
    description: 'A place of some kind',
    interfaces: [ PlaceInterface ],
    isTypeOf: e => e.placeType != "Stop", // fixme, use enum somehow

    fields: () => ({
        id: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'Unique ID for a place'
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Name of place'
        },
        district: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'District place belongs to'
        },
        placeType: {
            type: new GraphQLNonNull(PlaceType),
            description: 'Type of place'
        }
    })
});

function ensureUtmInHybridPosition(pos) {
    if (pos.x && pos.y) {
        return pos
    }
    else if (pos.lat && pos.lng) {
        const {easting, northing} = fromLatLon(pos.lat, pos.lng)
        pos.x = parseInt(easting);
        pos.y = parseInt(northing);
        return pos
    }
    else {
        throw new Error("bad invariant. Need either x and y or lat and lng on a HybridPosition")
    }
}

export const schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: 'Query',
        fields: {
            version: {
                type: GraphQLString,
                resolve: function() {
                    return '1.0';
                }
            },
            utcTime: {
                type: GraphQLString,
                resolve: function() {
                    return new Date().toString();
                }
            },
            stop: {
                type: Stop,
                args: {
                    id: { name: 'id', type: new GraphQLNonNull(GraphQLInt) }
                },
                resolve: (root, {id}, source) => stopInfo(id)
            },
            line: {
                type: Line,
                args: {
                    id: { name: 'id', type: new GraphQLNonNull(GraphQLInt) }
                },
                resolve: (root, {id}, source) => lineInfo(id)
            },
            places: {
                type: new GraphQLList(PlaceInterface),
                args: {
                    name: {
                        name: 'name',
                        type: new GraphQLNonNull(GraphQLString)
                    },
                    type: {
                        name: 'type',
                        type: new GraphQLList(PlaceType)
                    }
                    // add counties and type
                },
                resolve: (root, {name, type}) => {
                    let p = placesForName(name);
                    if (type) {
                        p = p.then(e => e.filter(y => type.indexOf(y.placeType) != -1));
                    }
                    return p;
                }
            },

            pointStops: {
                type: new GraphQLList(Stop),
                args: {
                    location: {
                        name: "location",
                        type: new GraphQLNonNull(HybridLocationInput)
                    },
                    maxDistance: {
                        names: "maxDistance",
                        type: GraphQLInt
                    }
                    // proposals as well?
                },
                resolve: (root, {location}) => {
                    ensureUtmInHybridPosition(location);
                    return closestStops(location.x, location.y)
                }
            },

            areaStops: {
                type: new GraphQLList(Stop),
                args: {
                    sw: {
                        name: "sw",
                        type: new GraphQLNonNull(HybridLocationInput)
                    },
                    ne: {
                        name: "ne",
                        type: new GraphQLNonNull(HybridLocationInput)
                    },
                },
                resolve: (root, {sw, ne}) => {
                    ensureUtmInHybridPosition(sw);
                    ensureUtmInHybridPosition(ne);
                    return areaStops(sw, ne)
                }
            }
        }
    })
});
<commit_msg>Cleaned up realtime stuff<commit_after>import {
    stopInfo,
    lineInfo,
    linesForStop,
    stopsForLine,
    stopVisits,
    placesForName,
    closestStops,
    areaStops
} from './ruter-fetcher';

import {
    GraphQLEnumType,
    GraphQLInterfaceType,
    GraphQLInputObjectType,
    GraphQLObjectType,
    GraphQLList,
    GraphQLNonNull,
    GraphQLSchema,
    GraphQLString,
    GraphQLInt,
    GraphQLFloat,
    GraphQLBoolean,
} from 'graphql';

import {
    assoc,
    groupBy,
    head,
    map as mapObj,
    map,
    pick,
    prop,
    toPairs,
    values,
    zip
} from 'ramda';

import {fromLatLon} from 'utm';

const GeoLocationInput = new GraphQLInputObjectType({
  name: 'GeoLocationInput',
  fields: {
    lat: { type: new GraphQLNonNull(GraphQLFloat) },
    lng: { type: new GraphQLNonNull(GraphQLFloat) },
  }
});

const UtmLocationInput = new GraphQLInputObjectType({
  name: 'UtmLocationInput',
  fields: {
    x: { type: new GraphQLNonNull(GraphQLFloat) },
    y: { type: new GraphQLNonNull(GraphQLFloat) },
  }
});

const HybridLocationInput = new GraphQLInputObjectType({
  name: 'HybridLocationInput',
  description: "Either UTM, with .x and .y, or .lat and .lon. Exists because UnionTypes are not InputObjectTypes yet",
  fields: {
    lat: { type: GraphQLFloat },
    lng: { type: GraphQLFloat },
    x: { type: GraphQLFloat },
    y: { type: GraphQLFloat }
  }
});

const TransitType = new GraphQLEnumType({
    name: 'TransitType',
    description: 'One of the types of transit operated by ruter',
    values: {
        TRAM: {
            value: 7,
            description: 'Tram'
        },
        BUS: {
            value: 2,
            description: 'Bus'
        },
        SUBWAY: {
            value: 8,
            description: 'Subway'
        },
        FERRY: {
            value: 1,
            description: 'Ferry'
        }
    }
});

const PlaceType = new GraphQLEnumType({
    name: 'PlaceType',
    description: 'A kind of place',
    values: {
        AREA: {
            value: "Area",
            description: "An area"
        },
        STOP: {
            value: "Stop",
            description: "A public transportation stop"
        },
        STREET: {
            value: "Street",
            description: "A street"
        },
        POI: {
            value: "POI",
            description: "Point of interest"
        }
    }
});

const PlaceInterface = new GraphQLInterfaceType({
    name: 'PlaceInterface',
    description: 'A place of some kind',
    fields: {
       id: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'Unique ID for a place'
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Name of place'
        },
        district: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'District place belongs to'
        },
        placeType: {
            type: new GraphQLNonNull(PlaceType),
            description: 'Type of place'
        }
    }
});

const GeoLocation = new GraphQLObjectType({
    name: 'GeoLocation',
    description: 'geo type',
    fields: {
        latitude: {
            type: GraphQLFloat,
            description: 'latitude'
        },
        longitude: {
            type: GraphQLFloat,
            description: 'longitude'
        }
    }
});

const Line = new GraphQLObjectType({
    name: 'Line',
    description: 'A public transit line',
    fields: () => ({
        id: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'The id of the line.',
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'The name of the line.',
        },
        transitType: {
            type: new GraphQLNonNull(TransitType),
            description: 'The type or transport of the line.',
        },
        color: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'The color of the line.',
        },
        stops: {
            type: new GraphQLList(new GraphQLNonNull(Stop)),
            description: 'Stops serviced by this line',
            resolve: ({id}, args, source) => stopsForLine(id)
        },
        endPoints: {
            type: GraphQLString,
            description: 'End points for line',
            resolve: ({id}) => stopsForLine(id).then(e => {
                return e[0].name + ' / ' + e[e.length - 1].name;
            })

        }
    }),
    interfaces: [ ]
});

const Deviation = new GraphQLObjectType({
    name: 'Deviation',
    description: 'Notice about a deviation from regular service',
    fields: {
        id: {
            type: new GraphQLNonNull(GraphQLInt),
        },
        header: {
            type: new GraphQLNonNull(GraphQLString),
            description: "Short summary of deviation"
        }
    }
});

const Stop = new GraphQLObjectType({
    name: 'Stop',
    description: 'A stop',
    interfaces: [ PlaceInterface ],
    isTypeOf: e => e.placeType == "Stop", // fixme, use enum somehow
    fields: () => ({

        // fields for PlaceInterface
        id: {
            type: new GraphQLNonNull(GraphQLInt),
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
        },
        placeType: {
            type: new GraphQLNonNull(PlaceType),
        },
        district: {
            type: new GraphQLNonNull(GraphQLString),
        },

        // Other fields
        shortName: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'desc'
        },
        zone: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'desc'
        },
        isHub: {
            type: new GraphQLNonNull(GraphQLBoolean),
            description: 'desc'
        },
        utmX: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'desc'
        },
        utmY: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'desc'
        },
        geoLocation: {
            type: GeoLocation,
            description: 'geo point'
        },
        lines: {
            type: new GraphQLList(Line),
            description: 'lines serviced by from stop by type',
            args: {
                transitType: {
                    name: 'transitType',
                    type: new GraphQLList(TransitType)
                },
                id: {
                    name: 'id',
                    type: new GraphQLList(GraphQLInt),
                }
            },
            resolve: ({id: stopId}, {transitType, id: lineId}) => {
                let p = linesForStop(stopId);

                if (transitType) {
                    p = p.then(e => e.filter(y => transitType.indexOf(y.transitType) != -1));
                }

                if (lineId) {
                    p = p.then(e => {
                        return e.filter(y => lineId.indexOf(y.id) != -1 );
                    })
                }

                return p;

            }
        },

        realtime: {
            type: Realtime,
            resolve: ({id}) => stopVisits(id)
        }
    })
});

const RealtimeDestination = new GraphQLObjectType({
    name: 'RealtimeDestination',
    description: 'A line, as reprsented by the realtime system',
    fields: () => ({
        // also pointer to actual line?
        // also pointer to actual stop?
        // also, deviations ?
        // also, fix RealtimeVisit to be same as other visit stuff
        name: {
            type: new GraphQLNonNull(GraphQLString)
        },
        lineId: {
            type: new GraphQLNonNull(GraphQLInt)
        },
        stopId: {
            type: new GraphQLNonNull(GraphQLInt)
        },
        destinationName: {
            type: new GraphQLNonNull(GraphQLString)
        },
        visits: {
            type: new GraphQLList(RealtimeVisit)
        }
    })
});

function visitsToDestinations(visits) {
    const grouper = e => `${e.lineId}:${e.destinationName}`;
    const lineVisits = values(groupBy(grouper, visits));
    const lineInfo = lineVisits
                        .map(head)
                        .map(pick(['stopId', 'lineId', 'name', 'destinationName']));
    return zip(lineInfo, lineVisits).map(([i, v]) => assoc('visits', v, i));
}

const RealtimePlatform = new GraphQLObjectType({
    name: 'RealtimePlatform',
    description: 'A platform connected to a stop, valid for realtime departure info only, thus volatile based on time of day etc.',
    fields: () => ({
        name: {
            type: GraphQLString
        },
        visits: {
            type: new GraphQLList(RealtimeVisit)
        },
        destinations: {
            type: new GraphQLList(RealtimeDestination),
            resolve: ({visits}) => visitsToDestinations(visits)
        }
    })
});

function platformsFromVisits(visits) {
    visits = visits.filter(prop('platform'));
    const platformVisits = groupBy(prop('platform'), visits);
    return toPairs(platformVisits)
            .map(([name, visits]) => ({name, visits}));
}

const Realtime = new GraphQLObjectType({
    name: 'Realtime',
    description: 'Bag of holding for realtime info attached to a stop',
    fields: () => ({
        visits: {
            type: new GraphQLList(RealtimeVisit),
            resolve: (visits) => visits
        },
        platforms: {
            type: new GraphQLList(RealtimePlatform),
            resolve: (visits) => platformsFromVisits(visits)
        },
        destinations: {
            type: new GraphQLList(RealtimeDestination),
            resolve: (visits) => visitsToDestinations(visits)
        }
    })
});

const RealtimeVisit = new GraphQLObjectType({
    name: 'RealtimeVisit',
    description: 'Realtime visit, that is realtime data for a transport visiting a stop',
    fields: () => ({
        expectedArrival: {
            type: new GraphQLNonNull(GraphQLString),
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
        },
        destinationName: {
            type: new GraphQLNonNull(GraphQLString),
        },
        direction: {
            type: GraphQLString
        },
        platform: {
            type: GraphQLString
        },
        deviations: {
            type: new GraphQLList(Deviation)
        },
        stop: {
            type: new GraphQLNonNull(Stop),
            resolve: ({stopId}) => stopInfo(stopId)
        },
        line: {
            type: new GraphQLNonNull(Line),
            resolve: ({lineId}) => lineInfo(lineId)
        }
    })

});

const Place = new GraphQLObjectType({
    name: 'Place',
    description: 'A place of some kind',
    interfaces: [ PlaceInterface ],
    isTypeOf: e => e.placeType != "Stop", // fixme, use enum somehow

    fields: () => ({
        id: {
            type: new GraphQLNonNull(GraphQLInt),
            description: 'Unique ID for a place'
        },
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Name of place'
        },
        district: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'District place belongs to'
        },
        placeType: {
            type: new GraphQLNonNull(PlaceType),
            description: 'Type of place'
        }
    })
});

function ensureUtmInHybridPosition(pos) {
    if (pos.x && pos.y) {
        return pos
    }
    else if (pos.lat && pos.lng) {
        const {easting, northing} = fromLatLon(pos.lat, pos.lng)
        pos.x = parseInt(easting);
        pos.y = parseInt(northing);
        return pos
    }
    else {
        throw new Error("bad invariant. Need either x and y or lat and lng on a HybridPosition")
    }
}

export const schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: 'Query',
        fields: {
            version: {
                type: GraphQLString,
                resolve: function() {
                    return '1.0';
                }
            },
            utcTime: {
                type: GraphQLString,
                resolve: function() {
                    return new Date().toString();
                }
            },
            stop: {
                type: Stop,
                args: {
                    id: { name: 'id', type: new GraphQLNonNull(GraphQLInt) }
                },
                resolve: (root, {id}, source) => stopInfo(id)
            },
            line: {
                type: Line,
                args: {
                    id: { name: 'id', type: new GraphQLNonNull(GraphQLInt) }
                },
                resolve: (root, {id}, source) => lineInfo(id)
            },
            places: {
                type: new GraphQLList(PlaceInterface),
                args: {
                    name: {
                        name: 'name',
                        type: new GraphQLNonNull(GraphQLString)
                    },
                    type: {
                        name: 'type',
                        type: new GraphQLList(PlaceType)
                    }
                    // add counties and type
                },
                resolve: (root, {name, type}) => {
                    let p = placesForName(name);
                    if (type) {
                        p = p.then(e => e.filter(y => type.indexOf(y.placeType) != -1));
                    }
                    return p;
                }
            },

            pointStops: {
                type: new GraphQLList(Stop),
                args: {
                    location: {
                        name: "location",
                        type: new GraphQLNonNull(HybridLocationInput)
                    },
                    maxDistance: {
                        names: "maxDistance",
                        type: GraphQLInt
                    }
                    // proposals as well?
                },
                resolve: (root, {location}) => {
                    ensureUtmInHybridPosition(location);
                    return closestStops(location.x, location.y)
                }
            },

            areaStops: {
                type: new GraphQLList(Stop),
                args: {
                    sw: {
                        name: "sw",
                        type: new GraphQLNonNull(HybridLocationInput)
                    },
                    ne: {
                        name: "ne",
                        type: new GraphQLNonNull(HybridLocationInput)
                    },
                },
                resolve: (root, {sw, ne}) => {
                    ensureUtmInHybridPosition(sw);
                    ensureUtmInHybridPosition(ne);
                    return areaStops(sw, ne)
                }
            }
        }
    })
});
<|endoftext|>


<commit_before>
var CellsTest = TestCase("CellsTest");

CellsTest.prototype.setUp = function () {
  this.clockDestructor = Clock.hijack();
}

CellsTest.prototype.tearDown = function () {
  Clock.tickFarAway();
  this.clockDestructor();
  Cell.forgetState();
}

CellsTest.prototype.testSetup = function () {
  assert(!!this.clockDestructor);
}

CellsTest.prototype.testCallbacks = function () {
  var cell = new Cell();

  var anyFirings = 0;
  var definedFirings = 0;
  var undefinedFirings = 0;

  var assertIncreases = mkAssertIncreases(function () {
    return {anyFirings: anyFirings,
            definedFirings: definedFirings,
            undefinedFirings: undefinedFirings};
  });

  cell.subscribe(function () {
    definedFirings++;
  });

  cell.subscribeAny(function () {
    anyFirings++;
  });

  cell.subscribe(function () {
    undefinedFirings++;
  }, {
    'undefined': true,
    'changed': false
  });

  assertIncreases(["definedFirings", "anyFirings"],
                  function () {
                    cell.setValue(2);
                  });

  assertIncreases(["undefinedFirings", "anyFirings"],
                  function () {
                    cell.setValue(undefined);
                  });

  assertIncreases(["definedFirings", "anyFirings"],
                  function () {
                    cell.setValue(3);
                  });

  var deliverValue;

  assertIncreases(["undefinedFirings", "anyFirings"], function () {
    cell.setValue(future(function (_deliverValue) {
      deliverValue = _deliverValue;
    }))
  });

  assertEventuallyBecomes(function () {
    return !!deliverValue;
  });

  assertIncreases(["definedFirings", "anyFirings"],
                  function () {
                    deliverValue(4);
                  });

  assertEquals(4, cell.value);
}

CellsTest.prototype.checkFormulaWithFutureCase = function (sources) {
  var cell = new Cell(function () {
    if (realFormula)
      return realFormula();
  }, sources);

  var deliverValue;
  var realFormula = function () {
    return future(function (_deliverValue) {
      deliverValue = _deliverValue;
    });
  }

  assertSame(undefined, cell.value);

  cell.recalculate();

  assertEventuallyBecomes(function () {
    return !!deliverValue
  });

  assertSame(undefined, cell.value);

  deliverValue(3);

  assertEventuallyBecomes(function () {
    return cell.value == 3;
  });

  realFormula = function () {
    return 5;
  }

  cell.recalculate();

  assertEventuallyBecomes(function () {
    return cell.value == 5;
  });
}

CellsTest.prototype.testFormulaWithFuture = function () {
  this.checkFormulaWithFutureCase();
}

CellsTest.prototype.testFormulaWithFutureWithSources = function () {
  this.checkFormulaWithFutureCase({});
}

CellsTest.prototype.testFormulaCells = function () {
  var aCell = new Cell();
  var bCell = new Cell();
  var cCell = new Cell(function (a,b) {
    assertEquals(this.a, a);
    assertEquals(this.b, b);

    var context = this.self.context;
    assertEquals(context.a, aCell);
    assertEquals(aCell.value, a);
    assertEquals(context.b, bCell);
    assertEquals(bCell.value, b);

    return (a + b) % 3;
  }, {a:aCell,b:bCell});

  assertSame(undefined, cCell.value);

  var cUpdates = 0;

  cCell.subscribeAny(function () {cUpdates++});

  var assertIncreases = mkAssertIncreases(function () {
    return {cUpdates: cUpdates};
  });

  assertIncreases([], function () {
    aCell.setValue(1);
  });
  assertSame(undefined, cCell.value);

  assertIncreases("cUpdates", function () {
    bCell.setValue(0);
  });

  assertEquals(1, cCell.value);

  assertIncreases([], function () {
    bCell.setValue(3);
  });
  assertEquals(1, cCell.value);

  assertIncreases("cUpdates", function () {
    bCell.setValue(undefined);
    aCell.setValue(undefined);
  });

  assertSame(undefined, cCell.value);
}

// verifies that we don't overflow anything with long formula
// dependency chains and that we fire callbacks and initiate futures
// when everything is quiet
CellsTest.prototype.testLongChainsAndQuiscentState = function () {
  var cells = [new Cell()];
  _.each(_.range(1000), function (i) {
    cells.push(new Cell(function (dep) {
      if (i == cells.length/2)
        Clock.tickFarAway();
      return dep+1;
    }, {dep: cells[i]}))
  });

  var events = [];

  cells.push(new Cell(function (dep) {
    events.push("last-cell-calculated");
    return dep+1;
  }, {dep: cells[cells.length-1]}));

  cells[0].subscribeAny(function () {
    events.push("initial-cell-callback-fired");
  });

  var futureCell = new Cell(function (dep) {
    return future(function () {
      events.push("future-cell-async-started");
    });
  }, {dep: cells[cells.length/2]});

  cells[0].setValue(0);

  for (var i = cells.length*20; i >= 0; i--) {
    if (cells[cells.length-1].value !== undefined)
      break;
    Clock.tick(20);
  }

  assertEquals(cells.length-1, cells[cells.length-1].value);

  assertEventuallyBecomes(function () {
    return events.length == 3;
  }, function (raiser) {
    console.log("events:", events);
    raiser();
  });

  assertEquals("last-cell-calculated", events[0]);
  assertSetEquals(["future-cell-async-started", "initial-cell-callback-fired"],
                  events.slice(1));
}

CellsTest.prototype.testErrorDetection = function () {
  var cell = new Cell();
  var f = function () {};
  assertException(function () {
    new Cell(f, {c: cell, a: null});
  });
  assertException("non-cell source must be detected", function () {
    new Cell(f, {c: cell, a: 1});
  });
  var okCell;
  assertNoException(function () {
    okCell = new Cell(f, {c: cell});
  });

  assertException(function () {
    (new Cell()).setSources({c: cell});
  });
  assertException("sources cannot be updated yet", function () {
    okCell.setSources({a: new Cell()});
  });

  assertException("unknown sources in args must be detected", function () {
    new Cell(function (a,b) {
    }, {a: new Cell()});
  });
  assertNoException(function () {
    new Cell(function (a) {
    }, {a: new Cell()});
  });

  Clock.tickFarAway();
}

CellsTest.prototype.testSimpleFormulaCell = function () {
  var events = [];
  var cell = new Cell(function () {
    events.push(3);
    return 3;
  });

  Clock.tickFarAway();

  assertEquals([3], events)
  assertEquals(3, cell.value);
}

CellsTest.prototype.testInvalidate = function () {
  var events = [];
  var deliverValue;

  var cell = new Cell(function () {
    events.push("recalc");
    return future(function (_deliverValue) {
      deliverValue = _deliverValue;
    });
  });

  assertEventuallyBecomes(function () {
    return events.length == 1;
  });

  assertEventuallyBecomes(function () {
    return deliverValue != null;
  });

  assertEquals(["recalc"], events);

  cell.invalidate();
  Clock.tickFarAway();
  assertEquals("no pending future recalculation after invalidate",
               ["recalc"], events);

  deliverValue(1);
  Clock.tickFarAway();
  assertEquals(1, cell.value);

  assertEquals(["recalc"], events);
  cell.invalidate();
  Clock.tickFarAway();
  assertEquals("invalidate causes recalculation",
               ["recalc", "recalc"], events);
}

CellsTest.prototype.testDoubleFutureStartBug = function () {
  var cell = new Cell(function () {
    return future(function (deliver) {
      setTimeout(function () {
        deliver(3);
      }, 2000);
    });
  });
  var dependentCell = new Cell(function (a) {
    return future(function (deliver) {
      setTimeout(function () {
        deliver(a + 1);
      }, 500);
    });
  }, {a: cell});

  Clock.tickFarAway();

  cell.setValue(future(function () {}));
  Clock.tickFarAway();
  assertSame(undefined, cell.value);
  assert(!!cell.pendingFuture);

  cell.recalculate();
  Clock.tickFarAway();
  assertEquals(3, cell.value);
  assertEquals(4, dependentCell.value);
}

CellsTest.prototype.testCompute = function () {
  var cell1 = new Cell();
  cell1.setValue(1);
  var cell2 = new Cell()
  cell2.setValue(2);

  var cell3 = new Cell();
  cell3.setValue('cell1');

  cell1.name = 'cell1';
  cell2.name = 'cell2';
  cell3.name = 'cell3';

  var computations = 0;

  var switchedCell = Cell.compute(function (v) {
    computations++;
    switch (v(cell3)) {
    case 'cell1':
      return v(cell1);
    case 'cell2':
      return v(cell2);
    }
  });

  Clock.tickFarAway();

  //no demand no value
  assertSame(undefined, switchedCell.value);
  assertEquals(0, computations);

  var demand = switchedCell.subscribeValue(function () {});

  Clock.tickFarAway();

  assertEquals(1, switchedCell.value);
  assertEquals(2, computations);

  cell1.setValue('newCell1');
  Clock.tickFarAway()
  computations = 0;

  assertEquals('newCell1', switchedCell.value);

  cell2.setValue('newCell2');
  Clock.tickFarAway();

  assertEquals('newCell1', switchedCell.value);
  assertEquals(0, computations);

  cell3.setValue('unknown');
  Clock.tickFarAway();

  assertEquals(undefined, switchedCell.value);
  assertEquals(1, computations);

  cell1.setValue('newerCell1');
  Clock.tickFarAway();

  assertEquals(undefined, switchedCell.value);
  assertEquals(1, computations);

  cell3.setValue('cell2');
  Clock.tickFarAway();

  assertEquals('newCell2', switchedCell.value);
  assertEquals(2, computations);

  // nothing happens after we cancel demand
  demand.cancel();
  Clock.tickFarAway();

  assertEquals(2, computations);

  cell2.setValue('anotherValue');
  cell3.setValue('anotherValue');
  Clock.tickFarAway();

  assertEquals(2, computations);
}
<commit_msg>speedup CellsTest#testLongChainsAndQuiscentState<commit_after>
var CellsTest = TestCase("CellsTest");

CellsTest.prototype.setUp = function () {
  this.clockDestructor = Clock.hijack();
}

CellsTest.prototype.tearDown = function () {
  Clock.tickFarAway();
  this.clockDestructor();
  Cell.forgetState();
}

CellsTest.prototype.testSetup = function () {
  assert(!!this.clockDestructor);
}

CellsTest.prototype.testCallbacks = function () {
  var cell = new Cell();

  var anyFirings = 0;
  var definedFirings = 0;
  var undefinedFirings = 0;

  var assertIncreases = mkAssertIncreases(function () {
    return {anyFirings: anyFirings,
            definedFirings: definedFirings,
            undefinedFirings: undefinedFirings};
  });

  cell.subscribe(function () {
    definedFirings++;
  });

  cell.subscribeAny(function () {
    anyFirings++;
  });

  cell.subscribe(function () {
    undefinedFirings++;
  }, {
    'undefined': true,
    'changed': false
  });

  assertIncreases(["definedFirings", "anyFirings"],
                  function () {
                    cell.setValue(2);
                  });

  assertIncreases(["undefinedFirings", "anyFirings"],
                  function () {
                    cell.setValue(undefined);
                  });

  assertIncreases(["definedFirings", "anyFirings"],
                  function () {
                    cell.setValue(3);
                  });

  var deliverValue;

  assertIncreases(["undefinedFirings", "anyFirings"], function () {
    cell.setValue(future(function (_deliverValue) {
      deliverValue = _deliverValue;
    }))
  });

  assertEventuallyBecomes(function () {
    return !!deliverValue;
  });

  assertIncreases(["definedFirings", "anyFirings"],
                  function () {
                    deliverValue(4);
                  });

  assertEquals(4, cell.value);
}

CellsTest.prototype.checkFormulaWithFutureCase = function (sources) {
  var cell = new Cell(function () {
    if (realFormula)
      return realFormula();
  }, sources);

  var deliverValue;
  var realFormula = function () {
    return future(function (_deliverValue) {
      deliverValue = _deliverValue;
    });
  }

  assertSame(undefined, cell.value);

  cell.recalculate();

  assertEventuallyBecomes(function () {
    return !!deliverValue
  });

  assertSame(undefined, cell.value);

  deliverValue(3);

  assertEventuallyBecomes(function () {
    return cell.value == 3;
  });

  realFormula = function () {
    return 5;
  }

  cell.recalculate();

  assertEventuallyBecomes(function () {
    return cell.value == 5;
  });
}

CellsTest.prototype.testFormulaWithFuture = function () {
  this.checkFormulaWithFutureCase();
}

CellsTest.prototype.testFormulaWithFutureWithSources = function () {
  this.checkFormulaWithFutureCase({});
}

CellsTest.prototype.testFormulaCells = function () {
  var aCell = new Cell();
  var bCell = new Cell();
  var cCell = new Cell(function (a,b) {
    assertEquals(this.a, a);
    assertEquals(this.b, b);

    var context = this.self.context;
    assertEquals(context.a, aCell);
    assertEquals(aCell.value, a);
    assertEquals(context.b, bCell);
    assertEquals(bCell.value, b);

    return (a + b) % 3;
  }, {a:aCell,b:bCell});

  assertSame(undefined, cCell.value);

  var cUpdates = 0;

  cCell.subscribeAny(function () {cUpdates++});

  var assertIncreases = mkAssertIncreases(function () {
    return {cUpdates: cUpdates};
  });

  assertIncreases([], function () {
    aCell.setValue(1);
  });
  assertSame(undefined, cCell.value);

  assertIncreases("cUpdates", function () {
    bCell.setValue(0);
  });

  assertEquals(1, cCell.value);

  assertIncreases([], function () {
    bCell.setValue(3);
  });
  assertEquals(1, cCell.value);

  assertIncreases("cUpdates", function () {
    bCell.setValue(undefined);
    aCell.setValue(undefined);
  });

  assertSame(undefined, cCell.value);
}

CellsTest.prototype.testLongChainsAndQuiscentState = function () {
  var oldPropagateMeta = Cell.prototype.propagateMeta;
  Cell.prototype.propagateMeta = null;
  try {
    this.doTestLongChainsAndQuiscentState();
  } finally {
    Cell.prototype.propagateMeta = oldPropagateMeta;
  }
}

// verifies that we don't overflow anything with long formula
// dependency chains and that we fire callbacks and initiate futures
// when everything is quiet
CellsTest.prototype.doTestLongChainsAndQuiscentState = function () {
  var cells = [new Cell()];
  _.each(_.range(1000), function (i) {
    cells.push(new Cell(function (dep) {
      if (i == cells.length/2)
        Clock.tickFarAway();
      return dep+1;
    }, {dep: cells[i]}))
  });

  var events = [];

  cells.push(new Cell(function (dep) {
    events.push("last-cell-calculated");
    return dep+1;
  }, {dep: cells[cells.length-1]}));

  cells[0].subscribeAny(function () {
    events.push("initial-cell-callback-fired");
  });

  var futureCell = new Cell(function (dep) {
    return future(function () {
      events.push("future-cell-async-started");
    });
  }, {dep: cells[cells.length/2]});

  cells[0].setValue(0);

  for (var i = cells.length*20; i >= 0; i--) {
    if (cells[cells.length-1].value !== undefined)
      break;
    Clock.tick(20);
  }

  assertEquals(cells.length-1, cells[cells.length-1].value);

  assertEventuallyBecomes(function () {
    return events.length == 3;
  }, function (raiser) {
    console.log("events:", events);
    raiser();
  });

  assertEquals("last-cell-calculated", events[0]);
  assertSetEquals(["future-cell-async-started", "initial-cell-callback-fired"],
                  events.slice(1));
}

CellsTest.prototype.testErrorDetection = function () {
  var cell = new Cell();
  var f = function () {};
  assertException(function () {
    new Cell(f, {c: cell, a: null});
  });
  assertException("non-cell source must be detected", function () {
    new Cell(f, {c: cell, a: 1});
  });
  var okCell;
  assertNoException(function () {
    okCell = new Cell(f, {c: cell});
  });

  assertException(function () {
    (new Cell()).setSources({c: cell});
  });
  assertException("sources cannot be updated yet", function () {
    okCell.setSources({a: new Cell()});
  });

  assertException("unknown sources in args must be detected", function () {
    new Cell(function (a,b) {
    }, {a: new Cell()});
  });
  assertNoException(function () {
    new Cell(function (a) {
    }, {a: new Cell()});
  });

  Clock.tickFarAway();
}

CellsTest.prototype.testSimpleFormulaCell = function () {
  var events = [];
  var cell = new Cell(function () {
    events.push(3);
    return 3;
  });

  Clock.tickFarAway();

  assertEquals([3], events)
  assertEquals(3, cell.value);
}

CellsTest.prototype.testInvalidate = function () {
  var events = [];
  var deliverValue;

  var cell = new Cell(function () {
    events.push("recalc");
    return future(function (_deliverValue) {
      deliverValue = _deliverValue;
    });
  });

  assertEventuallyBecomes(function () {
    return events.length == 1;
  });

  assertEventuallyBecomes(function () {
    return deliverValue != null;
  });

  assertEquals(["recalc"], events);

  cell.invalidate();
  Clock.tickFarAway();
  assertEquals("no pending future recalculation after invalidate",
               ["recalc"], events);

  deliverValue(1);
  Clock.tickFarAway();
  assertEquals(1, cell.value);

  assertEquals(["recalc"], events);
  cell.invalidate();
  Clock.tickFarAway();
  assertEquals("invalidate causes recalculation",
               ["recalc", "recalc"], events);
}

CellsTest.prototype.testDoubleFutureStartBug = function () {
  var cell = new Cell(function () {
    return future(function (deliver) {
      setTimeout(function () {
        deliver(3);
      }, 2000);
    });
  });
  var dependentCell = new Cell(function (a) {
    return future(function (deliver) {
      setTimeout(function () {
        deliver(a + 1);
      }, 500);
    });
  }, {a: cell});

  Clock.tickFarAway();

  cell.setValue(future(function () {}));
  Clock.tickFarAway();
  assertSame(undefined, cell.value);
  assert(!!cell.pendingFuture);

  cell.recalculate();
  Clock.tickFarAway();
  assertEquals(3, cell.value);
  assertEquals(4, dependentCell.value);
}

CellsTest.prototype.testCompute = function () {
  var cell1 = new Cell();
  cell1.setValue(1);
  var cell2 = new Cell()
  cell2.setValue(2);

  var cell3 = new Cell();
  cell3.setValue('cell1');

  cell1.name = 'cell1';
  cell2.name = 'cell2';
  cell3.name = 'cell3';

  var computations = 0;

  var switchedCell = Cell.compute(function (v) {
    computations++;
    switch (v(cell3)) {
    case 'cell1':
      return v(cell1);
    case 'cell2':
      return v(cell2);
    }
  });

  Clock.tickFarAway();

  //no demand no value
  assertSame(undefined, switchedCell.value);
  assertEquals(0, computations);

  var demand = switchedCell.subscribeValue(function () {});

  Clock.tickFarAway();

  assertEquals(1, switchedCell.value);
  assertEquals(2, computations);

  cell1.setValue('newCell1');
  Clock.tickFarAway()
  computations = 0;

  assertEquals('newCell1', switchedCell.value);

  cell2.setValue('newCell2');
  Clock.tickFarAway();

  assertEquals('newCell1', switchedCell.value);
  assertEquals(0, computations);

  cell3.setValue('unknown');
  Clock.tickFarAway();

  assertEquals(undefined, switchedCell.value);
  assertEquals(1, computations);

  cell1.setValue('newerCell1');
  Clock.tickFarAway();

  assertEquals(undefined, switchedCell.value);
  assertEquals(1, computations);

  cell3.setValue('cell2');
  Clock.tickFarAway();

  assertEquals('newCell2', switchedCell.value);
  assertEquals(2, computations);

  // nothing happens after we cancel demand
  demand.cancel();
  Clock.tickFarAway();

  assertEquals(2, computations);

  cell2.setValue('anotherValue');
  cell3.setValue('anotherValue');
  Clock.tickFarAway();

  assertEquals(2, computations);
}
<|endoftext|>


<commit_before>var async = require('async');
var cheerio = require('cheerio');
var crypto = require('crypto');
var execTime = require('exec-time')
var fs = require('fs');
var request = require('request');

var sites = [
    'http://bukk.it',
    'http://wil.to/_',
    'http://misatkes.com',
    'http://meyerweb.com/bkkt'
];

var profiler = new execTime('processing sites');

function compareItems(a, b) {
    if (a.name < b.name) return -1;
    if (a.name > b.name) return 1;
    return 0;
}

function formatResults(results) {
    var sortedList, i = 1, len = results.length, args = [];
    for (; i < len; i++) {
        args.push(results[i]);
    }
    sortedList = Array.prototype.concat.apply(results[0], args).sort(compareItems);
    return sortedList;
}

function outputJson(images) {
    var serializedStr = JSON.stringify(images);
    fs.writeFile('images.json', serializedStr);
    profiler.step('done');
    return serializedStr;
}

function parallelDone(err, results) {
    if (err || !results || !results.length) return console.log('async.parallel: %s - %s', err, results);
    var images;
    images = formatResults(results);
    console.log('Processed ' + images.length + ' images');
    return outputJson(images);
}

function mapDone(err, results) {
    if (err || !results || !results.length) return console.log('async.map: %s - %s', err, results);
    return async.parallel(results, parallelDone);
}

function createLink(origin, name) {
    var url = origin + '/' + name;
    return {
        id: crypto.createHash('md5').update(url).digest('hex'),
        url: url,
        name: name,
        origin: origin
    };
}

function eachOrigin(origin, callback) {
    return callback(null, function (parallelCallback) {
        return request(origin, function (err, res, body) {
            var $ = cheerio.load(body);
            var selector = 'a[href$=".gif"], a[href$=".jpg"], a[href$=".jpeg"], a[href$=".png"]';
            var links = [];
            $(selector).each(function () {
                var link = createLink(origin, $(this).attr('href'));
                links.push(link);
            });
            return parallelCallback(null, links);
        });
    });
}

profiler.beginProfiling();

async.map(sites, eachOrigin, mapDone);
<commit_msg>Slight tweak to the public API (cleaner names)<commit_after>var async = require('async');
var cheerio = require('cheerio');
var crypto = require('crypto');
var execTime = require('exec-time')
var fs = require('fs');
var request = require('request');

var protocol = 'http://';
var sites = [
    'bukk.it',
    'wil.to/_',
    'misatkes.com',
    'meyerweb.com/bkkt'
];

var profiler = new execTime('processing sites');

function compareItems(a, b) {
    if (a.name < b.name) return -1;
    if (a.name > b.name) return 1;
    return 0;
}

function formatResults(results) {
    var sortedList, i = 1, len = results.length, args = [];
    for (; i < len; i++) {
        args.push(results[i]);
    }
    sortedList = Array.prototype.concat.apply(results[0], args).sort(compareItems);
    return sortedList;
}

function outputJson(images) {
    var serializedStr = JSON.stringify(images);
    fs.writeFile('images.json', serializedStr);
    profiler.step('done');
    return serializedStr;
}

function parallelDone(err, results) {
    if (err || !results || !results.length) return console.log('async.parallel: %s - %s', err, results);
    var images;
    images = formatResults(results);
    console.log('Processed ' + images.length + ' images');
    return outputJson(images);
}

function mapDone(err, results) {
    if (err || !results || !results.length) return console.log('async.map: %s - %s', err, results);
    return async.parallel(results, parallelDone);
}

function createLink(origin, name) {
    var url = protocol + origin + '/' + name;
    return {
        id: crypto.createHash('md5').update(url).digest('hex'),
        url: url,
        name: name,
        origin: origin
    };
}

function eachOrigin(origin, callback) {
    return callback(null, function (parallelCallback) {
        return request(protocol + origin, function (err, res, body) {
            var $ = cheerio.load(body);
            var selector = 'a[href$=".gif"], a[href$=".jpg"], a[href$=".jpeg"], a[href$=".png"]';
            var links = [];
            $(selector).each(function () {
                var link = createLink(origin, $(this).attr('href'));
                links.push(link);
            });
            return parallelCallback(null, links);
        });
    });
}

profiler.beginProfiling();

async.map(sites, eachOrigin, mapDone);
<|endoftext|>


<commit_before>const crypto = require("crypto");
const execPromise = require("./execPromise");
// for fs.remove. replace with fs.rm after dropping v12 support
const fse = require("fs-extra");
const fsNonPromise = require("fs");
const { promises: fs } = fsNonPromise;
const path = require("path");
const got = require("got");
const { performance } = require("perf_hooks");
const { promisify } = require("util");
const stream = require("stream");
const tar = require("tar-fs");
const zlib = require("zlib");

const pipeline = promisify(stream.pipeline);

const win32BatPath = path.join(__dirname, "build-openssl.bat");
const vendorPath = path.resolve(__dirname, "..", "vendor");
const distrosFilePath = path.join(vendorPath, "static_config", "openssl_distributions.json");
const extractPath = path.join(vendorPath, "openssl");

// TODO: Determine if we are GYPing in Debug
const getIsDebug = () => false;

const getOpenSSLSourceUrl = (version) => `https://www.openssl.org/source/openssl-${version}.tar.gz`;
const getOpenSSLSourceSha256Url = (version) => `${getOpenSSLSourceUrl(version)}.sha256`;

class HashVerify extends stream.Transform {
  constructor(algorithm, expected) {
    super();
    this.expected = expected;
    this.hash = crypto.createHash(algorithm);
  }

  _transform(chunk, encoding, callback) {
    this.hash.update(chunk, encoding);
    callback(null, chunk);
  }

  _final(callback) {
    const digest = this.hash.digest("hex");
    const digestOk = digest === this.expected;
    callback(digestOk ? null : new Error(`Digest not OK: ${digest} !== ${this.expected}`));
  }
}

const buildDarwin = async (buildCwd, macOsDeploymentTarget) => {
  await execPromise(`./Configure darwin64-x86_64-cc shared enable-ec_nistp_64_gcc_128 no-ssl2 no-ssl3 no-comp --prefix="${
    extractPath
  }" --openssldir="${extractPath}" -mmacosx-version-min=${macOsDeploymentTarget}`, {
    cwd: buildCwd
  }, { pipeOutput: true });

  await execPromise("make", {
    cwd: buildCwd
  }, { pipeOutput: true });

  await execPromise("make test", {
    cwd: buildCwd
  }, { pipeOutput: true });

  await execPromise("make install", {
    cwd: buildCwd,
    maxBuffer: 10 * 1024 * 1024 // we should really just use spawn
  }, { pipeOutput: true });
};

const buildWin32 = async (buildCwd) => {
  const vcvarsallPath = process.env.npm_config_vcvarsall_path || `${
    process.env.ProgramFiles || "C:\\Program Files"
  }\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\Auxiliary\\Build\\vcvarsall.bat`;
  const vcvarsallArch = process.arch === "x64" ? "x64" : "x86";
  const vcTarget = process.arch === "x64" ? "VC-WIN64A" : "VC-WIN32";
  await execPromise(`"${win32BatPath}" "${vcvarsallPath}" ${vcvarsallArch} ${vcTarget}`, {
    cwd: buildCwd,
    maxBuffer: 10 * 1024 * 1024 // we should really just use spawn
  }, { pipeOutput: true });
};

const removeOpenSSLIfOudated = async (openSSLVersion) => {
  try {
    let pkgconfigContent;
    try {
      pkgconfigContent = await fs.readFile(path.join(extractPath, "lib", "pkgconfig", "openssl.pc"), "utf8");
    } catch {
      /* if we fail to read the file, assume removal not required */
    }

    if (!pkgconfigContent) {
      return;
    }

    const versionMatch = pkgconfigContent.match(/\nVersion: (\d\.\d\.\d[a-z]*)\n/);
    const installedVersion = versionMatch && versionMatch[1];
    if (!installedVersion || installedVersion === openSSLVersion) {
      return;
    }

    console.log("Removing outdated OpenSSL at: ", extractPath);
    await fse.remove(extractPath);
    console.log("Outdated OpenSSL removed.");
  } catch (err) {
    console.log("Remove outdated OpenSSL failed: ", err);
  }
};

const buildOpenSSLIfNecessary = async (openSSLVersion, macOsDeploymentTarget) => {
  if (process.platform !== "darwin" && process.platform !== "win32") {
    console.log(`Skipping OpenSSL build, not required on ${process.platform}`);
    return;
  }

  await removeOpenSSLIfOudated(openSSLVersion);

  try {
    await fs.stat(extractPath);
    console.log("Skipping OpenSSL build, dir exists");
    return;
  } catch {}

  const openSSLUrl = getOpenSSLSourceUrl(openSSLVersion);
  const openSSLSha256Url = getOpenSSLSourceSha256Url(openSSLVersion);

  const openSSLSha256 = (await got(openSSLSha256Url)).body.trim();

  const downloadStream = got.stream(openSSLUrl);
  let lastReport = performance.now();
  downloadStream.on("downloadProgress", ({ percent, transferred, total }) => {
    const currentTime = performance.now();
    if (currentTime - lastReport > 1 * 1000) {
      lastReport = currentTime;
      console.log(`progress: ${transferred}/${total} (${(percent * 100).toFixed(2)}%)`)
    }
  });

  await pipeline(
    downloadStream,
    new HashVerify("sha256", openSSLSha256),
    zlib.createGunzip(),
    tar.extract(extractPath)
  );

  console.log("OpenSSL download + extract complete: SHA256 OK.");

  const buildCwd = path.join(extractPath, `openssl-${openSSLVersion}`);

  if (process.platform === "darwin") {
    await buildDarwin(buildCwd, macOsDeploymentTarget);
  } else if (process.platform === "win32") {
    await buildWin32(buildCwd);
  } else {
    throw new Error(`Unknown platform: ${process.platform}`);
  }

  console.log("Build finished.");
}

const acquireOpenSSL = async () => {
  try {
    let macOsDeploymentTarget;
    if (process.platform === "darwin") {
      macOsDeploymentTarget = process.argv[2];
      if (!macOsDeploymentTarget || !macOsDeploymentTarget.match(/\d+\.\d+/)) {
        throw new Error(`Invalid macOsDeploymentTarget: ${macOsDeploymentTarget}`);
      }
    }

    await buildOpenSSLIfNecessary("1.1.1c", macOsDeploymentTarget);
  } catch (err) {
    console.error("Acquire failed: ", err);
    process.exit(1);
  }
};

acquireOpenSSL();
<commit_msg>Update OpenSSL to 1.1.1l<commit_after>const crypto = require("crypto");
const execPromise = require("./execPromise");
// for fs.remove. replace with fs.rm after dropping v12 support
const fse = require("fs-extra");
const fsNonPromise = require("fs");
const { promises: fs } = fsNonPromise;
const path = require("path");
const got = require("got");
const { performance } = require("perf_hooks");
const { promisify } = require("util");
const stream = require("stream");
const tar = require("tar-fs");
const zlib = require("zlib");

const pipeline = promisify(stream.pipeline);

const win32BatPath = path.join(__dirname, "build-openssl.bat");
const vendorPath = path.resolve(__dirname, "..", "vendor");
const distrosFilePath = path.join(vendorPath, "static_config", "openssl_distributions.json");
const extractPath = path.join(vendorPath, "openssl");

// TODO: Determine if we are GYPing in Debug
const getIsDebug = () => false;

const getOpenSSLSourceUrl = (version) => `https://www.openssl.org/source/openssl-${version}.tar.gz`;
const getOpenSSLSourceSha256Url = (version) => `${getOpenSSLSourceUrl(version)}.sha256`;

class HashVerify extends stream.Transform {
  constructor(algorithm, expected) {
    super();
    this.expected = expected;
    this.hash = crypto.createHash(algorithm);
  }

  _transform(chunk, encoding, callback) {
    this.hash.update(chunk, encoding);
    callback(null, chunk);
  }

  _final(callback) {
    const digest = this.hash.digest("hex");
    const digestOk = digest === this.expected;
    callback(digestOk ? null : new Error(`Digest not OK: ${digest} !== ${this.expected}`));
  }
}

const buildDarwin = async (buildCwd, macOsDeploymentTarget) => {
  await execPromise(`./Configure darwin64-x86_64-cc shared enable-ec_nistp_64_gcc_128 no-ssl2 no-ssl3 no-comp --prefix="${
    extractPath
  }" --openssldir="${extractPath}" -mmacosx-version-min=${macOsDeploymentTarget}`, {
    cwd: buildCwd
  }, { pipeOutput: true });

  await execPromise("make", {
    cwd: buildCwd
  }, { pipeOutput: true });

  await execPromise("make test", {
    cwd: buildCwd
  }, { pipeOutput: true });

  await execPromise("make install", {
    cwd: buildCwd,
    maxBuffer: 10 * 1024 * 1024 // we should really just use spawn
  }, { pipeOutput: true });
};

const buildWin32 = async (buildCwd) => {
  const vcvarsallPath = process.env.npm_config_vcvarsall_path || `${
    process.env.ProgramFiles || "C:\\Program Files"
  }\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\Auxiliary\\Build\\vcvarsall.bat`;
  const vcvarsallArch = process.arch === "x64" ? "x64" : "x86";
  const vcTarget = process.arch === "x64" ? "VC-WIN64A" : "VC-WIN32";
  await execPromise(`"${win32BatPath}" "${vcvarsallPath}" ${vcvarsallArch} ${vcTarget}`, {
    cwd: buildCwd,
    maxBuffer: 10 * 1024 * 1024 // we should really just use spawn
  }, { pipeOutput: true });
};

const removeOpenSSLIfOudated = async (openSSLVersion) => {
  try {
    let pkgconfigContent;
    try {
      pkgconfigContent = await fs.readFile(path.join(extractPath, "lib", "pkgconfig", "openssl.pc"), "utf8");
    } catch {
      /* if we fail to read the file, assume removal not required */
    }

    if (!pkgconfigContent) {
      return;
    }

    const versionMatch = pkgconfigContent.match(/\nVersion: (\d\.\d\.\d[a-z]*)\n/);
    const installedVersion = versionMatch && versionMatch[1];
    if (!installedVersion || installedVersion === openSSLVersion) {
      return;
    }

    console.log("Removing outdated OpenSSL at: ", extractPath);
    await fse.remove(extractPath);
    console.log("Outdated OpenSSL removed.");
  } catch (err) {
    console.log("Remove outdated OpenSSL failed: ", err);
  }
};

const buildOpenSSLIfNecessary = async (openSSLVersion, macOsDeploymentTarget) => {
  if (process.platform !== "darwin" && process.platform !== "win32") {
    console.log(`Skipping OpenSSL build, not required on ${process.platform}`);
    return;
  }

  await removeOpenSSLIfOudated(openSSLVersion);

  try {
    await fs.stat(extractPath);
    console.log("Skipping OpenSSL build, dir exists");
    return;
  } catch {}

  const openSSLUrl = getOpenSSLSourceUrl(openSSLVersion);
  const openSSLSha256Url = getOpenSSLSourceSha256Url(openSSLVersion);

  const openSSLSha256 = (await got(openSSLSha256Url)).body.trim();

  const downloadStream = got.stream(openSSLUrl);
  let lastReport = performance.now();
  downloadStream.on("downloadProgress", ({ percent, transferred, total }) => {
    const currentTime = performance.now();
    if (currentTime - lastReport > 1 * 1000) {
      lastReport = currentTime;
      console.log(`progress: ${transferred}/${total} (${(percent * 100).toFixed(2)}%)`)
    }
  });

  await pipeline(
    downloadStream,
    new HashVerify("sha256", openSSLSha256),
    zlib.createGunzip(),
    tar.extract(extractPath)
  );

  console.log("OpenSSL download + extract complete: SHA256 OK.");

  const buildCwd = path.join(extractPath, `openssl-${openSSLVersion}`);

  if (process.platform === "darwin") {
    await buildDarwin(buildCwd, macOsDeploymentTarget);
  } else if (process.platform === "win32") {
    await buildWin32(buildCwd);
  } else {
    throw new Error(`Unknown platform: ${process.platform}`);
  }

  console.log("Build finished.");
}

const acquireOpenSSL = async () => {
  try {
    let macOsDeploymentTarget;
    if (process.platform === "darwin") {
      macOsDeploymentTarget = process.argv[2];
      if (!macOsDeploymentTarget || !macOsDeploymentTarget.match(/\d+\.\d+/)) {
        throw new Error(`Invalid macOsDeploymentTarget: ${macOsDeploymentTarget}`);
      }
    }

    await buildOpenSSLIfNecessary("1.1.1l", macOsDeploymentTarget);
  } catch (err) {
    console.error("Acquire failed: ", err);
    process.exit(1);
  }
};

acquireOpenSSL();
<|endoftext|>


<commit_before>// Substitutes

var chars = {
	'o': ['0'],
	'e': ['3']
}

function convert(text){
	var probab = 0.4
	len = text.length
	var newText = ""

	for (var i=0; i < len; i++){
		charCode = text[i].charCodeAt()
		chance = Math.random()

		if (chance <= probab){
			if (charCode >= 65 && charCode <= 90){
				newText += String.fromCharCode(charCode + 32)
			} else if (charCode >= 97 && charCode <= 122){
				newText += (String.fromCharCode(charCode - 32))[0]
			} else {
				newText += text[i]
			}
		} else {
			newText += text[i]
		}
	}

	return newText
}

function inputChangeEvent(){
	val = $("#input").val()
	newVal = convert(val)
	console.log(newVal)
	$("#output").text(newVal)
}

$(document).ready(function(){
	$("#input").bind('input propertychange', inputChangeEvent)
})
<commit_msg>convert sequence of chars too (this => dis)<commit_after>// Substitutes

var chars = {
	'o': ['0'],
	'e': ['3'],
	'i': ['1']
}

var words = {
	'tha': 'da',
	'thi': 'di'
}

function convertWords(text){
	var text = String(text)
	var probab = 0.6

	for (var key in words) {
		reg = new RegExp(key, "gi")
		if (reg.test(text)){
			chance = Math.random()
			if (chance <= probab){
				text = text.replace(reg, words[key])
			}
		}
	}

	return text
}

function convertSingleChar(text){
	var probab = 0.4
	len = text.length
	var newText = ""

	for (var i=0; i < len; i++){
		charCode = text[i].charCodeAt()
		chance = Math.random()

		if (chance <= probab){
			if (charCode >= 65 && charCode <= 90){
				newText += String.fromCharCode(charCode + 32)
			} else if (charCode >= 97 && charCode <= 122){
				newText += (String.fromCharCode(charCode - 32))[0]
			} else {
				newText += text[i]
			}
		} else {
			newText += text[i]
		}
	}

	return newText
}

function inputChangeEvent(){
	val = $("#input").val()
	newVal = convertWords(val)
	console.log(newVal)
	newVal = convertSingleChar(newVal)
	console.log(newVal)
	$("#output").text(newVal)
}

$(document).ready(function(){
	$("#input").bind('input propertychange', inputChangeEvent)
})
<|endoftext|>


<commit_before>
if(u.ga_account) {

    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', u.ga_account, u.ga_domain);
    ga('send', 'pageview');

// 	var _gaq = _gaq || [];
// 	_gaq.push(['_setAccount', u.ga_account]);
// 	_gaq.push(['_trackPageview']);
//
// 	(function() {
// 		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
// 		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
//
// //		text += "#google
";
//
// 		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
// 	})();

	u.stats = new function() {

		this.pageView = function(url) {
//			_gaq.push(['_trackPageview', url]);
			ga('send', 'pageview', url);
		}

		this.event = function(node, action, label) {
//			_gaq.push(['_trackEvent', location.href.replace(document.location.protocol + "//" + document.domain, ""), action, (label ? label : this.nodeSnippet(node))]);
			ga('_trackEvent', location.href.replace(document.location.protocol + "//" + document.domain, ""), action, (label ? label : this.nodeSnippet(node)));
		}

		this.customVar = function(slot, name, value, scope) {

			// _gaq.push(['_setCustomVar',
			//       slot,		// This custom var is set to slot #1.  Required parameter.
			//       name,		// The name of the custom variable.  Required parameter.
			//       value,	// The value of the custom variable.  Required parameter.
			//       scope		// Sets the scope to visitor-level.  Optional parameter.
			//  ]);

		}

		this.nodeSnippet = function(e) {

			if(e.textContent != undefined) {
				return u.cutString(e.textContent.trim(), 20) + "(<"+e.nodeName+">)";
			}
			else {
				return u.cutString(e.innerText.trim(), 20) + "(<"+e.nodeName+">)";
			}
		}
	}

}
<commit_msg>added defer to google include<commit_after>
if(u.ga_account) {

    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.defer=true;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', u.ga_account, u.ga_domain);
    ga('send', 'pageview');

// 	var _gaq = _gaq || [];
// 	_gaq.push(['_setAccount', u.ga_account]);
// 	_gaq.push(['_trackPageview']);
//
// 	(function() {
// 		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
// 		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
//
// //		text += "#google
";
//
// 		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
// 	})();

	u.stats = new function() {

		this.pageView = function(url) {
//			_gaq.push(['_trackPageview', url]);
			ga('send', 'pageview', url);
		}

		this.event = function(node, action, label) {
//			_gaq.push(['_trackEvent', location.href.replace(document.location.protocol + "//" + document.domain, ""), action, (label ? label : this.nodeSnippet(node))]);
			ga('_trackEvent', location.href.replace(document.location.protocol + "//" + document.domain, ""), action, (label ? label : this.nodeSnippet(node)));
		}

		this.customVar = function(slot, name, value, scope) {

			// _gaq.push(['_setCustomVar',
			//       slot,		// This custom var is set to slot #1.  Required parameter.
			//       name,		// The name of the custom variable.  Required parameter.
			//       value,	// The value of the custom variable.  Required parameter.
			//       scope		// Sets the scope to visitor-level.  Optional parameter.
			//  ]);

		}

		this.nodeSnippet = function(e) {

			if(e.textContent != undefined) {
				return u.cutString(e.textContent.trim(), 20) + "(<"+e.nodeName+">)";
			}
			else {
				return u.cutString(e.innerText.trim(), 20) + "(<"+e.nodeName+">)";
			}
		}
	}

}
<|endoftext|>


<commit_before>#!/usr/bin/env /usr/local/bin/node

'use strict';

const https = require( 'https' );
const fs = require( 'fs' );

const ACCESS_TOKEN = ''; // here put your access token
const CLIENT_ID = ''; // here put your client id

const args = process.argv.slice( 2 );

const DEFAULT_HTTP_OPTIONS = {
	host: 'a.wunderlist.com',
	path: '/api/v1/lists',
	headers: {
		'X-Access-Token': args[ 0 ] || ACCESS_TOKEN,
		'X-Client-ID': args[ 1 ] || CLIENT_ID
	}
};

const _result = Symbol( 'result' );

class OutputBuilder {
	constructor() {
		this[ _result ] = '';
	}

	/**
	 * Adds string to output and adds new line to the end.
	 *
	 * @param {String} line
	 *
	 * @returns {OutputBuilder}
	 */
	addLine( line ) {
		this[ _result ] += line + ' \n';

		return this;
	}

	/**
	 * Adds empty line.
	 *
	 * @returns {OutputBuilder}
	 */
	addSeparator() {
		this.addLine( '' );

		return this;
	}

	/**
	 * Returns output.
	 *
	 * @returns {String}
	 */
	get result() {
		return this[ _result ];
	}
}

const TEMP_PATH = '/tmp/';

class FileCache {
	static saveValue( fileName, value ) {
		return new Promise( ( resolve, reject ) => {
			const path = TEMP_PATH + fileName;

			value = JSON.stringify( value );

			fs.writeFile( path, value, ( err ) => {
				if ( err ) {
					return reject( err );
				}

				resolve();
			} );
		} );
	}

	static getValue( fileName ) {
		return new Promise( ( resolve, reject ) => {
			fs.readFile( `${TEMP_PATH}${fileName}`, 'utf8', ( err, data ) => {
				if ( err ) {
					return reject( err );
				}

				resolve( JSON.parse( data ) );
			} );
		} );
	}
}

class WunderlistGeekTool {
	render() {
		const output = new OutputBuilder();

		console.log( `Last update: ${new Date().toUTCString()}` );
		output.addSeparator();

		this._getListsWithTasks()
			.then( ( lists ) => {
				for ( const list of lists.filter( list => list.tasks.length ) ) {
					output.addLine( `${list.title} ( ${list.tasks.length} )` );

					for ( const task of list.tasks ) {
						let daysToTask = this._getDaysToTask( task );

						output.addLine( `     ${task.starred ? '*' : ' '}${this._isAfterDeadline( task ) ? '!' : ' ' }    ${task.title}    ${task.due_date ||
						''}${daysToTask !== null ? ` ( ${daysToTask} )` : ''}` );
					}
				}

				console.log( output.result );

				FileCache.saveValue( 'output', {
					result: output.result,
					date: new Date()
				} );
			} )
			.catch( ( err ) => {
				if ( err[ 'invalid_request' ] ) {
					output.addLine( 'Invalid Request. It is possible that lack of data - Access Token or Client Id' ).addSeparator();
				}

				FileCache.getValue( 'output' )
					.then( ( data ) => {
						if ( data ) {
							output.addLine( data.result )
								.addSeparator()
								.addLine( `Information from cache ( ${new Date( data.date ).toUTCString()} )` );

							console.log( output.result );
						}
					} );
			} );
	}

	/**
	 * Returns information about the number of days to task.
	 *
	 * @private
	 * @param {Task} task
	 * @returns {Number}
	 */
	_getDaysToTask( task ) {
		if ( !task.due_date ) {
			return null;
		}

		const dueDate = new Date( task.due_date );
		dueDate.setHours( 0, 0, 0, 0 );

		return Math.round( (dueDate.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24) );
	}

	/**
	 * Returns information whether a task is after the deadline.
	 *
	 * @private
	 * @param {Task} task
	 * @returns {Boolean}
	 */
	_isAfterDeadline( task ) {
		const dayToTask = this._getDaysToTask( task );

		return dayToTask !== null && dayToTask <= 0;
	}

	/**
	 * Returns lists.
	 *
	 * @private
	 * @returns {Promise.<Array.<List>>}
	 */
	_getLists() {
		return HttpHelper.get( '/api/v1/lists' )
			.then( ( lists ) => {
				return this._getListsOrder()
					.then( ( ids ) => {
						const results = [];

						for ( const id of ids ) {
							const list = lists.find( list => list.id === id );

							if ( list ) {
								results.push( list );
							}
						}

						return results;
					} );
			} );
	}

	/**
	 * Returns lists with included tasks.
	 *
	 * @private
	 * @returns {Promise.<Array.<List>>}
	 */
	_getListsWithTasks() {
		return this._getLists().then( ( lists ) => {
			const getAllTasks = [];

			for ( const list of lists ) {
				getAllTasks.push( new Promise( ( resolve ) => {
					this._getTasksForList( list.id )
						.then( ( tasks ) => {
							list.tasks = tasks;
							resolve();
						} );
				} ) );
			}

			return Promise.all( getAllTasks )
				.then( () => lists );
		} );
	}

	/**
	 * Returns lists order.
	 *
	 * @private
	 * @returns {Promise.<Array.<Number>>}
	 */
	_getListsOrder() {
		return HttpHelper.get( '/api/v1/list_positions' )
			.then( ( res ) => res[ 0 ].values );
	}

	/**
	 * Return tasks for list.
	 *
	 * @private
	 * @param {Number} listId
	 * @returns {Promise.<Array.<Task>>}
	 */
	_getTasksForList( listId ) {
		return HttpHelper.get( `/api/v1/tasks?list_id=${listId}` )
			.then( ( tasks ) => {
				const results = [];

				return this._getTasksOrder( listId )
					.then( ( ids ) => {
						for ( const id of ids ) {
							const task = tasks.find( task => task.id === id );

							if ( task ) {
								results.push( task );
							}
						}

						return results;
					} );
			} );
	}

	/**
	 * Returns tasks order.
	 *
	 * @private
	 * @param {Number} listId
	 * @returns {Promise.<Array.<Number>>}
	 */
	_getTasksOrder( listId ) {
		return HttpHelper.get( `/api/v1/task_positions?list_id=${listId}` )
			.then( ( res ) => res[ 0 ].values );
	}
}

class HttpHelper {
	/**
	 * Sends request to Wunderlist API.
	 *
	 * @param {String} path
	 * @returns {Promise.<*>}
	 */
	static get( path ) {
		return new Promise( ( resolve, reject )=> {
			const options = Object.assign( {}, DEFAULT_HTTP_OPTIONS );
			options.path = path;

			https.get( options, ( res ) => {
				let body = '';

				res.on( 'data', ( chunk ) => {
					body += chunk;
				} );

				res.on( 'end', () => {
					const response = JSON.parse( body );

					if ( response[ 'invalid_request' ] ) {
						return reject( response );
					}

					resolve( response );
				} );

				res.on( 'error', ( err ) => reject( err ) );

				res.on( 'timeout', () => reject() );
			} );
		} );
	}
}

new WunderlistGeekTool().render();

/**
 * @typedef {Object} List
 * @property {Number} id
 * @property {Date} created_at
 * @property {String} title
 */

/**
 * @typedef {Object} ListWithTasks
 * @property {Number} id
 * @property {Date} created_at
 * @property {String} title
 * @property {Array.<Task>} tasks
 */

/**
 * @typedef {Object} Task
 * @property {Number} id
 * @property {Date} created_at
 * @property {Date} due_date
 * @property {String} title
 * @property {Boolean} starred
 */
<commit_msg>Added missing doc and small refactor<commit_after>#!/usr/bin/env /usr/local/bin/node

'use strict';

const https = require( 'https' );
const fs = require( 'fs' );

const ACCESS_TOKEN = ''; // here put your access token
const CLIENT_ID = ''; // here put your client id

const args = process.argv.slice( 2 );

const DEFAULT_HTTP_OPTIONS = {
	host: 'a.wunderlist.com',
	path: '/api/v1/lists',
	headers: {
		'X-Access-Token': args[ 0 ] || ACCESS_TOKEN,
		'X-Client-ID': args[ 1 ] || CLIENT_ID
	}
};

const _result = Symbol( 'result' );
const _printFunc = Symbol( 'printFunc' );

class OutputBuilder {
	constructor( printFunc ) {
		this[ _result ] = '';
		this[ _printFunc ] = printFunc;
	}

	/**
	 * Returns output.
	 *
	 * @returns {String}
	 */
	get result() {
		return this[ _result ];
	}

	/**
	 * Adds string to output and adds new line to the end.
	 *
	 * @param {String} line
	 *
	 * @returns {OutputBuilder}
	 */
	addLine( line ) {
		this[ _result ] += line + ' \n';

		return this;
	}

	/**
	 * Adds empty line.
	 *
	 * @returns {OutputBuilder}
	 */
	addSeparator() {
		this.addLine( '' );

		return this;
	}

	/**
	 * Prinst result.
	 */
	print() {
		this[ _printFunc ]( this.result );
	}
}

const TEMP_PATH = '/tmp/';

class FileCache {
	/**
	 * Saves information in file.
	 *
	 * @param {String} fileName
	 * @param {Object} value
	 * @returns {Promise}
	 */
	static saveValue( fileName, value ) {
		return new Promise( ( resolve, reject ) => {
			const path = TEMP_PATH + fileName;

			value = JSON.stringify( value );

			fs.writeFile( path, value, ( err ) => {
				if ( err ) {
					return reject( err );
				}

				resolve();
			} );
		} );
	}

	/**
	 * Returns object from cache file.
	 *
	 * @param {String} fileName
	 * @returns {Promise.<Object>}
	 */
	static getValue( fileName ) {
		return new Promise( ( resolve, reject ) => {
			fs.readFile( `${TEMP_PATH}${fileName}`, 'utf8', ( err, data ) => {
				if ( err ) {
					return reject( err );
				}

				resolve( JSON.parse( data ) );
			} );
		} );
	}
}

class WunderlistGeekTool {
	/**
	 * Gets data and displays them.
	 */
	run() {
		const output = new OutputBuilder( console.log );

		console.log( `Last update: ${new Date().toUTCString()}` );
		output.addSeparator();

		this._getListsWithTasks()
			.then( ( lists ) => {
				for ( const list of lists.filter( list => list.tasks.length ) ) {
					output.addLine( `${list.title} ( ${list.tasks.length} )` );

					for ( const task of list.tasks ) {
						let daysToTask = this._getDaysToTask( task );

						output.addLine( `     ${task.starred ? '*' : ' '}${this._isAfterDeadline( task ) ? '!' : ' ' }    ${task.title}    ${task.due_date ||
						''}${daysToTask !== null ? ` ( ${daysToTask} )` : ''}` );
					}
				}

				output.print();

				FileCache.saveValue( 'output', {
					result: output.result,
					date: new Date()
				} );
			} )
			.catch( ( err ) => {
				if ( err[ 'invalid_request' ] ) {
					output.addLine( 'Invalid Request. It is possible that lack of data - Access Token or Client Id' ).addSeparator();
				}

				FileCache.getValue( 'output' )
					.then( ( data ) => {
						if ( data ) {
							output.addLine( data.result )
								.addSeparator()
								.addLine( `Information from cache ( ${new Date( data.date ).toUTCString()} )` );

							output.print();
						}
					} );
			} );
	}

	/**
	 * Returns information about the number of days to task.
	 *
	 * @private
	 * @param {Task} task
	 * @returns {Number}
	 */
	_getDaysToTask( task ) {
		if ( !task.due_date ) {
			return null;
		}

		const dueDate = new Date( task.due_date );
		dueDate.setHours( 0, 0, 0, 0 );

		return Math.round( (dueDate.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24) );
	}

	/**
	 * Returns information whether a task is after the deadline.
	 *
	 * @private
	 * @param {Task} task
	 * @returns {Boolean}
	 */
	_isAfterDeadline( task ) {
		const dayToTask = this._getDaysToTask( task );

		return dayToTask !== null && dayToTask <= 0;
	}

	/**
	 * Returns lists.
	 *
	 * @private
	 * @returns {Promise.<Array.<List>>}
	 */
	_getLists() {
		return HttpHelper.get( '/api/v1/lists' )
			.then( ( lists ) => {
				return this._getListsOrder()
					.then( ( ids ) => {
						const results = [];

						for ( const id of ids ) {
							const list = lists.find( list => list.id === id );

							if ( list ) {
								results.push( list );
							}
						}

						return results;
					} );
			} );
	}

	/**
	 * Returns lists with included tasks.
	 *
	 * @private
	 * @returns {Promise.<Array.<List>>}
	 */
	_getListsWithTasks() {
		return this._getLists().then( ( lists ) => {
			const getAllTasks = [];

			for ( const list of lists ) {
				getAllTasks.push( new Promise( ( resolve ) => {
					this._getTasksForList( list.id )
						.then( ( tasks ) => {
							list.tasks = tasks;
							resolve();
						} );
				} ) );
			}

			return Promise.all( getAllTasks )
				.then( () => lists );
		} );
	}

	/**
	 * Returns lists order.
	 *
	 * @private
	 * @returns {Promise.<Array.<Number>>}
	 */
	_getListsOrder() {
		return HttpHelper.get( '/api/v1/list_positions' )
			.then( ( res ) => res[ 0 ].values );
	}

	/**
	 * Return tasks for list.
	 *
	 * @private
	 * @param {Number} listId
	 * @returns {Promise.<Array.<Task>>}
	 */
	_getTasksForList( listId ) {
		return HttpHelper.get( `/api/v1/tasks?list_id=${listId}` )
			.then( ( tasks ) => {
				const results = [];

				return this._getTasksOrder( listId )
					.then( ( ids ) => {
						for ( const id of ids ) {
							const task = tasks.find( task => task.id === id );

							if ( task ) {
								results.push( task );
							}
						}

						return results;
					} );
			} );
	}

	/**
	 * Returns tasks order.
	 *
	 * @private
	 * @param {Number} listId
	 * @returns {Promise.<Array.<Number>>}
	 */
	_getTasksOrder( listId ) {
		return HttpHelper.get( `/api/v1/task_positions?list_id=${listId}` )
			.then( ( res ) => res[ 0 ].values );
	}
}

class HttpHelper {
	/**
	 * Sends request to Wunderlist API.
	 *
	 * @param {String} path
	 * @returns {Promise.<*>}
	 */
	static get( path ) {
		return new Promise( ( resolve, reject )=> {
			const options = Object.assign( {}, DEFAULT_HTTP_OPTIONS );
			options.path = path;

			https.get( options, ( res ) => {
				let body = '';

				res.on( 'data', ( chunk ) => {
					body += chunk;
				} );

				res.on( 'end', () => {
					const response = JSON.parse( body );

					if ( response[ 'invalid_request' ] ) {
						return reject( response );
					}

					resolve( response );
				} );

				res.on( 'error', ( err ) => reject( err ) );

				res.on( 'timeout', () => reject() );
			} );
		} );
	}
}

new WunderlistGeekTool().run();

/**
 * @typedef {Object} List
 * @property {Number} id
 * @property {Date} created_at
 * @property {String} title
 */

/**
 * @typedef {Object} ListWithTasks
 * @property {Number} id
 * @property {Date} created_at
 * @property {String} title
 * @property {Array.<Task>} tasks
 */

/**
 * @typedef {Object} Task
 * @property {Number} id
 * @property {Date} created_at
 * @property {Date} due_date
 * @property {String} title
 * @property {Boolean} starred
 */
<|endoftext|>


<commit_before>//On load, .contentBox should contain question #1

// When user enters Answer and hits submit, ask if
//answer matches stored Answer

// An array containing questions and answers
//
var questionBank = ["Q1","Q2","Q3","Q4","Q5","Q6","Q7","Q8","Q9","Q10"];
var answerBank = ["A1","A2","A3","A4","A5","A6","A7","A8","A9","A10"];

$(document).ready()

var submitButton = $("#submitInput");
var displayQuestion = $("#card");
var nextButton = $("#nextButton");

nextButton.on("click", function(){
  console.log("I was clicked!")
})

submitButton.on("click", function(){
  console.log("I was clicked!")
  var userInput = $("#answerInput").val()
  console.log(userInput)
  displayQuestion.html(questionBank[0])
});

questionBank.forEach(function(currentQuestion) {
  console.log(currentQuestion)
});

// //flipping card
//   $("#card").flip({
//     axis: 'x',
//     trigger: 'hover'
//   });
<commit_msg>Add Next Question Functionality<commit_after>//On load, .contentBox should contain question #1

// When user enters Answer and hits submit, ask if
//answer matches stored Answer

// An array containing questions and answers
//
var questionBank = ["Q1","Q2","Q3","Q4","Q5","Q6","Q7","Q8","Q9","Q10"];
var answerBank = ["A1","A2","A3","A4","A5","A6","A7","A8","A9","A10"];

$(document).ready()

var submitButton = $("#submitInput");
var displayQuestion = $("#card");
var nextButton = $("#nextButton");
// var currentQuestion = questionBank[0]

var currentIndex = -1;

nextButton.on("click", function(){
  displayQuestion.html(questionBank[currentIndex + 1]);
  currentIndex++;
  if(currentIndex === 9) {
    currentIndex = -1;
  }
});

submitButton.on("click", function(){

  var userInput = $("#answerInput").val()
  if (userInput === answerBank[0]) {
    displayQuestion.html(questionBank())
  }
});
//
// questionBank.forEach(function(currentQuestion) {
//   console.log(currentQuestion)
// });

// //flipping card
//   $("#card").flip({
//     axis: 'x',
//     trigger: 'hover'
//   });
<|endoftext|>


<commit_before>/**
 * Module Dependencies
 */
//=============================================================================
const
  twilio = require('twilio'),
  config = require('../config/config');
//=============================================================================
/**
 * Module variables
 */
//=============================================================================
const
  acctSID = config.twilio.liveAccountSid,
  authToken = config.twilio.liveAuthToken,
  sender = config.twilio.livePhoneNumber,
  client = new twilio.RestClient(acctSID, authToken);
//=============================================================================
/**
 * Export Module
 */
//=============================================================================
module.exports = function (p_num) {
  send_params = {
    'to': p_num, // Sender's phone number with country code
    'from': sender, // Receiver's phone Number with country code
    'body': "Hi, your research results have been sent to your email address." +
      "Thank you for using the Textpedia service."
};
  // Prints the complete response
  client.messages.create(send_params, function (err, resp) {
    if(err) {
      console.log('There was an error sending the message via Twilio');
      return console.error(err);
    }
    else {
      console.log('The response from Twilio');
      return console.log(resp);
    }
  });
};
//=============================================================================
<commit_msg>corrected typo in delivery msg<commit_after>/**
 * Module Dependencies
 */
//=============================================================================
const
  twilio = require('twilio'),
  config = require('../config/config');
//=============================================================================
/**
 * Module variables
 */
//=============================================================================
const
  acctSID = config.twilio.liveAccountSid,
  authToken = config.twilio.liveAuthToken,
  sender = config.twilio.livePhoneNumber,
  client = new twilio.RestClient(acctSID, authToken);
//=============================================================================
/**
 * Export Module
 */
//=============================================================================
module.exports = function (p_num) {
  send_params = {
    'to': p_num, // Sender's phone number with country code
    'from': sender, // Receiver's phone Number with country code
    'body': "Hi, your research results have been sent to your email address." +
      " Thank you for using the Textpedia service."
};
  // Prints the complete response
  client.messages.create(send_params, function (err, resp) {
    if(err) {
      console.log('There was an error sending the message via Twilio');
      return console.error(err);
    }
    else {
      console.log('The response from Twilio');
      return console.log(resp);
    }
  });
};
//=============================================================================
<|endoftext|>


<commit_before>// main
var playground = new Kursaal();
var generator = new RandomBrickGenerator({
	enableMoving: true
});

// 设置生成器要服务的娱乐场
generator.setKursaal(playground);

// 摆放位置
generator.moveTo((config.stage.canvas.width - playground.mapWidth) / 2, playground.mapHeight + 100 + config.size * 1.5);
playground.moveTo((config.stage.canvas.width - playground.mapWidth) / 2, 100);

// 启动游戏
generator.start();<commit_msg>[UPD]调整生成器位置<commit_after>// main
var playground = new Kursaal();
var generator = new RandomBrickGenerator({
	enableMoving: true
});

// 设置生成器要服务的娱乐场
generator.setKursaal(playground);

// 摆放位置
generator.moveTo((config.stage.canvas.width - playground.mapWidth) / 4, playground.mapHeight + 100 + config.size * 1.5);
playground.moveTo((config.stage.canvas.width - playground.mapWidth) / 2, 100);

// 启动游戏
generator.start();<|endoftext|>