<commit_before>/*
    Sudoku.js
    ---------

    A Sudoku puzzle generator and solver JavaScript library based on
    "Solving Every Sudoku Puzzle" by Peter Norvig[1].

    Puzzles are represented by a string of digits, 1-9, and '.' as spaces. Each
    character represents a square, e.g.,

        "52...6.........7.13...........4..8..6......5...........418.........3."+
        ".2...87....."

    Usage:
    TODO: Complete this.

        >>> sudoku.solve()
        >>> sudoku.generate()
        >>> sudoku.get_candidates()

    References:
        - Michael Anderson's Python implementation for Mac OS X[2]
        - "Sudoku" on Wikipedia[2]

    [1]: http://norvig.com/sudoku.html
    [2]: https://github.com/andermic/cousins/tree/master/sudoku
    [3]: http://en.wikipedia.org/wiki/Sudoku
*/

(function(win){

    // Create global reference to this entire library
    var sudoku = win.sudoku = {};

    // Lib globals
    var DIGITS = "123456789";       // Allowed digits
    var ROWS = "ABCDEFGHI";         // Row lables
    var COLS = DIGITS;              // Column lables
    var SQUARES = null;             // Square IDs

    var UNITS = null;               // All units (row, column, or box)
    var SQUARE_UNITS_MAP = null;     // Squares -> units map
    var SQUARE_PEERS_MAP = null;    // Squares -> peers map

    var BLANK_CHAR = '.';           // How to represent a blank square

    function initialize(){
        /* Initialize the Sudoku library (invoked after library load)
        */
        SQUARES             = sudoku._cross(ROWS, COLS);
        UNITS               = sudoku._get_all_units(ROWS, COLS);
        SQUARE_UNITS_MAP    = sudoku._get_square_units_map(SQUARES, UNITS);
        SQUARE_PEERS_MAP    = sudoku._get_square_peers_map(SQUARES, SQUARE_UNITS_MAP);
    }

    // Solve
    // -----

    sudoku.solve = function(board){
        /* Solve a sudoku puzzle given a sudoku `board`, i.e., a representation
        of the board with digits, 1-9, and spaces identified by '.'
        */
        var result = sudoku._search(sudoku.get_candidates(board));
        var solution = "";
        for(var square in result){
            solution += result[square];
        }
        return solution;
    };

    sudoku._search = function(candidates){
        /* Given a map of squares -> candiates, using depth-first search and
        constraint propigation, recursively try all possible values until a
        solution is found, or false if no solution exists.
        */

        // Return if error in previous iteration
        if(!candidates){
            //console.log("Search: Error encountered in previous iteration. Returning false.")
            return false;
        }

        //console.log("Search: Searching", JSON.stringify(candidates));

        // If only one candidate for every square, we've a solved puzzle!
        // Return the candidates map.
        var max_nr_candidates = 0;
        var max_candidates_square = null;
        for(var si in SQUARES){
            var square = SQUARES[si];

            var nr_candidates = candidates[square].length;

            if(nr_candidates > max_nr_candidates){
                max_nr_candidates = nr_candidates;
                max_candidates_square = square;
            }
        }
        //console.log("Search: Most candidates: ", max_candidates_square, candidates[max_candidates_square], " (", max_nr_candidates")");
        if(max_nr_candidates === 1){
            return candidates;
        }

        // Choose the blank square with the fewest possibilities > 1
        var min_nr_candidates = 10;
        var min_candidates_square = null;
        for(si in SQUARES){
            square = SQUARES[si];

            nr_candidates = candidates[square].length;

            if(nr_candidates < min_nr_candidates && nr_candidates > 1){
                min_nr_candidates = nr_candidates;
                min_candidates_square = square;
            }
        }
        //console.log("Search: Fewest candidates: ", min_candidates_square, ":",candidates[min_candidates_square], " (", min_nr_candidates, ")");

        // Recursively search for each of the candidates of the square with the
        // fewest candidates. Return false if
        var candidates_next = [];
        for(var vi in candidates[min_candidates_square]){
            var val = candidates[min_candidates_square][vi];

            var candidates_copy = JSON.parse(JSON.stringify(candidates));

            candidates_next.push(
                sudoku._search(
                    sudoku._assign(candidates_copy, min_candidates_square, val)
                )
            );
        }
        //console.log(candidates_next, sudoku._first_true(candidates_next));
        return sudoku._first_true(candidates_next);
    };

    sudoku._assign = function(candidates, square, val){
        /* Eliminate all values, *except* for `val`, from `candidates` at
        `square` (candidates[square]), and propagate. Return the candidates map
        when finished. If a contradiciton is found, return false.
        */

        //console.log("\tAssign: Assigning val", val, "to square", square);

        // Grab a list of canidates without 'val'
        var other_vals = candidates[square].replace(val, "");

        // Loop through all other values and eliminate them from the candidates
        // at the current square, and propigate. If at any point we get a
        // contradiction, return false.
        for(var ovi in other_vals){
            var other_val = other_vals[ovi];

            var candidates_next =
                sudoku._eliminate(candidates, square, other_val);

            if(!candidates_next){
                //console.log("Contradiction found by _eliminate.");
                return false;
            }
        }

        return candidates;
    };

    sudoku._eliminate = function(candidates, square, val){
        /* Eliminate `val` from `candidates` at `square`, (candidates[square]),
        and propagate when values or places <= 2. Return updated candidates,
        unless a contradiction is detected, in which case, return false.
        */

        // If `val` has already been eliminated from candidates[square], return
        // with candidates.
        if(!sudoku._in(val, candidates[square])){
            return candidates;
        }

        //console.log("\t\tEliminate: Eliminating val", val, "from square", square);

        // Remove `val` from candidates[square]
        candidates[square] = candidates[square].replace(val, '');

        // If the square has only candidate left, eliminate that value from its
        // peers
        var nr_candidates = candidates[square].length;
        if(nr_candidates === 1){
            var target_val = candidates[square];

            for(var pi in SQUARE_PEERS_MAP[square]){
                var peer = SQUARE_PEERS_MAP[square][pi];

                var candidates_new =
                        sudoku._eliminate(candidates, peer, target_val);

                if(!candidates_new){
                    //console.log("Contradiction found by _eliminate.");
                    return false;
                }
            }

        // Otherwise, if the square has no candidates, we have a contradiction.
        // Return false.
        } if(nr_candidates === 0){
            //console.log("Contradiction: Current square," + square + ", has no candidates.");
            return false;
        }

        // If a unit is reduced to only one place for a value, then assign it
        for(var ui in SQUARE_UNITS_MAP[square]){
            var unit = SQUARE_UNITS_MAP[square][ui];

            var val_places = [];
            for(var si in unit){
                var unit_square = unit[si];
                if(sudoku._in(val, candidates[unit_square])){
                    val_places.push(unit_square);
                }
            }

            // If there's no place for this value, we have a contradition!
            // return false
            if(val_places.length == 0){
                //console.log("Contradiction: There are no places for val, " + val + ", in unit, " + unit)
                return false;

            // Otherwise the value can only be in one place. Assign it there.
            } else if(val_places.length == 1){
                var candidates_new =
                    sudoku._assign(candidates, val_places[0], val);

                if(!candidates_new){
                    //console.log("Contradiction found by _assign")
                    return false
                }
            }
        }

        return candidates;
    };

    // Square relationships
    // --------------------
    // Squares, and their relationships with:
    //
    //      - Candidates    = Possible values for each square
    //      - Units         = A square's units, e.g., row, column, and box
    //      - Peers         = A set of peer squares in a square's units

    sudoku.get_candidates = function(board){
        /* Get all possible candidates for each square as a map in the form
        {square: digits}.

        `board` is a representation of the board with digits,
        1-9, and spaces identified by '.'.

        @throws errors if board is not 81 digits, or if those digits aren't 1-9
            or '.'

        @returns `false` if a contradiction is encountered
        */

        var candidate_map = {}
        var squares_values_map = sudoku._get_square_vals_map(board);

        // Make sure we have a valid board, otherwise throw an error
        if(board.length !== 81){
            throw "Invalid board size. Expecting an 81-square board."
        }
        for(var v_i in board){
            var val = board[v_i];
            if(!sudoku._in(val, DIGITS) && val !== BLANK_CHAR){
                throw "Invalid board character encountered: " + val;
            }
        }

        // Start by assigning every digit as a candidate to every square
        for(var si in SQUARES){
            candidate_map[SQUARES[si]] = DIGITS;
        }

        //console.log("Get candidates: Finding candidates for board ", board, ", current candidates map: ", candidate_map);

        // For each non-blank square, assign its value in the candidate map and
        // propigate.
        for(var square in squares_values_map){
            val = squares_values_map[square];

            if(sudoku._in(val, DIGITS)){
                //console.log("Get candidates: Working on square ", square, ", value ", val);

                var new_candidates = sudoku._assign(candidate_map, square, val)

                // Fail if we can't assign val to square
                if(!new_candidates){
                    return false;
                }
            }
        }

        return candidate_map;
    }

    sudoku._get_square_vals_map = function(board){
        /* Return a map of squares -> values with blanks (non-1-9 chars)
        represented as '.'.
        */
        var squares_vals_map = {};

        // Make sure `board` is a string of length 81
        if(board.length != SQUARES.length){
            throw "Board/squares length mismatch.";

        } else {
            for(var i in SQUARES){
                squares_vals_map[SQUARES[i]] = board[i];
            }
        }

        return squares_vals_map;
    }

    sudoku._get_square_units_map = function(squares, units){
        /* Return a map of `squares` and their associated units (row, col, box)
        */
        var square_unit_map = {};

        // For every square...
        for(var si in squares){
            var cur_square = squares[si];

            // Maintain a list of the current square's units
            var cur_square_units = [];

            // Look through the units, and see if the current square is in it,
            // and if so, add it to the list of of the square's units.
            for(var ui in units){
                var cur_unit = units[ui];

                if(cur_unit.indexOf(cur_square) !== -1){
                    cur_square_units.push(cur_unit);
                }
            }

            // Save the current square and its units to the map
            square_unit_map[cur_square] = cur_square_units;
        }

        return square_unit_map;
    }

    sudoku._get_square_peers_map = function(squares, units_map){
        /* Return a map of `squares` and their associated peers, i.e., a set of
        other squares in the square's unit.
        */
        var square_peers_map = {};

        // For every square...
        for(var si in squares){
            var cur_square = squares[si];
            var cur_square_units = units_map[cur_square];

            // Maintain list of the current square's peers
            var cur_square_peers = [];

            // Look through the current square's units map...
            for(var sui in cur_square_units){
                var cur_unit = cur_square_units[sui];

                for(var ui in cur_unit){
                    var cur_unit_square = cur_unit[ui];

                    if(cur_square_peers.indexOf(cur_unit_square) === -1 &&
                            cur_unit_square !== cur_square){
                        cur_square_peers.push(cur_unit_square);
                    }
                }
            }

            // Save the current square an its associated peers to the map
            square_peers_map[cur_square] = cur_square_peers;
        }

        return square_peers_map;
    }

    sudoku._get_all_units = function(rows, cols){
        /* Return a list of all units (rows, cols, boxes)
        */
        var units = [];

        // Rows
        for(var ri in rows){
            units.push(sudoku._cross(rows[ri], cols));
        }

        // Columns
        for(var ci in cols){
           units.push(sudoku._cross(rows, cols[ci]));
        }

        // Boxes
        var row_squares = ["ABC", "DEF", "GHI"];
        var col_squares = ["123", "456", "789"];
        for(var rsi in row_squares){
            for(var csi in col_squares){
                units.push(sudoku._cross(row_squares[rsi], col_squares[csi]));
            }
        }

        return units;
    }

    // Utility
    // -------

    sudoku._cross = function(a, b){
        /* Cross product of all elements in `a` and `b`, e.g.,
        sudoku._cross("abc", "123") ->
        ["a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3"]
        */
        var result = [];
        for(var ai in a){
            for(var bi in b){
                result.push(a[ai] + b[bi]);
            }
        }
        return result;
    };

    sudoku._in = function(v, seq){
        /* Return if a value `v` is in sequence `seq`.
        */
        return seq.indexOf(v) !== -1;
    }

    sudoku._first_true = function(seq){
        /* Return the first element in `seq` that is true. If no element is
        true, return false.
        */
        for(var i in seq){
            if(seq[i]){
                return seq[i];
            }
        }
        return false;
    }

    sudoku.display_board = function(board){
        /* Display a sudoku `board` to the console.
        */

        var HORIZ_SEPARATOR = '\n';
        var VERT_SEPARATOR  = "  ";
        var PADDING         = " ";

        var display_string = "";

        for(var r = 0; r < 9; ++r){
            for(var c = 0; c < 9; ++c){
                display_string += board[r][c] + PADDING;
                if(c % 3 === 2) display_string += VERT_SEPARATOR;
                if(c % 9 === 8) display_string += "\n";
            }
            if(r % 3 === 2) display_string += HORIZ_SEPARATOR;
        }

        //console.log(display_string);
    };

    // Initialize library after load
    initialize();

})(window);<commit_msg>Clean up code comments.<commit_after>/*
    Sudoku.js
    ---------

    A Sudoku puzzle generator and solver JavaScript library based on
    "Solving Every Sudoku Puzzle" by Peter Norvig[1].

    Puzzles are represented by a string of digits, 1-9, and '.' as spaces. Each
    character represents a square, e.g.,

        "52...6.........7.13...........4..8..6......5...........418.........3."+
        ".2...87....."

    Usage:
    TODO: Complete this.

        >>> sudoku.solve()
        >>> sudoku.generate()
        >>> sudoku.get_candidates()

    References:
        - Michael Anderson's Python implementation for Mac OS X[2]
        - "Sudoku" on Wikipedia[2]

    [1]: http://norvig.com/sudoku.html
    [2]: https://github.com/andermic/cousins/tree/master/sudoku
    [3]: http://en.wikipedia.org/wiki/Sudoku
*/

(function(root){
    var sudoku = root.sudoku = {};  // Global reference to the sudoku library

    var DIGITS = "123456789";       // Allowed digits
    var ROWS = "ABCDEFGHI";         // Row lables
    var COLS = DIGITS;              // Column lables
    var SQUARES = null;             // Square IDs

    var UNITS = null;               // All units (row, column, or box)
    var SQUARE_UNITS_MAP = null;    // Squares -> units map
    var SQUARE_PEERS_MAP = null;    // Squares -> peers map

    var BLANK_CHAR = '.';           // How to represent a blank square

    // Init
    // -------------------------------------------------------------------------
    function initialize(){
        /* Initialize the Sudoku library (invoked after library load)
        */
        SQUARES             = sudoku._cross(ROWS, COLS);
        UNITS               = sudoku._get_all_units(ROWS, COLS);
        SQUARE_UNITS_MAP    = sudoku._get_square_units_map(SQUARES, UNITS);
        SQUARE_PEERS_MAP    = sudoku._get_square_peers_map(SQUARES,
                                    SQUARE_UNITS_MAP);
    }

    // Solve
    // -------------------------------------------------------------------------
    sudoku.solve = function(board){
        /* Solve a sudoku puzzle given a sudoku `board`, i.e., an 81-character
        string of digits, 1-9, and spaces identified by '.', representing the
        squares.
        */
        var result = sudoku._search(sudoku.get_candidates(board));
        var solution = "";
        for(var square in result){
            solution += result[square];
        }
        return solution;
    };

    sudoku.get_candidates = function(board){
        /* Get all possible candidates for each square as a map in the form
        {square: digits}.

        @throws errors if board is not 81 digits, or if those digits aren't 1-9
            or '.'

        @returns `false` if a contradiction is encountered
        */

        var candidate_map = {}
        var squares_values_map = sudoku._get_square_vals_map(board);

        // Make sure we have a valid board, otherwise throw an error
        if(board.length !== 81){
            throw "Invalid board size. Expecting an 81-square board."
        }
        for(var v_i in board){
            var val = board[v_i];
            if(!sudoku._in(val, DIGITS) && val !== BLANK_CHAR){
                throw "Invalid board character encountered: " + val;
            }
        }

        // Start by assigning every digit as a candidate to every square
        for(var si in SQUARES){
            candidate_map[SQUARES[si]] = DIGITS;
        }

        // For each non-blank square, assign its value in the candidate map and
        // propigate.
        for(var square in squares_values_map){
            val = squares_values_map[square];

            if(sudoku._in(val, DIGITS)){
                var new_candidates = sudoku._assign(candidate_map, square, val)

                // Fail if we can't assign val to square
                if(!new_candidates){
                    return false;
                }
            }
        }

        return candidate_map;
    }

    sudoku._search = function(candidates){
        /* Given a map of squares -> candiates, using depth-first search,
        recursively try all possible values until a solution is found, or false
        if no solution exists.
        */

        // Return if error in previous iteration
        if(!candidates){
            return false;
        }

        // If only one candidate for every square, we've a solved puzzle!
        // Return the candidates map.
        var max_nr_candidates = 0;
        var max_candidates_square = null;
        for(var si in SQUARES){
            var square = SQUARES[si];

            var nr_candidates = candidates[square].length;

            if(nr_candidates > max_nr_candidates){
                max_nr_candidates = nr_candidates;
                max_candidates_square = square;
            }
        }
        if(max_nr_candidates === 1){
            return candidates;
        }

        // Choose the blank square with the fewest possibilities > 1
        var min_nr_candidates = 10;
        var min_candidates_square = null;
        for(si in SQUARES){
            square = SQUARES[si];

            nr_candidates = candidates[square].length;

            if(nr_candidates < min_nr_candidates && nr_candidates > 1){
                min_nr_candidates = nr_candidates;
                min_candidates_square = square;
            }
        }

        // Recursively search for each of the candidates of the square with the
        // fewest candidates. Return false if
        var candidates_next = [];
        for(var vi in candidates[min_candidates_square]){
            var val = candidates[min_candidates_square][vi];

            var candidates_copy = JSON.parse(JSON.stringify(candidates));

            candidates_next.push(
                sudoku._search(
                    sudoku._assign(candidates_copy, min_candidates_square, val)
                )
            );
        }
        return sudoku._first_true(candidates_next);
    };

    sudoku._assign = function(candidates, square, val){
        /* Eliminate all values, *except* for `val`, from `candidates` at
        `square` (candidates[square]), and propagate. Return the candidates map
        when finished. If a contradiciton is found, return false.

        WARNING: This will modify the contents of `candidates` directly.
        */

        // Grab a list of canidates without 'val'
        var other_vals = candidates[square].replace(val, "");

        // Loop through all other values and eliminate them from the candidates
        // at the current square, and propigate. If at any point we get a
        // contradiction, return false.
        for(var ovi in other_vals){
            var other_val = other_vals[ovi];

            var candidates_next =
                sudoku._eliminate(candidates, square, other_val);

            if(!candidates_next){
                //console.log("Contradiction found by _eliminate.");
                return false;
            }
        }

        return candidates;
    };

    sudoku._eliminate = function(candidates, square, val){
        /* Eliminate `val` from `candidates` at `square`, (candidates[square]),
        and propagate when values or places <= 2. Return updated candidates,
        unless a contradiction is detected, in which case, return false.

        WARNING: This will modify the contents of `candidates` directly.
        */

        // If `val` has already been eliminated from candidates[square], return
        // with candidates.
        if(!sudoku._in(val, candidates[square])){
            return candidates;
        }

        // Remove `val` from candidates[square]
        candidates[square] = candidates[square].replace(val, '');

        // If the square has only candidate left, eliminate that value from its
        // peers
        var nr_candidates = candidates[square].length;
        if(nr_candidates === 1){
            var target_val = candidates[square];

            for(var pi in SQUARE_PEERS_MAP[square]){
                var peer = SQUARE_PEERS_MAP[square][pi];

                var candidates_new =
                        sudoku._eliminate(candidates, peer, target_val);

                if(!candidates_new){
                    return false;
                }
            }

        // Otherwise, if the square has no candidates, we have a contradiction.
        // Return false.
        } if(nr_candidates === 0){
            return false;
        }

        // If a unit is reduced to only one place for a value, then assign it
        for(var ui in SQUARE_UNITS_MAP[square]){
            var unit = SQUARE_UNITS_MAP[square][ui];

            var val_places = [];
            for(var si in unit){
                var unit_square = unit[si];
                if(sudoku._in(val, candidates[unit_square])){
                    val_places.push(unit_square);
                }
            }

            // If there's no place for this value, we have a contradition!
            // return false
            if(val_places.length === 0){
                return false;

            // Otherwise the value can only be in one place. Assign it there.
            } else if(val_places.length === 1){
                candidates_new =
                    sudoku._assign(candidates, val_places[0], val);

                if(!candidates_new){
                    return false;
                }
            }
        }

        return candidates;
    };

    // Square relationships
    // -------------------------------------------------------------------------
    // Squares, and their relationships with values, units, and peers.

    sudoku._get_square_vals_map = function(board){
        /* Return a map of squares -> values
        */
        var squares_vals_map = {};

        // Make sure `board` is a string of length 81
        if(board.length != SQUARES.length){
            throw "Board/squares length mismatch.";

        } else {
            for(var i in SQUARES){
                squares_vals_map[SQUARES[i]] = board[i];
            }
        }

        return squares_vals_map;
    }

    sudoku._get_square_units_map = function(squares, units){
        /* Return a map of `squares` and their associated units (row, col, box)
        */
        var square_unit_map = {};

        // For every square...
        for(var si in squares){
            var cur_square = squares[si];

            // Maintain a list of the current square's units
            var cur_square_units = [];

            // Look through the units, and see if the current square is in it,
            // and if so, add it to the list of of the square's units.
            for(var ui in units){
                var cur_unit = units[ui];

                if(cur_unit.indexOf(cur_square) !== -1){
                    cur_square_units.push(cur_unit);
                }
            }

            // Save the current square and its units to the map
            square_unit_map[cur_square] = cur_square_units;
        }

        return square_unit_map;
    }

    sudoku._get_square_peers_map = function(squares, units_map){
        /* Return a map of `squares` and their associated peers, i.e., a set of
        other squares in the square's unit.
        */
        var square_peers_map = {};

        // For every square...
        for(var si in squares){
            var cur_square = squares[si];
            var cur_square_units = units_map[cur_square];

            // Maintain list of the current square's peers
            var cur_square_peers = [];

            // Look through the current square's units map...
            for(var sui in cur_square_units){
                var cur_unit = cur_square_units[sui];

                for(var ui in cur_unit){
                    var cur_unit_square = cur_unit[ui];

                    if(cur_square_peers.indexOf(cur_unit_square) === -1 &&
                            cur_unit_square !== cur_square){
                        cur_square_peers.push(cur_unit_square);
                    }
                }
            }

            // Save the current square an its associated peers to the map
            square_peers_map[cur_square] = cur_square_peers;
        }

        return square_peers_map;
    }

    sudoku._get_all_units = function(rows, cols){
        /* Return a list of all units (rows, cols, boxes)
        */
        var units = [];

        // Rows
        for(var ri in rows){
            units.push(sudoku._cross(rows[ri], cols));
        }

        // Columns
        for(var ci in cols){
           units.push(sudoku._cross(rows, cols[ci]));
        }

        // Boxes
        var row_squares = ["ABC", "DEF", "GHI"];
        var col_squares = ["123", "456", "789"];
        for(var rsi in row_squares){
            for(var csi in col_squares){
                units.push(sudoku._cross(row_squares[rsi], col_squares[csi]));
            }
        }

        return units;
    }

    // Utility
    // -------------------------------------------------------------------------

    sudoku._cross = function(a, b){
        /* Cross product of all elements in `a` and `b`, e.g.,
        sudoku._cross("abc", "123") ->
        ["a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3"]
        */
        var result = [];
        for(var ai in a){
            for(var bi in b){
                result.push(a[ai] + b[bi]);
            }
        }
        return result;
    };

    sudoku._in = function(v, seq){
        /* Return if a value `v` is in sequence `seq`.
        */
        return seq.indexOf(v) !== -1;
    }

    sudoku._first_true = function(seq){
        /* Return the first element in `seq` that is true. If no element is
        true, return false.
        */
        for(var i in seq){
            if(seq[i]){
                return seq[i];
            }
        }
        return false;
    }

    sudoku.display_board = function(board){
        /* Display a sudoku `board` to the console.
        */

        var HORIZ_SEPARATOR = '\n';
        var VERT_SEPARATOR  = "  ";
        var PADDING         = " ";

        var display_string = "";

        for(var r = 0; r < 9; ++r){
            for(var c = 0; c < 9; ++c){
                display_string += board[r][c] + PADDING;
                if(c % 3 === 2) display_string += VERT_SEPARATOR;
                if(c % 9 === 8) display_string += "\n";
            }
            if(r % 3 === 2) display_string += HORIZ_SEPARATOR;
        }

        //console.log(display_string);
    };

    // Initialize library after load
    initialize();

})(this);<|endoftext|>


<commit_before>var config = require('./config.json'),
  logger = require('./my_modules/logger.js'),
  Web = require('./my_modules/web.js'),
  DB = require('./my_modules/db.js'),
  BaseShowScraper = require('./my_modules/baseShowScraper.js'),
  EpisodeActorGrabber = require('./my_modules/episodeActorGrabber.js'),
  ActorCreditsGrabber = require('./my_modules/actorCreditsGrabber.js'),
  queries = require('./my_modules/queries.js'),
  fs = require('fs');

var day = 1000 * 60 * 60 * 24;
var numBaseShows = 0, doneBaseShows = 0;

var web = new Web(config);
web.startServer();

var cast = new EpisodeActorGrabber(config);
var credits = new ActorCreditsGrabber(config);

var queueAllActors = function() {
  var db = new DB(config);
  db.connect('queueUpAllActors', function(){
    db.query({ sql: 'Insert into ProcessActors(ActorID) select ActorID from Actors a where not exists (select 1 from ProcessActors pa where pa.ActorID = a.ActorID);' }, function() {
      credits.start();
      db.disconnect();
    });
  });
};

var scrapeBaseTitle = function(baseId) {
  var base = new BaseShowScraper(config, baseId);

  base.on('done',function(baseId) {
    doneBaseShows++;
    if (doneBaseShows === numBaseShows) {
      cast.setBaseShowsDone();
    }
  });

  base.start();
};

var startBaseTitles = function() {
  var db = new DB(config);
  db.connect('queueUpAllActors', function(){
    db.query({ sql: 'select * from BaseTitles;' }, function(dbRes) {
      numBaseShows = dbRes.length;
      doneBaseShows = 0;
      cast.start();
      credits.start();
      for (var i = 0; i < dbRes.length; i++) {
        scrapeBaseTitle(dbRes[i].BaseTitleID);
      }
      db.disconnect();
    });
  });
};

var fetchAllInitFiles = function(baseTitles) {
  var db = new DB(config);
  db.connect('fetchAllInitFiles', function(){
    var baseId = baseTitles[0].BaseTitleID;
    logger.log({
      caller: 'SVUViz',
      message: 'Fetching all info',
      params: baseId
    });
    web.allInfo(db, baseId, function(allInfo) {
      db.disconnect();
      var s = JSON.stringify(allInfo);
      var filename = process.cwd() + '/web/static/' + baseId + '.json';
      logger.log({
        caller: 'SVUViz',
        message: 'Writing to file',
        params: { filename: filename }
      });
      fs.writeFile(filename, s, function (err) {
        if (err) {
          console.log(err);
          return;
        }
        logger.log({
          caller: 'SVUViz',
          message: 'Done writing to file',
          params: { filename: filename }
        });
        if (baseTitles.length > 1) {
          process.nextTick(function(){
            fetchAllInitFiles(baseTitles.slice(1));
          });
          s = null;
        }
      });
    });
  });
};

cast.on('done', function() {
  credits.setIncomingActorsDone();
});

credits.on('done', function() {
  var db = new DB(config);
  db.connect('FinishProcessing', function(){
    db.query(queries.buildCommonTitles(), function() {
      db.query({ sql: 'select * from BaseTitles;' }, function(dbRes2) {
        db.disconnect();
        fetchAllInitFiles(dbRes2);
      });
    });
  });
});

startBaseTitles();

setTimeout(function() {
  scrapeBaseTitle(baseId);
}, day*7);

setInterval(queueAllActors, day*3);
<commit_msg>turn off credits after full actor sweep<commit_after>var config = require('./config.json'),
  logger = require('./my_modules/logger.js'),
  Web = require('./my_modules/web.js'),
  DB = require('./my_modules/db.js'),
  BaseShowScraper = require('./my_modules/baseShowScraper.js'),
  EpisodeActorGrabber = require('./my_modules/episodeActorGrabber.js'),
  ActorCreditsGrabber = require('./my_modules/actorCreditsGrabber.js'),
  queries = require('./my_modules/queries.js'),
  fs = require('fs');

var day = 1000 * 60 * 60 * 24;
var numBaseShows = 0, doneBaseShows = 0;

var web = new Web(config);
web.startServer();

var cast = new EpisodeActorGrabber(config);
var credits = new ActorCreditsGrabber(config);

var queueAllActors = function() {
  var db = new DB(config);
  db.connect('queueUpAllActors', function(){
    db.query({ sql: 'Insert into ProcessActors(ActorID) select ActorID from Actors a where not exists (select 1 from ProcessActors pa where pa.ActorID = a.ActorID);' }, function() {
      credits.start();
      db.disconnect();
      setTimeout(function() {
        credits.setIncomingActorsDone();
      },120000);
    });
  });
};

var scrapeBaseTitle = function(baseId) {
  var base = new BaseShowScraper(config, baseId);

  base.on('done',function(baseId) {
    doneBaseShows++;
    if (doneBaseShows === numBaseShows) {
      cast.setBaseShowsDone();
    }
  });

  base.start();
};

var startBaseTitles = function() {
  var db = new DB(config);
  db.connect('queueUpAllActors', function(){
    db.query({ sql: 'select * from BaseTitles;' }, function(dbRes) {
      numBaseShows = dbRes.length;
      doneBaseShows = 0;
      cast.start();
      credits.start();
      for (var i = 0; i < dbRes.length; i++) {
        scrapeBaseTitle(dbRes[i].BaseTitleID);
      }
      db.disconnect();
    });
  });
};

var fetchAllInitFiles = function(baseTitles) {
  var db = new DB(config);
  db.connect('fetchAllInitFiles', function(){
    var baseId = baseTitles[0].BaseTitleID;
    logger.log({
      caller: 'SVUViz',
      message: 'Fetching all info',
      params: baseId
    });
    web.allInfo(db, baseId, function(allInfo) {
      db.disconnect();
      var s = JSON.stringify(allInfo);
      var filename = process.cwd() + '/web/static/' + baseId + '.json';
      logger.log({
        caller: 'SVUViz',
        message: 'Writing to file',
        params: { filename: filename }
      });
      fs.writeFile(filename, s, function (err) {
        if (err) {
          console.log(err);
          return;
        }
        logger.log({
          caller: 'SVUViz',
          message: 'Done writing to file',
          params: { filename: filename }
        });
        if (baseTitles.length > 1) {
          process.nextTick(function(){
            fetchAllInitFiles(baseTitles.slice(1));
          });
          s = null;
        }
      });
    });
  });
};

cast.on('done', function() {
  credits.setIncomingActorsDone();
});

credits.on('done', function() {
  var db = new DB(config);
  db.connect('FinishProcessing', function(){
    db.query(queries.buildCommonTitles(), function() {
      db.query({ sql: 'select * from BaseTitles;' }, function(dbRes2) {
        db.disconnect();
        fetchAllInitFiles(dbRes2);
      });
    });
  });
});

startBaseTitles();

setTimeout(function() {
  scrapeBaseTitle(baseId);
}, day*7);

setInterval(queueAllActors, day*3);
<|endoftext|>


<commit_before>var fs = require("fs");
var easyimg = require('easyimage');

module.exports = function (imgDirectory) {
    // Path to source and destination
    var srcPath = './' + imgDirectory;
    var dstPath = srcPath + '/thumbnails';

    // If source directory does not exist, return false.
    if (!fs.existsSync(srcPath)) {
        return (false);
    }

    // If thumbnail-directory does not exist, create it.
    if (!fs.existsSync(dstPath)) {
        fs.mkdirSync(dstPath);
    }

    // Read source file names
    var imgFiles = fs.readdirSync(srcPath);

    // Go through every source file
    imgFiles.forEach (function (image) {
        var srcFile = srcPath + '/' + image;
        var dstFile = dstPath + '/' + image.replace(/\.jpg$/, '_thumb.jpg');

        /* For testing purposes
        console.log(srcFile);
        console.log(dstFile);
        */

        // If source is a file then create thumbnail
        var stat = fs.statSync(srcFile)
        if (stat && stat.isFile()) {
            easyimg.thumbnail({
                src: srcFile,
                dst: dstFile,
                width:100,
                height:100,
                x:0,
                y:0
            }).then(
              function(image) {
                 console.log('Thumbnail created: ' + image.name + ' ' + image.width + ' x ' + image.height);
              },
              function (err) {
                console.log("Can't create thumbnail!");
              }
            );
        }
    });
    return (true);
};<commit_msg>Images directory may be anywhere.<commit_after>var fs = require("fs");
var easyimg = require('easyimage');

module.exports = function (imgDirectory) {
    // Path to source and destination
    var srcPath = imgDirectory;
    // Just in case
    if(srcPath.indexOf('/') == -1) {
        srcPath = './' + srcPath;
    }
    var dstPath = srcPath + '/thumbnails';

    // If source directory does not exist, return false.
    if (!fs.existsSync(srcPath)) {
        return (false);
    }

    // If thumbnail-directory does not exist, create it.
    if (!fs.existsSync(dstPath)) {
        fs.mkdirSync(dstPath);
    }

    // Read source file names
    var imgFiles = fs.readdirSync(srcPath);

    // Go through every source file
    imgFiles.forEach (function (image) {
        var srcFile = srcPath + '/' + image;
        var dstFile = dstPath + '/' + image.replace(/\.jpg$/, '_thumb.jpg');

        // If source is a file then create thumbnail
        var stat = fs.statSync(srcFile)
        if (stat && stat.isFile() && ((srcFile.indexOf('.jpg') > -1) || (srcFile.indexOf('.png') > -1))) {
            easyimg.thumbnail({
                src: srcFile,
                dst: dstFile,
                width:100,
                height:100,
                x:0,
                y:0
            }).then(
              function(image) {
                 console.log('Thumbnail created: ' + image.name + ' ' + image.width + ' x ' + image.height);
              },
              function (err) {
                console.log("Can't create thumbnail! ");
              }
            );
        }
    });
    return (true);
};<|endoftext|>


<commit_before>var Discord = require('discord.io');
var request = require('request');

// Define the bot instance
var bot = new Discord.Client({
    autorun: true,
    token: ""
});

// Reconnect the bot if they somehow get disconnected
bot.on('disconnect', function(errMsg, code) {
  bot.connect()
});

// Make sure the emojis are fresh from the repo
function getEmojiFonts(){
  request('https://github.com/haykam821/Discord-Font-Service/raw/master/index.json', function (error, response, body) {
    if (!error && response.statusCode == 200) {
       importedJSON = JSON.parse(body);
       fonts = importedJSON['fonts'];
       config = importedJSON['config'];
    }
  })
};

setInterval(getEmojiFonts,3000);

// Define fonts in case it hasn't loaded yet
var fonts = {};

// Define a function to convert from text to letter emoji
function parseToEmoji(cmd, message) {
  try {
    array = message.toLowerCase().replace(cmd + ' ', '').split(' ');
    font = fonts[message.replace('font:', '').split(' ')[message.split(' ').length - 1]] == undefined ? fonts['default'] : fonts[message.replace('font:', '').split(' ')[message.split(' ').length - 1]]
    // Font setup
    if (array[array.length - 1].startsWith('font:')) {
        array.pop();
    } else {
        font = fonts['default'];
    };
    // Fix array again
    array = array.join(' ').split('');
    // Convert to emoji!
    for (var i = 0; i < array.length; i++) {
        console.log(font['emojis'][array[i]])
        array[i] = font['emojis'][array[i]] == undefined ? array[i] : font['emojis'][array[i]]
    }
    return {
      font: font == fonts['default'] ? `Default (${fonts.default['font_name']})` : font['font_name'],
      text: array.join(''),
      color: parseInt(font['color'])
    }
  } catch (err) {
    return {
      font: 'None',
      text: `Fail. ${err}`,
      color: 0xFF1100
    }
  }
}

// Define a function that allows checking commands easily
function cmd(message, cmdname) {
  return message.toLowerCase().startsWith(cmdname);
}

// Message handling
bot.on('message', function(user, userID, channelID, message, event) {
  try {
    if (userID == bot.id) {
        // Respond to commands using parse to emoji function
        if (message.toLowerCase().startsWith('>fontify ')) {
            var result = parseToEmoji('>fontify',message);
            bot1.editMessage({
                channelID: channelID,
                messageID: event.d.id,
                message: message,
                embed: {color:result.color,description:result.text,footer:{text:`Font: ${result.font}`}},
            });
        }
        // Respond to commands using parse to emoji function, but output as raw
        if (message.toLowerCase().startsWith('>codeify')) {
            var result = parseToEmoji('>codeify',message);
            bot1.editMessage({
                channelID: channelID,
                messageID: event.d.id,
                message: message,
                embed: {color:result.color,description:`\`\`\`\n${result.text}\`\`\``,footer:{text:`Font: ${result.font}`}},
            });
        }
    }
  } catch (err) {
    console.log('Error: ' + err);
  }
});
<commit_msg>Use the fallback color if the font color is unavailable!<commit_after>var Discord = require('discord.io');
var request = require('request');

// Define the bot instance
var bot = new Discord.Client({
    autorun: true,
    token: ""
});

// Reconnect the bot if they somehow get disconnected
bot.on('disconnect', function(errMsg, code) {
  bot.connect()
});

// Make sure the emojis are fresh from the repo
function getEmojiFonts(){
  request('https://github.com/haykam821/Discord-Font-Service/raw/master/index.json', function (error, response, body) {
    if (!error && response.statusCode == 200) {
       importedJSON = JSON.parse(body);
       fonts = importedJSON['fonts'];
       config = importedJSON['config'];
    }
  })
};

setInterval(getEmojiFonts,3000);

// Define fonts in case it hasn't loaded yet
var fonts = {};

// Define a function to convert from text to letter emoji
function parseToEmoji(cmd, message) {
  try {
    array = message.toLowerCase().replace(cmd + ' ', '').split(' ');
    font = fonts[message.replace('font:', '').split(' ')[message.split(' ').length - 1]] == undefined ? fonts['default'] : fonts[message.replace('font:', '').split(' ')[message.split(' ').length - 1]]
    // Font setup
    if (array[array.length - 1].startsWith('font:')) {
        array.pop();
    } else {
        font = fonts['default'];
    };
    // Fix array again
    array = array.join(' ').split('');
    // Convert to emoji!
    for (var i = 0; i < array.length; i++) {
        console.log(font['emojis'][array[i]])
        array[i] = font['emojis'][array[i]] == undefined ? array[i] : font['emojis'][array[i]]
    }
    return {
      font: font == fonts['default'] ? `Default (${fonts.default['font_name']})` : font['font_name'],
      text: array.join(''),
      color: parseInt(font['color']) == undefined ? config['fallback_color'] : parseInt(font['color'])
    }
  } catch (err) {
    return {
      font: 'None',
      text: `Fail. ${err}`,
      color: 0xFF1100
    }
  }
}

// Define a function that allows checking commands easily
function cmd(message, cmdname) {
  return message.toLowerCase().startsWith(cmdname);
}

// Message handling
bot.on('message', function(user, userID, channelID, message, event) {
  try {
    if (userID == bot.id) {
        // Respond to commands using parse to emoji function
        if (message.toLowerCase().startsWith('>fontify ')) {
            var result = parseToEmoji('>fontify',message);
            bot1.editMessage({
                channelID: channelID,
                messageID: event.d.id,
                message: message,
                embed: {color:result.color,description:result.text,footer:{text:`Font: ${result.font}`}},
            });
        }
        // Respond to commands using parse to emoji function, but output as raw
        if (message.toLowerCase().startsWith('>codeify')) {
            var result = parseToEmoji('>codeify',message);
            bot1.editMessage({
                channelID: channelID,
                messageID: event.d.id,
                message: message,
                embed: {color:result.color,description:`\`\`\`\n${result.text}\`\`\``,footer:{text:`Font: ${result.font}`}},
            });
        }
    }
  } catch (err) {
    console.log('Error: ' + err);
  }
});
<|endoftext|>


<commit_before>var net = require('net');
var util = require('util');

function FtpServer(options) {
    var self = this;

    if (!(this instanceof FtpServer)) {
        return new FtpServer(options);
    }

    this.myHost = options.host || '127.0.0.1';
    this.server = net.createServer();
    this.getHostFromUsername = options.getHostFromUsername || function(username) { return null; };
    this.logLevel = options.logLevel || 0;

    function log(level, message, isError) {
        if (self.logLevel < level)
            return;

        var now = new Date();
        var dateStr = now.getFullYear() + "-" + (1 + now.getMonth()) + "-" + now.getDate() + " " +
                      now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();
        console.log(dateStr + " " + message);

        if (isError)
            console.trace("Trace follows");
    };

    this.server.on("error", function (err) {
        log(0, "Server error: " + err);
    });
    this.server.on("listening", function() {
        log(0, "FTP multiplexer up and ready for connections.");
    });
    this.server.on("connection", function(clientSocket) {
        var conn = {
            clientSocket: clientSocket,
            serverSocket: null,
            serverGreetingRecieved: false,
            log: function(level, message, isError) {
                log(level, clientSocket.remoteAddress + ': ' + message, isError);
            },
            destination: null
        }

        clientSocket.setEncoding("ascii");
        clientSocket.setNoDelay();

        conn.log(1, "Client connected.");
        clientSocket.write("220 FTP multiplexer ready\r\n");

        clientSocket.on("end", function() {
            conn.log(1, "Client disconnected.");
        });
        clientSocket.on("error", function(err) {
            conn.log(0, "Client connection error: " + err);
            clientSocket.destroy();
        });
        clientSocket.on("data", handleClientData);

        function parseFTPCommand(data) {
            var m = (data + '').match(/\s*(\S*)(\s+(.*\S))?\s*/);
            if (!m) {
                return {cmd: '', arg: ''};
            } else {
                return {cmd: m[1], arg: m[3]};
            }
        }

        function parseServerResponse(data) {
            var m = (data + '').match(/\s*(\d{1,3})([\s-]+(.*\S))?\s*/);
            if (!m) {
                return {cmd: '', arg: ''};
            } else {
                return {cmd: m[1], arg: m[3]};
            }
        }

        function forwardPassiveConnection(host, port, callback) {
            conn.log(0, "Establishing forward for passive connection (" + host + ":" + port + ")");

            var listenPort = null;
            var serverConnected = false;
            var clientConnected = false;

            var psvListener = net.createServer(function(lsocket) {
                if (clientConnected) {
                    lsocket.end();
                } else {
                    conn.log(4, "Client connected to forwarder.");
                    clientConnected = true;
                    psvListener.close();

                    lsocket.on('error', function(err) {
                        conn.log(0, "Passive forwarding error: " + err, conn);
                        lsocket.destroy();
                    });

                    lsocket.pipe(serverConn);
                    serverConn.pipe(lsocket);
                }
            });
            psvListener.listen(0, function() {
                conn.log(4, "Listening for client.");
                listenPort = psvListener.address().port;
                tryNotifyingClient();
            });
            psvListener.on('error', function(err) {
                conn.log(0, "Passive listener error: " + err, conn);
                psvListener.destroy();
            });
            var serverConn = net.createConnection(port, host, function() {
                conn.log(4, "Connected to server.");
                serverConnected = true;
                tryNotifyingClient();
            });
            serverConn.on('error', function(err) {
                conn.log(0, "Passive forwarding error: " + err, conn);
                serverConn.destroy();
            });

            function tryNotifyingClient() {
                if (listenPort === null || !serverConnected)
                    return;
                conn.log(4, "Forwarder established, notifying client.");
                callback(self.myHost, listenPort);
            }
        }

        function handleClientData(data) {
            // Don't want to include passwords in logs.
            conn.log(2, "Client command:  " + (data + '').trim().toString('utf-8').replace(/^PASS\s+.*/, 'PASS ***'));

            if (conn.serverSocket !== null) {
                conn.serverSocket.write(data);
                return;
            }

            var command = parseFTPCommand(data);

            if (command.cmd !== "USER") {
                clientSocket.write("202 Not supported\r\n");
                return;
            }

            conn.destination = self.getHostFromUsername(command.arg);
            if (conn.destination === null) {
                clientSocket.write("530 Invalid username\r\n");
                clientSocket.close();
                return;
            }

            conn.serverSocket = net.createConnection(conn.destination.port, conn.destination.hostname);
            conn.serverSocket.setEncoding('ascii');
            conn.serverSocket.setNoDelay();
            conn.serverSocket.on('connect', function() {
                conn.serverSocket.write(data);
            });
            conn.serverSocket.on('data', function(data) {
                data.split('\r\n').forEach(function(data) {
                    if ((data + '').trim()) {
                        handleServerResponse(data + '\r\n');
                    }
                });
            });
            conn.serverSocket.on('end', function() {
                clientSocket.end();
            });
            conn.serverSocket.on('error', function(err) {
                conn.log(0, "Error from server connection: " + err);
                clientSocket.end();
            });
        }

        function handleServerResponse(data) {
            conn.log(2, "Server response: " + (data + '').trim().toString('utf-8'));

            var command = parseServerResponse(data);

            if (!conn.serverGreetingRecieved) {
               if (command.cmd === "220") {
                    /* suppress "welcome"-message, wait for the answer to
                    * the USER-command */
                    conn.log(4, "Response suppressed.");
                    return;
               } else {
                   conn.serverGreetingRecieved = true;
               }
            } else if (command.cmd === "227") {
                /* intercept passive mode */
                conn.log(3, "Trying to intercept passive mode.");
                var m = command.arg.match(/.*\((\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3})\).*/);
                if (m) {
                    var hostname = m[1] + '.' + m[2] + '.' + m[3] + '.' + m[4];
                    var port = parseInt(m[5]) * 256 + parseInt(m[6]);
                    forwardPassiveConnection(hostname, port, function(localHost, localPort) {
                        var i1 = parseInt(localPort / 256);
                        var i2 = parseInt(localPort % 256);
                        conn.log(0, "227 Entering Passive Mode (" + localHost.split(".").join(",") + "," + i1 + "," + i2 + ")");
                        clientSocket.write("227 Entering Passive Mode (" + localHost.split(".").join(",") + "," + i1 + "," + i2 + ")\r\n");
                    });
                    return;
                } else {
                    conn.log(1, "Unable to parse PASV address.");
                }
            } else if (command.cmd === "229") {
                conn.log(3, "Trying to intercept extended passive mode.");
                var m = command.arg.match(/.*\(\|\|\|(\d{1,5})\|\).*/);
                if (m) {
                    forwardPassiveConnection(conn.destination.hostname, port, function(localHost, localPort) {
                        conn.log(0, "229 Entering Passive Mode (|||" + localPort + "|)");
                        clientSocket.write("229 Entering Passive Mode (|||" + localPort + "|)\r\n");
                    });
                    return;
                } else {
                    conn.log(1, "Unable to parse EPASV address.");
                }
            }

            clientSocket.write(data);
        }
    });

    this.server.on("close", function() {
        log(0, "Server closed");
    });
}

["listen", "close"].forEach(function (fname) {
    FtpServer.prototype[fname] = function () {
        return this.server[fname].apply(this.server, arguments);
    }
});

exports.FtpServer = FtpServer;
<commit_msg>Make EPSV working<commit_after>var net = require('net');
var util = require('util');

function FtpServer(options) {
    var self = this;

    if (!(this instanceof FtpServer)) {
        return new FtpServer(options);
    }

    this.myHost = options.host || '127.0.0.1';
    this.server = net.createServer();
    this.getHostFromUsername = options.getHostFromUsername || function(username) { return null; };
    this.logLevel = options.logLevel || 0;

    function log(level, message, isError) {
        if (self.logLevel < level)
            return;

        var now = new Date();
        var dateStr = now.getFullYear() + "-" + (1 + now.getMonth()) + "-" + now.getDate() + " " +
                      now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();
        console.log(dateStr + " " + message);

        if (isError)
            console.trace("Trace follows");
    };

    this.server.on("error", function (err) {
        log(0, "Server error: " + err);
    });
    this.server.on("listening", function() {
        log(0, "FTP multiplexer up and ready for connections.");
    });
    this.server.on("connection", function(clientSocket) {
        var conn = {
            clientSocket: clientSocket,
            serverSocket: null,
            serverGreetingRecieved: false,
            log: function(level, message, isError) {
                log(level, clientSocket.remoteAddress + ': ' + message, isError);
            },
            destination: null
        }

        clientSocket.setEncoding("ascii");
        clientSocket.setNoDelay();

        conn.log(1, "Client connected.");
        clientSocket.write("220 FTP multiplexer ready\r\n");

        clientSocket.on("end", function() {
            conn.log(1, "Client disconnected.");
        });
        clientSocket.on("error", function(err) {
            conn.log(0, "Client connection error: " + err);
            clientSocket.destroy();
        });
        clientSocket.on("data", handleClientData);

        function parseFTPCommand(data) {
            var m = (data + '').match(/\s*(\S*)(\s+(.*\S))?\s*/);
            if (!m) {
                return {cmd: '', arg: ''};
            } else {
                return {cmd: m[1], arg: m[3]};
            }
        }

        function parseServerResponse(data) {
            var m = (data + '').match(/\s*(\d{1,3})([\s-]+(.*\S))?\s*/);
            if (!m) {
                return {cmd: '', arg: ''};
            } else {
                return {cmd: m[1], arg: m[3]};
            }
        }

        function forwardPassiveConnection(host, port, callback) {
            conn.log(0, "Establishing forward for passive connection (" + host + ":" + port + ")");

            var listenPort = null;
            var serverConnected = false;
            var clientConnected = false;

            var psvListener = net.createServer(function(lsocket) {
                if (clientConnected) {
                    lsocket.end();
                } else {
                    conn.log(4, "Client connected to forwarder.");
                    clientConnected = true;
                    psvListener.close();

                    lsocket.on('error', function(err) {
                        conn.log(0, "Passive forwarding error: " + err, conn);
                        lsocket.destroy();
                    });

                    lsocket.pipe(serverConn);
                    serverConn.pipe(lsocket);
                }
            });
            psvListener.listen(0, function() {
                conn.log(4, "Listening for client.");
                listenPort = psvListener.address().port;
                tryNotifyingClient();
            });
            psvListener.on('error', function(err) {
                conn.log(0, "Passive listener error: " + err, conn);
                psvListener.destroy();
            });
            var serverConn = net.createConnection(port, host, function() {
                conn.log(4, "Connected to server.");
                serverConnected = true;
                tryNotifyingClient();
            });
            serverConn.on('error', function(err) {
                conn.log(0, "Passive forwarding error: " + err, conn);
                serverConn.destroy();
            });

            function tryNotifyingClient() {
                if (listenPort === null || !serverConnected)
                    return;
                conn.log(4, "Forwarder established, notifying client.");
                callback(self.myHost, listenPort);
            }
        }

        function handleClientData(data) {
            // Don't want to include passwords in logs.
            conn.log(2, "Client command:  " + (data + '').trim().toString('utf-8').replace(/^PASS\s+.*/, 'PASS ***'));

            if (conn.serverSocket !== null) {
                conn.serverSocket.write(data);
                return;
            }

            var command = parseFTPCommand(data);

            if (command.cmd !== "USER") {
                clientSocket.write("202 Not supported\r\n");
                return;
            }

            conn.destination = self.getHostFromUsername(command.arg);
            if (conn.destination === null) {
                clientSocket.write("530 Invalid username\r\n");
                clientSocket.close();
                return;
            }

            conn.serverSocket = net.createConnection(conn.destination.port, conn.destination.hostname);
            conn.serverSocket.setEncoding('ascii');
            conn.serverSocket.setNoDelay();
            conn.serverSocket.on('connect', function() {
                conn.serverSocket.write(data);
            });
            conn.serverSocket.on('data', function(data) {
                data.split('\r\n').forEach(function(data) {
                    if ((data + '').trim()) {
                        handleServerResponse(data + '\r\n');
                    }
                });
            });
            conn.serverSocket.on('end', function() {
                clientSocket.end();
            });
            conn.serverSocket.on('error', function(err) {
                conn.log(0, "Error from server connection: " + err);
                clientSocket.end();
            });
        }

        function handleServerResponse(data) {
            conn.log(2, "Server response: " + (data + '').trim().toString('utf-8'));

            var command = parseServerResponse(data);

            if (!conn.serverGreetingRecieved) {
               if (command.cmd === "220") {
                    /* suppress "welcome"-message, wait for the answer to
                    * the USER-command */
                    conn.log(4, "Response suppressed.");
                    return;
               } else {
                   conn.serverGreetingRecieved = true;
               }
            } else if (command.cmd === "227") {
                /* intercept passive mode */
                conn.log(3, "Trying to intercept passive mode.");
                var m = command.arg.match(/.*\((\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3})\).*/);
                if (m) {
                    var hostname = m[1] + '.' + m[2] + '.' + m[3] + '.' + m[4];
                    var port = parseInt(m[5]) * 256 + parseInt(m[6]);
                    forwardPassiveConnection(hostname, port, function(localHost, localPort) {
                        var i1 = parseInt(localPort / 256);
                        var i2 = parseInt(localPort % 256);
                        conn.log(0, "227 Entering Passive Mode (" + localHost.split(".").join(",") + "," + i1 + "," + i2 + ")");
                        clientSocket.write("227 Entering Passive Mode (" + localHost.split(".").join(",") + "," + i1 + "," + i2 + ")\r\n");
                    });
                    return;
                } else {
                    conn.log(1, "Unable to parse PASV address.");
                }
            } else if (command.cmd === "229") {
                conn.log(3, "Trying to intercept extended passive mode.");
                var m = command.arg.match(/.*\(\|\|\|(\d{1,5})\|\).*/);
                if (m) {
                    var port = parseInt(m[1]);
                    forwardPassiveConnection(conn.destination.hostname, port, function(localHost, localPort) {
                        conn.log(0, "229 Entering Passive Mode (|||" + localPort + "|)");
                        clientSocket.write("229 Entering Passive Mode (|||" + localPort + "|)\r\n");
                    });
                    return;
                } else {
                    conn.log(1, "Unable to parse EPASV address.");
                }
            }

            clientSocket.write(data);
        }
    });

    this.server.on("close", function() {
        log(0, "Server closed");
    });
}

["listen", "close"].forEach(function (fname) {
    FtpServer.prototype[fname] = function () {
        return this.server[fname].apply(this.server, arguments);
    }
});

exports.FtpServer = FtpServer;
<|endoftext|>


<commit_before>(function()
{
    "use strict";

    var math = require('mathjs');
    var fs = require('fs');

    var PNG = require('node-png').PNG;

    var fp = require('lodash-fp');
    fp.mixin(require('./plus-fp/plus-fp'));

    var Q = require('q');

    var Twitter_update_with_media = require('./twitter_update_with_media');

    //----------- fractal functions
    var ff = {};

    // convert to -1 .. 1
    ff.normalize = fp.curry(function(range, x)
    {
        return x / range * 2 - 1;
    });

    ff.escapeCount = fp.curry(function(f, x, y)
    {
        var count = 0;

        // start z at zero
        var z = math.complex(0, 0);

        // vary c by x & y
        var c = math.complex(x, y);

        var maxCount = f.maxCount;
        var limit = f.limit;

        // count how long the iteration takes to break the limit

        while (count < maxCount - 1)
        {
            z = math.chain(z)
                .pow(2)
                .add(c)
                .done();

            if (math.norm(z) > limit)
            {
                break;
            }

            count++;
        }

        return count;
    });

    // ---------- make a functal

    ff.make = fp.curry(function(options)
    {
        var deferred = Q.defer();

        var f = {};

        f.width = options.width();
        f.height = options.height();
        f.maxCount = options.maxCount();
        f.limit = options.limit();

        var data = [];

        var startTime = (new Date()).getTime();

        fp.range(0, f.width).forEach(function(x)
        {
            data[x] = [];

            var fx = ff.normalize(f.width, x);

            fp.range(0, f.height).forEach(function(y)
            {
                var fy = ff.normalize(f.height, y);

                var count = ff.escapeCount(f, fx, fy);

                data[x][y] = count;
            });
        });

        f.time = ((new Date()).getTime() - startTime) / 1000;

        ff.png(options.file(), f, data).then(function()
        {
            deferred.resolve(f);
        });

        return deferred.promise;
    });

    // ------------ output to a png image

    ff.png = fp.curry(function(filename, functal, data)
    {
        var deferred = Q.defer();

        var image = new PNG(
        {
            width: functal.width,
            height: functal.height,
            filterType: -1
        });

        for (var y = 0; y < image.height; y++)
        {
            for (var x = 0; x < image.width; x++)
            {
                var idx = (image.width * y + x) << 2;

                var i = data[x][y];

                // grayscale

                image.data[idx] = i;
                image.data[idx + 1] = i;
                image.data[idx + 2] = i;
                image.data[idx + 3] = 0xff;
            }
        }

        image.pack().pipe(fs.createWriteStream(filename)).on('close', function()
        {
            deferred.resolve();
        });

        return deferred.promise;

    });

    // ------------ init a functal

    var options = {
        width: function()
        {
            return 100;
        },
        height: function()
        {
            return 100;
        },
        maxCount: function()
        {
            return 256;
        },
        limit: function()
        {
            return 2;
        },
        file: function()
        {
            return 'functals/f000001.png';
        }
    };

    ff.make(options).then(function(functal)
    {
        console.log(functal.time + ' secs');

        if (process.env.consumer_key)
        {
            var tuwm = new Twitter_update_with_media(
            {
                consumer_key: process.env.consumer_key,
                consumer_secret: process.env.consumer_secret,
                token: process.env.token,
                token_secret: process.env.token_secret
            });

            tuwm.post('First functal', 'functals/f000001.png', function(err, response)
            {
                if (err)
                {
                    console.log('error', err);
                }

                console.log(JSON.parse(response.body).text);
            });
        }
    });

}());
<commit_msg>resolve if no file<commit_after>(function()
{
    "use strict";

    var math = require('mathjs');
    var fs = require('fs');

    var PNG = require('node-png').PNG;

    var fp = require('lodash-fp');
    fp.mixin(require('./plus-fp/plus-fp'));

    var Q = require('q');

    var Twitter = require('./twitter_update_with_media');

    //----------- fractal functions
    var ff = {};

    // convert to -1 .. 1
    ff.normalize = fp.curry(function(range, x)
    {
        return x / range * 2 - 1;
    });

    ff.escapeCount = fp.curry(function(f, x, y)
    {
        var count = 0;

        // start z at zero
        var z = math.complex(0, 0);

        // vary c by x & y
        var c = math.complex(x, y);

        var maxCount = f.maxCount;
        var limit = f.limit;

        // count how long the iteration takes to break the limit

        while (count < maxCount - 1)
        {
            z = math.chain(z)
                .pow(2)
                .add(c)
                .done();

            if (math.norm(z) > limit)
            {
                break;
            }

            count++;
        }

        return count;
    });

    // ---------- make a functal

    ff.make = fp.curry(function(options)
    {
        var deferred = Q.defer();

        var f = {};

        f.width = options.width();
        f.height = options.height();
        f.maxCount = options.maxCount();
        f.limit = options.limit();

        var data = [];

        var startTime = (new Date()).getTime();

        fp.range(0, f.width).forEach(function(x)
        {
            data[x] = [];

            var fx = ff.normalize(f.width, x);

            fp.range(0, f.height).forEach(function(y)
            {
                var fy = ff.normalize(f.height, y);

                var count = ff.escapeCount(f, fx, fy);

                data[x][y] = count;
            });
        });

        f.time = ((new Date()).getTime() - startTime) / 1000;

        if (options.file())
        {
            f.file = options.file();

            ff.png(f, data).then(function()
            {
                deferred.resolve(f);
            });
        }
        else
        {
            deferred.resolve(f);
        }

        return deferred.promise;
    });

    // ------------ output to a png image

    ff.png = fp.curry(function(functal, data)
    {
        var deferred = Q.defer();

        var image = new PNG(
        {
            width: functal.width,
            height: functal.height,
            filterType: -1
        });

        for (var y = 0; y < image.height; y++)
        {
            for (var x = 0; x < image.width; x++)
            {
                var idx = (image.width * y + x) << 2;

                var i = data[x][y];

                // grayscale

                image.data[idx] = i;
                image.data[idx + 1] = i;
                image.data[idx + 2] = i;
                image.data[idx + 3] = 0xff;
            }
        }

        image.pack().pipe(fs.createWriteStream(functal.file)).on('close', function()
        {
            deferred.resolve();
        });

        return deferred.promise;

    });

    // ------------ init a functal

    var options = {
        width: function()
        {
            return 100;
        },
        height: function()
        {
            return 100;
        },
        maxCount: function()
        {
            return 256;
        },
        limit: function()
        {
            return 2;
        },
        file: function()
        {
            return 'functals/f000001.png';
        }
    };

    ff.make(options).then(function(functal)
    {
        console.log(functal.time + ' secs');

        if (functal.file && process.env.consumer_key)
        {
            var twit = new Twitter(
            {
                consumer_key: process.env.consumer_key,
                consumer_secret: process.env.consumer_secret,
                token: process.env.token,
                token_secret: process.env.token_secret
            });

            twit.post('First functal', functal.file, function(err, response)
            {
                if (err)
                {
                    console.log('error', err);
                }

                console.log(JSON.parse(response.body).text);
            });
        }
    });
}());
<|endoftext|>


<commit_before>/* WARNING:  This is NOT as ES6 file. So no =>, `str`, or other conveniences */

// some RequireJS config before we start.
requirejs.config({

  // IMPORTANT NOTE: if you add something here, update the Gruntfile
  // 'compile2' task

  paths: {
    // all of our code is written in jsx/es6 syntax and converted using babel
    babel: "vendor/requirejs-babel/babel-4.6.6.min",
    classnames: 'vendor/classnames/index',
    es6: "vendor/requirejs-babel/es6", // the requirejs babel loader
    // time library
    moment: "vendor/moment/min/moment.min",
    // some extra react components
    react_bootstrap: 'vendor/react-bootstrap/react-bootstrap',
    // core libraries we use
    react: 'vendor/react/react-with-addons',
    'react-dom': 'vendor/react/react-dom',
    requirejs: 'vendor/requirejs/require',
    underscore: 'vendor/underscore/underscore',
    // library to deal with URIs. Per github repo, this version is published
    // under a pure MIT license (despite the gpl v3 reference.)
    uriJS: 'vendor/uri.js/src'
  },
  config: {
    'es6': {
      'optional': ['es7.objectRestSpread'],
    }
  },
  shim: {
    underscore: {
      exports: '_'
    },
  },

  // Increase the require.js load timeout threshold, since the ES6 compilation
  // step in development mode often exceeds the 7-second default threshold.
  waitSeconds: 15
});

/*
 * essentially main(). Routes the user to the right page
 */

require([
  "react",
  "react-dom",
  "underscore",
  "uriJS/URI",
  "es6!server/api",
  "es6!utils/custom_content",
  "es6!utils/utils",
  "es6!display/changes/links",
  // requiring every page. It doesn't matter that much in prod since we bundle,
  // and we want to avoid dynamic module loading
  "es6!pages/home_page",
  "es6!pages/admin_page",
  "es6!pages/admin_project_page",
  "es6!pages/admin_repository_page",
  "es6!pages/infra_fails_page",
  "es6!pages/task_tree_page",
  "es6!pages/jobstep_summary_page",
  "es6!pages/project_page/project_page",
  "es6!pages/author_builds_page",
  "es6!pages/builds_pages/builds_pages",
  "es6!pages/tests_for_build_page",
  "es6!pages/test_history_page",
  "es6!pages/log_page",
  "es6!pages/all_projects_page",
  "es6!pages/node_page",
  "es6!pages/snapshot_page",
  "es6!pages/code_page",
  "es6!pages/pusher_page",
  "es6!pages/examples_page",
  "es6!pages/fourohfour_page",
], function(
  React,
  ReactDOM,
  _,
  URI,
  data_fetching,
  custom_content_hook,
  utils,
  ChangesLinks,

  HomePage,
  AdminPage,
  AdminProjectPage,
  AdminRepositoryPage,
  InfraFailsPage,
  TaskTreePage,
  JobstepSummaryPage,
  ProjectPage,
  AuthorBuildsPage,
  buildsPages,
  buildTestsPages,
  TestHistoryPage,
  LogPage,
  AllProjectsPage,
  NodePage,
  SnapshotPage,
  CodePage,
  PusherPage,
  DisplayExamplesPage,
  FourOhFourPage
) {
  'use strict';

  // for some reason, import statements aren't working for the URI library
  // TODO: figure out why
  window.URI = URI;

  var CommitPage = buildsPages.CommitPage;
  var DiffPage = buildsPages.DiffPage;
  var SingleBuildPage = buildsPages.SingleBuildPage;

  var BuildTestsPage = buildTestsPages.BuildTestsPage;
  var SingleBuildTestPage = buildTestsPages.SingleBuildTestPage;

  // routing
  // TODO: all of this is terrible and temporary just to get something working.
  // replace with a routing library. Probably not react-router, though... its
  // too template-y. Or at least don't use nesting with react-router

  var path = window.location.pathname;
  var path_parts = _.compact(path.split('/'));

  // Strip the leading /v2/ if it exists
  if (path_parts[0] == 'v2') {
    path_parts.shift();
  }

  // We want to ensure that certain changes classic style links still work.
  if (path_parts.length > 3 && path_parts[0] === 'projects' && path_parts[2] == 'builds') {
    var build_id = path_parts[3];
    if (path_parts.indexOf('tests') > 3)
      path_parts = ['build_tests', build_id];
    // for /projects/<slug>/builds/<build_id>/jobs/<job_id>/logs/<log_id>
    else if (path_parts.length == 8 && path_parts[4] == 'jobs' && path_parts[6] == 'logs')
      path_parts = ['job_log', build_id, path_parts[5], path_parts[7]];
    else
      path_parts = ['find_build', build_id];
  }

  var redirect_to_build = function(build_id) {
    var build_redirect_func = function(response, was_success) {
      if (!was_success) {
        document.write('Redirect failed');
        return;
      }

      var build = JSON.parse(response.responseText);
      var new_href = URI(ChangesLinks.buildHref(build))
        .addSearch('optin', 1);
      window.location.href = new_href;
    };

    data_fetching.make_api_ajax_get('/api/0/builds/' + build_id, null,
      build_redirect_func, build_redirect_func);
  };

  var redirect_to_node = function(node_hostname) {
    var node_redirect_func = function(response, was_success) {
      if (!was_success) {
        document.write('Redirect failed');
        return;
      }

      var node = JSON.parse(response.responseText);
      var new_href = URI('/node/' + node.id + '/');
      window.location.href = new_href;
    };

    data_fetching.make_api_ajax_get('/api/0/nodes/hostname/' + node_hostname, null,
      node_redirect_func, node_redirect_func);
  };

  var redirect_to_jobstep = function(jobstep_id) {
    var jobstep_redirect_func = function(response, was_success) {
      if (!was_success) {
        document.write('Redirect failed');
        return;
      }

      var jobstep = JSON.parse(response.responseText);
      redirect_to_build(jobstep.job.build.id);
    };

    data_fetching.make_api_ajax_get('/api/0/jobsteps/' + jobstep_id, null,
      jobstep_redirect_func, jobstep_redirect_func);
  };

  if (path_parts[0] === 'find_build') {
    redirect_to_build(path_parts[1]);
    return;
  } else if (path_parts[0] === 'find_jobstep') {
    redirect_to_jobstep(path_parts[1]);
    return;
  } else if (path_parts[0] === 'find_node') {
    redirect_to_node(path_parts[1]);
    return;
  }

  var url_contains = {
    'projects': [AllProjectsPage],
    'project': [ProjectPage, 'projectSlug'],
    'author_builds': [AuthorBuildsPage, 'author'],
    'commit_source': [CommitPage, 'sourceUUID'],
    'diff': [DiffPage, 'diff_id'],
    'single_build': [SingleBuildPage, 'buildID'],
    'build_test': [SingleBuildTestPage, 'buildID', 'testID'],
    'build_tests': [BuildTestsPage, 'buildID'],
    'project_test': [TestHistoryPage, 'projectUUID', 'testHash'],
    'job_log': [LogPage, 'buildID', 'jobID', 'logsourceID'],
    'author': [HomePage, 'author'],  // TODO: don't just use the homepage
    'node': [NodePage, 'nodeID'],
    'snapshot': [SnapshotPage, 'snapshotID'],
    'infra_fails': [InfraFailsPage],
    'task_tree': [TaskTreePage, 'objectID'],
    'jobstep_summary': [JobstepSummaryPage],
    'code': [CodePage, 'sourceID'],
    'pusher': [PusherPage],
    'display_examples': [DisplayExamplesPage],
    'admin': [AdminPage],
    'admin_project': [AdminProjectPage, 'projectSlug'],
    'admin_repository': [AdminRepositoryPage, 'repositoryID'],
  };

  var page = FourOhFourPage;

  // Redirect projects/foo -> project/foo because
  // v1 project pages used the plural form
  if (path_parts[0] === 'projects' && path_parts.length > 1) {
    path_parts[0] = 'project';
  }

  var params = {};
  for (var str in url_contains) {
    if (path_parts[0] === str) {
      var page_data = url_contains[str];
      page = page_data[0];
      if (page_data.length > 1) {
        if (path_parts.length < page_data.length) {
          // path doesn't have enough parts...
          page = FourOhFourPage;
          params['badUrl'] = true;
          break;
        }
        for (var i = 1; i < page_data.length; i++) {
          params[page_data[i]] = path_parts[i];
        }
      }
      break;
    }
  }

  if (path_parts.length === 0) { page = HomePage; }

  // we fetch some initial data used by pages (e.g. are we logged in?)
  data_fetching.make_api_ajax_get('/api/0/initial/', null, function(response) {
    var parsedResponse = JSON.parse(response.responseText);

    // TODO: use context?
    window.changesAuthData = parsedResponse['auth'];
    window.changesMessageData = parsedResponse['admin_message'];

    // require user to be logged in
    if (!window.changesAuthData || !window.changesAuthData.user) {
      // disabled on the project page for now so that people can create
      // dashboards
      var unauthOKPages = ['project', 'pusher'];
      var unauthOK = _.any(unauthOKPages, function(path) {
        return path_parts[0] === path
      });

      if (!unauthOK) {
         // if WEBAPP_USE_ANOTHER_HOST, we can't redirect to login. Tell the
         // user to do it themselves
         if (window.changesGlobals['USE_ANOTHER_HOST']) {
           document.getElementById('reactRoot').innerHTML = '
' +
             'We want to redirect you to login, but API calls are using ' +
             'a different server (WEBAPP_USE_ANOTHER_HOST). Go to that ' +
             'server and log in.' +
             '
';
           return;
         }

         var current_location = encodeURIComponent(window.location.href);
         var login_href = '/auth/login/?orig_url=' + current_location;

         console.log("User not identified - redirecting to login");
         window.location.href = login_href;
         return;
      }
    }

    // add custom css class if present
    var custom_css = custom_content_hook('rootClass', '');
    var root_classes = (
      "reactRoot " +
      (document.getElementById('reactRoot').className || '') + " " +
      custom_css
    ).trim();
    document.getElementById('reactRoot').className = root_classes

    var pageElem = ReactDOM.render(
      React.createElement(page, params),
      document.getElementById('reactRoot')
    );

    var initialTitle = pageElem.getInitialTitle && pageElem.getInitialTitle();

    if (initialTitle) {
      utils.setPageTitle(initialTitle);
    }
  });
});

<commit_msg>Stop generating an 'optin' URL param<commit_after>/* WARNING:  This is NOT as ES6 file. So no =>, `str`, or other conveniences */

// some RequireJS config before we start.
requirejs.config({

  // IMPORTANT NOTE: if you add something here, update the Gruntfile
  // 'compile2' task

  paths: {
    // all of our code is written in jsx/es6 syntax and converted using babel
    babel: "vendor/requirejs-babel/babel-4.6.6.min",
    classnames: 'vendor/classnames/index',
    es6: "vendor/requirejs-babel/es6", // the requirejs babel loader
    // time library
    moment: "vendor/moment/min/moment.min",
    // some extra react components
    react_bootstrap: 'vendor/react-bootstrap/react-bootstrap',
    // core libraries we use
    react: 'vendor/react/react-with-addons',
    'react-dom': 'vendor/react/react-dom',
    requirejs: 'vendor/requirejs/require',
    underscore: 'vendor/underscore/underscore',
    // library to deal with URIs. Per github repo, this version is published
    // under a pure MIT license (despite the gpl v3 reference.)
    uriJS: 'vendor/uri.js/src'
  },
  config: {
    'es6': {
      'optional': ['es7.objectRestSpread'],
    }
  },
  shim: {
    underscore: {
      exports: '_'
    },
  },

  // Increase the require.js load timeout threshold, since the ES6 compilation
  // step in development mode often exceeds the 7-second default threshold.
  waitSeconds: 15
});

/*
 * essentially main(). Routes the user to the right page
 */

require([
  "react",
  "react-dom",
  "underscore",
  "uriJS/URI",
  "es6!server/api",
  "es6!utils/custom_content",
  "es6!utils/utils",
  "es6!display/changes/links",
  // requiring every page. It doesn't matter that much in prod since we bundle,
  // and we want to avoid dynamic module loading
  "es6!pages/home_page",
  "es6!pages/admin_page",
  "es6!pages/admin_project_page",
  "es6!pages/admin_repository_page",
  "es6!pages/infra_fails_page",
  "es6!pages/task_tree_page",
  "es6!pages/jobstep_summary_page",
  "es6!pages/project_page/project_page",
  "es6!pages/author_builds_page",
  "es6!pages/builds_pages/builds_pages",
  "es6!pages/tests_for_build_page",
  "es6!pages/test_history_page",
  "es6!pages/log_page",
  "es6!pages/all_projects_page",
  "es6!pages/node_page",
  "es6!pages/snapshot_page",
  "es6!pages/code_page",
  "es6!pages/pusher_page",
  "es6!pages/examples_page",
  "es6!pages/fourohfour_page",
], function(
  React,
  ReactDOM,
  _,
  URI,
  data_fetching,
  custom_content_hook,
  utils,
  ChangesLinks,

  HomePage,
  AdminPage,
  AdminProjectPage,
  AdminRepositoryPage,
  InfraFailsPage,
  TaskTreePage,
  JobstepSummaryPage,
  ProjectPage,
  AuthorBuildsPage,
  buildsPages,
  buildTestsPages,
  TestHistoryPage,
  LogPage,
  AllProjectsPage,
  NodePage,
  SnapshotPage,
  CodePage,
  PusherPage,
  DisplayExamplesPage,
  FourOhFourPage
) {
  'use strict';

  // for some reason, import statements aren't working for the URI library
  // TODO: figure out why
  window.URI = URI;

  var CommitPage = buildsPages.CommitPage;
  var DiffPage = buildsPages.DiffPage;
  var SingleBuildPage = buildsPages.SingleBuildPage;

  var BuildTestsPage = buildTestsPages.BuildTestsPage;
  var SingleBuildTestPage = buildTestsPages.SingleBuildTestPage;

  // routing
  // TODO: all of this is terrible and temporary just to get something working.
  // replace with a routing library. Probably not react-router, though... its
  // too template-y. Or at least don't use nesting with react-router

  var path = window.location.pathname;
  var path_parts = _.compact(path.split('/'));

  // Strip the leading /v2/ if it exists
  if (path_parts[0] == 'v2') {
    path_parts.shift();
  }

  // We want to ensure that certain changes classic style links still work.
  if (path_parts.length > 3 && path_parts[0] === 'projects' && path_parts[2] == 'builds') {
    var build_id = path_parts[3];
    if (path_parts.indexOf('tests') > 3)
      path_parts = ['build_tests', build_id];
    // for /projects/<slug>/builds/<build_id>/jobs/<job_id>/logs/<log_id>
    else if (path_parts.length == 8 && path_parts[4] == 'jobs' && path_parts[6] == 'logs')
      path_parts = ['job_log', build_id, path_parts[5], path_parts[7]];
    else
      path_parts = ['find_build', build_id];
  }

  var redirect_to_build = function(build_id) {
    var build_redirect_func = function(response, was_success) {
      if (!was_success) {
        document.write('Redirect failed');
        return;
      }

      var build = JSON.parse(response.responseText);
      window.location.href = URI(ChangesLinks.buildHref(build));
    };

    data_fetching.make_api_ajax_get('/api/0/builds/' + build_id, null,
      build_redirect_func, build_redirect_func);
  };

  var redirect_to_node = function(node_hostname) {
    var node_redirect_func = function(response, was_success) {
      if (!was_success) {
        document.write('Redirect failed');
        return;
      }

      var node = JSON.parse(response.responseText);
      var new_href = URI('/node/' + node.id + '/');
      window.location.href = new_href;
    };

    data_fetching.make_api_ajax_get('/api/0/nodes/hostname/' + node_hostname, null,
      node_redirect_func, node_redirect_func);
  };

  var redirect_to_jobstep = function(jobstep_id) {
    var jobstep_redirect_func = function(response, was_success) {
      if (!was_success) {
        document.write('Redirect failed');
        return;
      }

      var jobstep = JSON.parse(response.responseText);
      redirect_to_build(jobstep.job.build.id);
    };

    data_fetching.make_api_ajax_get('/api/0/jobsteps/' + jobstep_id, null,
      jobstep_redirect_func, jobstep_redirect_func);
  };

  if (path_parts[0] === 'find_build') {
    redirect_to_build(path_parts[1]);
    return;
  } else if (path_parts[0] === 'find_jobstep') {
    redirect_to_jobstep(path_parts[1]);
    return;
  } else if (path_parts[0] === 'find_node') {
    redirect_to_node(path_parts[1]);
    return;
  }

  var url_contains = {
    'projects': [AllProjectsPage],
    'project': [ProjectPage, 'projectSlug'],
    'author_builds': [AuthorBuildsPage, 'author'],
    'commit_source': [CommitPage, 'sourceUUID'],
    'diff': [DiffPage, 'diff_id'],
    'single_build': [SingleBuildPage, 'buildID'],
    'build_test': [SingleBuildTestPage, 'buildID', 'testID'],
    'build_tests': [BuildTestsPage, 'buildID'],
    'project_test': [TestHistoryPage, 'projectUUID', 'testHash'],
    'job_log': [LogPage, 'buildID', 'jobID', 'logsourceID'],
    'author': [HomePage, 'author'],  // TODO: don't just use the homepage
    'node': [NodePage, 'nodeID'],
    'snapshot': [SnapshotPage, 'snapshotID'],
    'infra_fails': [InfraFailsPage],
    'task_tree': [TaskTreePage, 'objectID'],
    'jobstep_summary': [JobstepSummaryPage],
    'code': [CodePage, 'sourceID'],
    'pusher': [PusherPage],
    'display_examples': [DisplayExamplesPage],
    'admin': [AdminPage],
    'admin_project': [AdminProjectPage, 'projectSlug'],
    'admin_repository': [AdminRepositoryPage, 'repositoryID'],
  };

  var page = FourOhFourPage;

  // Redirect projects/foo -> project/foo because
  // v1 project pages used the plural form
  if (path_parts[0] === 'projects' && path_parts.length > 1) {
    path_parts[0] = 'project';
  }

  var params = {};
  for (var str in url_contains) {
    if (path_parts[0] === str) {
      var page_data = url_contains[str];
      page = page_data[0];
      if (page_data.length > 1) {
        if (path_parts.length < page_data.length) {
          // path doesn't have enough parts...
          page = FourOhFourPage;
          params['badUrl'] = true;
          break;
        }
        for (var i = 1; i < page_data.length; i++) {
          params[page_data[i]] = path_parts[i];
        }
      }
      break;
    }
  }

  if (path_parts.length === 0) { page = HomePage; }

  // we fetch some initial data used by pages (e.g. are we logged in?)
  data_fetching.make_api_ajax_get('/api/0/initial/', null, function(response) {
    var parsedResponse = JSON.parse(response.responseText);

    // TODO: use context?
    window.changesAuthData = parsedResponse['auth'];
    window.changesMessageData = parsedResponse['admin_message'];

    // require user to be logged in
    if (!window.changesAuthData || !window.changesAuthData.user) {
      // disabled on the project page for now so that people can create
      // dashboards
      var unauthOKPages = ['project', 'pusher'];
      var unauthOK = _.any(unauthOKPages, function(path) {
        return path_parts[0] === path
      });

      if (!unauthOK) {
         // if WEBAPP_USE_ANOTHER_HOST, we can't redirect to login. Tell the
         // user to do it themselves
         if (window.changesGlobals['USE_ANOTHER_HOST']) {
           document.getElementById('reactRoot').innerHTML = '
' +
             'We want to redirect you to login, but API calls are using ' +
             'a different server (WEBAPP_USE_ANOTHER_HOST). Go to that ' +
             'server and log in.' +
             '
';
           return;
         }

         var current_location = encodeURIComponent(window.location.href);
         var login_href = '/auth/login/?orig_url=' + current_location;

         console.log("User not identified - redirecting to login");
         window.location.href = login_href;
         return;
      }
    }

    // add custom css class if present
    var custom_css = custom_content_hook('rootClass', '');
    var root_classes = (
      "reactRoot " +
      (document.getElementById('reactRoot').className || '') + " " +
      custom_css
    ).trim();
    document.getElementById('reactRoot').className = root_classes

    var pageElem = ReactDOM.render(
      React.createElement(page, params),
      document.getElementById('reactRoot')
    );

    var initialTitle = pageElem.getInitialTitle && pageElem.getInitialTitle();

    if (initialTitle) {
      utils.setPageTitle(initialTitle);
    }
  });
});

<|endoftext|>


<commit_before>var http = require("http");

var onRequest = function(request, response) {
          response.writeHead(200, {"Content-Type": "text/plain"});
          response.write("Hello World");
          response.end();
}

http.createServer(onRequest).listen(8888);<commit_msg>Dig inside event driven async callbacks topic<commit_after>var http = require("http");

var onRequest = function(request, response) {
    console.log("Request received.");
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
}

http.createServer(onRequest).listen(8888);

console.log("Server has started.");<|endoftext|>