<commit_before>function day(){
    // if day is not over, continue. else end day
    if(daylight_passed < 5){
        // if day just started, clear previous days events and change start-day link to text
        if(daylight_passed === 0){
            interval_value = get('day-duration').value;
            if(isNaN(interval_value) || interval_value <= 0){
                interval_value = 600;
            }

            get('day-events').innerHTML = '';
            get('start-day').innerHTML = 'Day Progressing...';
        }

        // generate random event value
        i = Math.random();

        if(i < .72){
            // no event
            i = '-----';

        }else if(i < .78){
            // food event

            // generate how much food
            j = random_number(2);

            if(Math.random() < .5){
                // food lost
                food -= j;

                if(food < 0){
                    // lose 2 gold per food under 0
                    gold += food * 2;
                    food = 0;
                }

                i = 'Bugs! -';

            }else{
                // food gained
                food += j;
                i = 'Rain! +';
            }
            i += j + ' Food';

        }else if(i < .84){
            // gold event

            // generate how much gold
            j = random_number(2);

            if(Math.random() < .5){
                // lose gold
                gold -= j;
                i = 'Theives! -';

            }else{
                // gain gold
                gold += j;
                i = 'Mining! +';
            }

            i += j + ' Gold';

        }else if(i < .9){
            // stone event

            // generate how much stone
            j = random_number(2);

            if(Math.random() < .5){
                // lose stone
                stone -= j;

                if(stone < 0){
                    // lose 2 gold per stone under 0
                    gold += stone * 2;
                    stone = 0;
                }

                i = 'Repair! -';

            }else{
                // gain stone
                stone += j;
                i = 'Mining! +';
            }
            i += j + ' Stone';

        }else if(i < .96){
            // population event

            if(Math.random() < .5){
                // lose people
                if(people > 0){
                    people -= 1;

                    // if no workers are unemployed
                    if(unemployed_workers < 1){
                        // decrease people workers first
                        if(people_workers > 0){
                            people_bonus -= 1;
                            people_workers -= 1;

                            get('people-bonus').innerHTML = people_workers;
                            get('people-workers').innerHTML = people_workers;

                        // if no people workers, decrease stone workers
                        }else if(stone_workers > 0){
                            stone_bonus -= 1;
                            stone_workers -= 1;

                            get('stone-bonus').innerHTML = stone_workers;
                            get('stone-workers').innerHTML = stone_workers;

                        // if no stone workers, decrease gold workers
                        }else if(gold_workers > 0){
                            gold_bonus -= 1;
                            gold_workers -= 1;

                            get('gold-bonus').innerHTML = gold_workers;
                            get('gold-workers').innerHTML = gold_workers;

                        // if no gold workers, decrease food workers
                        }else{
                            food_workers -= 1;
                            get('food-workers').innerHTML = food_workers;
                        }

                    // else decrease unemployed workers
                    }else{
                        unemployed_workers -= 1;
                    }
                }
                i = 'Sickness! -';

            }else{
                // gain people
                people += 1;
                unemployed_workers += 1;
                i = 'Recruitment! +';
            }

            // update food bonus based on current population
            food_bonus = food_workers * 2 - people;

            i += '1 Population';

        }else if(i < .99){
            // other events, not yet implemented
            j = random_number(2);
            if(j === 0){
                i = 'Battle Event (NYI)';

            }else{
                i = 'Other Event (NYI)';
            }

        }else{
            // resource bonus event

            // generate which resource
            j = random_number(4);

            if(j === 0){
                i = 'Seeds! +1 Food/day';
                food_bonus += 1;
                get('food-bonus').innerHTML = food_bonus;

            }else if(j === 1){
                i = 'Veins! +1 Gold/day';
                gold_bonus += 1;
                get('gold-bonus').innerHTML = gold_bonus;

            }else if(j === 2){
                i = 'Popularity! +1 Population/day';
                people_bonus += 1;
                get('people-bonus').innerHTML = people_bonus;

            }else{
                i = 'Rocks! +1 Stone/day';
                stone_bonus += 1;
                get('stone-bonus').innerHTML = stone_bonus;

            }
        }

        // add event to list of day-events
        get('day-events').innerHTML += i + '
';

        // more daylight has passed
        daylight_passed += 1;

        // if day is not over, wait interval_value ms for next event
        // interval_value is set by the day-duration input field
        if(daylight_passed < 5){
            setTimeout(
                'day()',
                interval_value
            );

        // otherwise move on
        }else{
            day();
        }

    }else{
        // end day
        block_unload = 1;
        daylight_passed = 0;

        // update resources with daily bonuses
        food += food_bonus;
        food_bonus -= people_bonus;
        gold += gold_bonus;
        people += people_bonus;
        stone += stone_bonus;
        unemployed_workers += people_bonus;

        // calculate if there is not enough food to feed population
        if(food + food_bonus < people){
            // if not enough food, decrease population and workers
            people -= people - food + food_bonus;
            unemployed_workers -= people - food + food_bonus;

            if(people < 0){
                people = 0;
            }

            // update new food_bonus
            food_bonus += people - food + food_bonus;
            food = 0;
        }

        // update start-day text with start new day or game over message
        get('start-day').innerHTML = people > 0
            ? 'Start New Day'
            : 'Your Castle Has Fallen. :(
Start Over';
    }

    // update text displays
    get('food').innerHTML = food;
    get('food-bonus').innerHTML = (food_bonus >= 0 ? '+' : '') + food_bonus;
    get('gold').innerHTML = gold;
    get('people').innerHTML = people;
    get('stone').innerHTML = stone;
    get('unemployed-workers').innerHTML = unemployed_workers;
}

function distribute_workers(resource,amount){
    // positive amount = decrease workers, negative amount = increase workers

    // if a day is not in progress and there are either unemployed workers or workers being decreased
    if(daylight_passed === 0 && (unemployed_workers > 0 || amount < 0)){
        // alter food workers
        if(resource === 0){
            if(food_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                food_bonus += amount * 2;
                food_workers += amount;

            }else{
                food_workers = 0;

            }
            get('food-bonus').innerHTML = (food_bonus >= 0 ? '+' : '') + food_bonus;
            get('food-workers').innerHTML = food_workers;

        // alter gold workers
        }else if(resource === 1){
            if(gold_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                gold_bonus += amount;
                gold_workers += amount;

            }else{
                gold_workers = 0;

            }
            get('gold-bonus').innerHTML = gold_workers;
            get('gold-workers').innerHTML = gold_workers;

        // alter people workers
        }else if(resource === 2){
            if(people_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                people_bonus += amount;
                people_workers += amount;

            }else{
                people_workers = 0;
            }

            get('people-bonus').innerHTML = people_workers;
            get('people-workers').innerHTML = people_workers;

        // alter stone workers
        }else{
            if(stone_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                stone_bonus += amount;
                stone_workers += amount;

            }else{
                stone_workers = 0;
            }

            get('stone-bonus').innerHTML = stone_workers;
            get('stone-workers').innerHTML = stone_workers;
        }
        get('unemployed-workers').innerHTML = unemployed_workers;
    }
}

function get(i){
    return document.getElementById(i);
}

function new_game(){
    block_unload = 0;
    daylight_passed = 0;
    food = 10;
    food_bonus = -1;
    food_workers = 0;
    gold = 0;
    gold_bonus = 0;
    gold_workers = 0;
    people = 1;
    people_bonus = 0;
    people_workers = 0;
    stone = 0;
    stone_bonus = 0;
    stone_workers = 0;
    unemployed_workers = 1;

    // reset all text displays
    get('food').innerHTML = food;
    get('food-bonus').innerHTML = food_bonus;
    get('food-workers').innerHTML = food_workers;
    get('gold').innerHTML = gold;
    get('gold-bonus').innerHTML = gold_bonus;
    get('gold-workers').innerHTML = gold_workers;
    get('people').innerHTML = people;
    get('people-bonus').innerHTML = people_bonus;
    get('people-workers').innerHTML = people_workers;
    get('stone').innerHTML = stone;
    get('stone-bonus').innerHTML = stone_bonus;
    get('stone-workers').innerHTML = stone_workers;
    get('unemployed-workers').innerHTML = unemployed_workers;

    get('day-events').innerHTML = '';
    get('start-day').innerHTML = 'Start New Day';
}

function random_number(i){
    return Math.floor(Math.random() * i) + 1;
}

var block_unload = 0;
var daylight_passed = 0;
var food = 10;
var food_bonus = -1;
var food_workers = 0;
var gold = 0;
var gold_bonus = 0;
var gold_workers = 0;
var i = 0;
var interval_value = 0;
var j = 0;
var people = 1;
var people_bonus = 0;
var people_workers = 0;
var stone = 0;
var stone_bonus = 0;
var stone_workers = 0;
var unemployed_workers = 1;

window.onbeforeunload = function(){
    // warn players if they have already made progress
    if(block_unload && people > 0){
        return 'Save feature will be implemented in the future.';
    }
};

window.onkeydown = function(e){
    var key = window.event ? event : e;
    key = key.charCode ? key.charCode : key.keyCode;

    // if new day can be started, any key except for integer keys will start it
    if(daylight_passed === 0 && people > 0 && (key < 48 || key > 57)){
        day();
    }
}
<commit_msg>fixed some population bugs<commit_after>function day(){
    // if day is not over, continue. else end day
    if(daylight_passed < 5){
        // if day just started, clear previous days events and change start-day link to text
        if(daylight_passed === 0){
            interval_value = get('day-duration').value;
            if(isNaN(interval_value) || interval_value <= 0){
                interval_value = 600;
            }

            get('day-events').innerHTML = '';
            get('start-day').innerHTML = 'Day Progressing...';
        }

        // generate random event value
        i = Math.random();

        if(i < .72){
            // no event
            i = '-----';

        }else if(i < .78){
            // food event

            // generate how much food
            j = random_number(2);

            if(Math.random() < .5){
                // food lost
                food -= j;

                if(food < 0){
                    // lose 2 gold per food under 0
                    gold += food * 2;
                    food = 0;
                }

                i = 'Bugs! -';

            }else{
                // food gained
                food += j;
                i = 'Rain! +';
            }
            i += j + ' Food';

        }else if(i < .84){
            // gold event

            // generate how much gold
            j = random_number(2);

            if(Math.random() < .5){
                // lose gold
                gold -= j;
                i = 'Theives! -';

            }else{
                // gain gold
                gold += j;
                i = 'Mining! +';
            }

            i += j + ' Gold';

        }else if(i < .9){
            // stone event

            // generate how much stone
            j = random_number(2);

            if(Math.random() < .5){
                // lose stone
                stone -= j;

                if(stone < 0){
                    // lose 2 gold per stone under 0
                    gold += stone * 2;
                    stone = 0;
                }

                i = 'Repair! -';

            }else{
                // gain stone
                stone += j;
                i = 'Mining! +';
            }
            i += j + ' Stone';

        }else if(i < .96){
            // population event

            if(Math.random() < .5){
                // lose people
                if(people > 0){
                    people -= 1;
                    delete_people(0);
                }
                i = 'Sickness! -';

            }else{
                // gain people
                people += 1;
                unemployed_workers += 1;
                i = 'Recruitment! +';
            }

            // update food bonus based on current population
            food_bonus = food_workers * 2 - people;

            i += '1 Population';

        }else if(i < .99){
            // other events, not yet implemented
            j = random_number(2);
            if(j === 0){
                i = 'Battle Event (NYI)';

            }else{
                i = 'Other Event (NYI)';
            }

        }else{
            // resource bonus event

            // generate which resource
            j = random_number(4);

            if(j === 0){
                i = 'Seeds! +1 Food/day';
                food_bonus += 1;
                get('food-bonus').innerHTML = food_bonus;

            }else if(j === 1){
                i = 'Veins! +1 Gold/day';
                gold_bonus += 1;
                get('gold-bonus').innerHTML = gold_bonus;

            }else if(j === 2){
                i = 'Popularity! +1 Population/day';
                people_bonus += 1;
                get('people-bonus').innerHTML = people_bonus;

            }else{
                i = 'Rocks! +1 Stone/day';
                stone_bonus += 1;
                get('stone-bonus').innerHTML = stone_bonus;

            }
        }

        // add event to list of day-events
        get('day-events').innerHTML += i + '
';

        // more daylight has passed
        daylight_passed += 1;

        // if day is not over, wait interval_value ms for next event
        // interval_value is set by the day-duration input field
        if(daylight_passed < 5){
            setTimeout(
                'day()',
                interval_value
            );

        // otherwise move on
        }else{
            day();
        }

    }else{
        // end day
        block_unload = 1;
        daylight_passed = 0;

        // update resources with daily bonuses
        food += food_bonus;
        food_bonus -= people_bonus;
        gold += gold_bonus;
        people += people_bonus;
        stone += stone_bonus;
        unemployed_workers += people_bonus;

        // calculate if there is not enough food to feed population
        if(food + food_bonus < 0){
            // if not enough food, decrease population and workers
            delete_people(people - 1);
            people -= people - (food + food_bonus);

            if(people < 0){
                people = 0;
            }

            // update new food_bonus
            food = 0;
            food_bonus = -1;
        }
        console.log('here')

        // update start-day text with start new day or game over message
        get('start-day').innerHTML = people > 0
            ? 'Start New Day'
            : 'Your Castle Has Fallen. :(
Start Over';
    }

    // update text displays
    get('food').innerHTML = food;
    get('food-bonus').innerHTML = (food_bonus >= 0 ? '+' : '') + food_bonus;
    get('gold').innerHTML = gold;
    get('people').innerHTML = people;
    get('stone').innerHTML = stone;
    get('unemployed-workers').innerHTML = unemployed_workers;
}

function delete_people(count){
    do{
        // if no workers are unemployed
        if(unemployed_workers < 1){
            // decrease people workers first
            if(people_workers > 0){
                people_bonus -= 1;
                people_workers -= 1;

                get('people-bonus').innerHTML = people_workers;
                get('people-workers').innerHTML = people_workers;

            // if no people workers, decrease stone workers
            }else if(stone_workers > 0){
                stone_bonus -= 1;
                stone_workers -= 1;

                get('stone-bonus').innerHTML = stone_workers;
                get('stone-workers').innerHTML = stone_workers;

            // if no stone workers, decrease gold workers
            }else if(gold_workers > 0){
                gold_bonus -= 1;
                gold_workers -= 1;

                get('gold-bonus').innerHTML = gold_workers;
                get('gold-workers').innerHTML = gold_workers;

            // if no gold workers, decrease food workers
            }else{
                food_workers -= 1;
                get('food-workers').innerHTML = food_workers;
            }

        // else decrease unemployed workers
        }else{
            unemployed_workers -= 1;
        }
    }while(count--);
}

function distribute_workers(resource,amount){
    // positive amount = decrease workers, negative amount = increase workers

    // if a day is not in progress and there are either unemployed workers or workers being decreased
    if(daylight_passed === 0 && (unemployed_workers > 0 || amount < 0)){
        // alter food workers
        if(resource === 0){
            if(food_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                food_bonus += amount * 2;
                food_workers += amount;

            }else{
                food_workers = 0;

            }
            get('food-bonus').innerHTML = (food_bonus >= 0 ? '+' : '') + food_bonus;
            get('food-workers').innerHTML = food_workers;

        // alter gold workers
        }else if(resource === 1){
            if(gold_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                gold_bonus += amount;
                gold_workers += amount;

            }else{
                gold_workers = 0;

            }
            get('gold-bonus').innerHTML = gold_bonus;
            get('gold-workers').innerHTML = gold_workers;

        // alter people workers
        }else if(resource === 2){
            if(people_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                people_bonus += amount;
                people_workers += amount;

            }else{
                people_workers = 0;
            }

            get('people-bonus').innerHTML = people_bonus;
            get('people-workers').innerHTML = people_workers;

        // alter stone workers
        }else{
            if(stone_workers > 0 || amount > 0){
                unemployed_workers -= amount;
                stone_bonus += amount;
                stone_workers += amount;

            }else{
                stone_workers = 0;
            }

            get('stone-bonus').innerHTML = stone_bonus;
            get('stone-workers').innerHTML = stone_workers;
        }
        get('unemployed-workers').innerHTML = unemployed_workers;
    }
}

function get(i){
    return document.getElementById(i);
}

function new_game(){
    block_unload = 0;
    daylight_passed = 0;
    food = 10;
    food_bonus = -1;
    food_workers = 0;
    gold = 0;
    gold_bonus = 0;
    gold_workers = 0;
    people = 1;
    people_bonus = 0;
    people_workers = 0;
    stone = 0;
    stone_bonus = 0;
    stone_workers = 0;
    unemployed_workers = 1;

    // reset all text displays
    get('food').innerHTML = food;
    get('food-bonus').innerHTML = food_bonus;
    get('food-workers').innerHTML = food_workers;
    get('gold').innerHTML = gold;
    get('gold-bonus').innerHTML = gold_bonus;
    get('gold-workers').innerHTML = gold_workers;
    get('people').innerHTML = people;
    get('people-bonus').innerHTML = people_bonus;
    get('people-workers').innerHTML = people_workers;
    get('stone').innerHTML = stone;
    get('stone-bonus').innerHTML = stone_bonus;
    get('stone-workers').innerHTML = stone_workers;
    get('unemployed-workers').innerHTML = unemployed_workers;

    get('day-events').innerHTML = '';
    get('start-day').innerHTML = 'Start New Day';
}

function random_number(i){
    return Math.floor(Math.random() * i) + 1;
}

var block_unload = 0;
var daylight_passed = 0;
var food = 10;
var food_bonus = -1;
var food_workers = 0;
var gold = 0;
var gold_bonus = 0;
var gold_workers = 0;
var i = 0;
var interval_value = 0;
var j = 0;
var people = 1;
var people_bonus = 0;
var people_workers = 0;
var stone = 0;
var stone_bonus = 0;
var stone_workers = 0;
var unemployed_workers = 1;

window.onbeforeunload = function(){
    // warn players if they have already made progress
    if(block_unload && people > 0){
        return 'Save feature will be implemented in the future.';
    }
};

window.onkeydown = function(e){
    var key = window.event ? event : e;
    key = key.charCode ? key.charCode : key.keyCode;

    // if new day can be started, any key except for integer keys will start it
    if(daylight_passed === 0 && people > 0 && (key < 48 || key > 57)){
        day();
    }
}
<|endoftext|>


<commit_before>/*!
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*!
 * @module bigquery/job
 */

'use strict';

var common = require('@google-cloud/common');
var extend = require('extend');
var is = require('is');
var util = require('util');

/*! Developer Documentation
 *
 * @param {module:bigquery} bigQuery - BigQuery instance.
 * @param {string} id - The ID of the job.
 */
/**
 * Job objects are returned from various places in the BigQuery API:
 *
 * - {module:bigquery#getJobs}
 * - {module:bigquery#job}
 * - {module:bigquery#query}
 * - {module:bigquery#startJob}
 * - {module:bigquery/table#copy}
 * - {module:bigquery/table#createWriteStream}
 * - {module:bigquery/table#export}
 * - {module:bigquery/table#import}
 *
 * They can be used to check the status of a running job or fetching the results
 * of a previously-executed one.
 *
 * @alias module:bigquery/job
 * @constructor
 *
 * @example
 * var job = bigquery.job('job-id');
 *
 * //-
 * // All jobs are event emitters. The status of each job is polled
 * // continuously, starting only after you register a "complete" listener.
 * //-
 * job.on('complete', function(metadata) {
 *   // The job is complete.
 * });
 *
 * //-
 * // Be sure to register an error handler as well to catch any issues which
 * // impeded the job.
 * //-
 * job.on('error', function(err) {
 *   // An error occurred during the job.
 * });
 *
 * //-
 * // To force the Job object to stop polling for updates, simply remove any
 * // "complete" listeners you've registered.
 * //
 * // The easiest way to do this is with `removeAllListeners()`.
 * //-
 * job.removeAllListeners();
 */
function Job(bigQuery, id) {
  var methods = {
    /**
     * Check if the job exists.
     *
     * @param {function} callback - The callback function.
     * @param {?error} callback.err - An error returned while making this
     *     request.
     * @param {boolean} callback.exists - Whether the job exists or not.
     *
     * @example
     * job.exists(function(err, exists) {});
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.exists().then(function(data) {
     *   var exists = data[0];
     * });
     */
    exists: true,

    /**
     * Get a job if it exists.
     *
     * @example
     * job.get(function(err, job, apiResponse) {
     *   if (!err) {
     *     // `job.metadata` has been populated.
     *   }
     * });
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.get().then(function(data) {
     *   var job = data[0];
     *   var apiResponse = data[1];
     * });
     */
    get: true,

    /**
     * Get the metadata of the job. This will mostly be useful for checking the
     * status of a previously-run job.
     *
     * @resource [Jobs: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/get}
     *
     * @param {function} callback - The callback function.
     * @param {?error} callback.err - An error returned while making this
     *     request.
     * @param {object} callback.metadata - The metadata of the job.
     * @param {object} callback.apiResponse - The full API response.
     *
     * @example
     * var job = bigquery.job('id');
     * job.getMetadata(function(err, metadata, apiResponse) {});
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.getMetadata().then(function(data) {
     *   var metadata = data[0];
     *   var apiResponse = data[1];
     * });
     */
    getMetadata: true,

    /**
     * Set the metadata for this job. This can be useful for updating job
     * labels.
     *
     * @resource [Jobs: patch API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/patch}
     *
     * @param {object} metadata - Metadata to save on the Job.
     * @param {function} callback - The callback function.
     * @param {?error} callback.err - An error returned while making this
     *     request.
     * @param {object} callback.apiResponse - The full API response.
     *
     * @example
     * var metadata = {
     *   configuration: {
     *     labels: {
     *       foo: 'bar'
     *     }
     *   }
     * };
     *
     * job.setMetadata(metadata, function(err, apiResponse) {});
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.setMetadata(metadata).then(function(data) {
     *   var apiResponse = data[0];
     * });
     */
    setMetadata: true,
  };

  common.Operation.call(this, {
    parent: bigQuery,
    baseUrl: '/jobs',
    id: id,
    methods: methods,
  });

  this.bigQuery = bigQuery;

  // The API endpoint for cancel is:    .../bigquery/v2/project/projectId/...
  // The rest of the API endpoints are: .../bigquery/v2/projects/projectId/...
  // Reference: https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1027
  this.interceptors.push({
    request: function(reqOpts) {
      if (reqOpts.uri.indexOf('/cancel') > -1) {
        reqOpts.uri = reqOpts.uri.replace('/projects/', '/project/');
      }
      return reqOpts;
    },
  });
}

util.inherits(Job, common.Operation);

/**
 * Cancel a job. Use {module:bigquery/job#getMetadata} to see if the cancel
 * completes successfully. See an example implementation below.
 *
 * @resource [Jobs: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/cancel}
 *
 * @param {function=} callback - The callback function.
 * @param {?error} callback.err - An error returned while making this request.
 * @param {object} callback.apiResponse - The full API response.
 *
 * @example
 * job.cancel(function(err, apiResponse) {
 *   // Check to see if the job completes successfully.
 *   job.on('error', function(err) {});
 *   job.on('complete', function(metadata) {});
 * });
 *
 * //-
 * // If the callback is omitted, we'll return a Promise.
 * //-
 * job.cancel().then(function(data) {
 *   var apiResponse = data[0];
 * });
 */
Job.prototype.cancel = function(callback) {
  callback = callback || common.util.noop;

  this.request(
    {
      method: 'POST',
      uri: '/cancel',
    },
    function(err, resp) {
      callback(err, resp);
    }
  );
};

/**
 * Get the results of a job.
 *
 * @resource [Jobs: getQueryResults API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/getQueryResults}
 *
 * @param {object=} options - Configuration object.
 * @param {boolean} options.autoPaginate - Have pagination handled
 *     automatically. Default: true.
 * @param {number} options.maxApiCalls - Maximum number of API calls to make.
 * @param {number} options.maxResults - Maximum number of results to read.
 * @param {string} options.pageToken - Page token, returned by a previous call,
 *     to request the next page of results. Note: This is automatically added to
 *     the `nextQuery` argument of your callback.
 * @param {number} options.startIndex - Zero-based index of the starting row.
 * @param {number} options.timeoutMs - How long to wait for the query to
 *     complete, in milliseconds, before returning. Default is to return
 *     immediately. If the timeout passes before the job completes, the request
 *     will fail with a `TIMEOUT` error.
 * @param {function=} callback - The callback function. If you intend to
 *     continuously run this query until all results are in as part of a stream,
 *     do not pass a callback.
 * @param {?error} callback.err - An error returned while making this request
 * @param {array} callback.rows - The results of a job.
 *
 * @example
 * //-
 * // Get all of the results of a query.
 * //-
 * job.getQueryResults(function(err, rows) {
 *   if (!err) {
 *     // rows is an array of results.
 *   }
 * });
 *
 * //-
 * // Customize the results you want to fetch.
 * //-
 * job.getQueryResults({
 *   maxResults: 100
 * }, function(err, rows) {});
 *
 * //-
 * // To control how many API requests are made and page through the results
 * // manually, set `autoPaginate` to `false`.
 * //-
 * function manualPaginationCallback(err, rows, nextQuery, apiResponse) {
 *   if (nextQuery) {
 *     // More results exist.
 *     job.getQueryResults(nextQuery, manualPaginationCallback);
 *   }
 * }
 *
 * job.getQueryResults({
 *   autoPaginate: false
 * }, manualPaginationCallback);
 *
 * //-
 * // If the callback is omitted, we'll return a Promise.
 * //-
 * job.getQueryResults().then(function(data) {
 *   var rows = data[0];
 * });
 */
Job.prototype.getQueryResults = function(options, callback) {
  var self = this;

  if (is.fn(options)) {
    callback = options;
    options = {};
  }

  this.bigQuery.request(
    {
      uri: '/queries/' + this.id,
      qs: options,
    },
    function(err, resp) {
      if (err) {
        callback(err, null, null, resp);
        return;
      }

      var rows = [];

      if (resp.schema && resp.rows) {
        rows = self.bigQuery.mergeSchemaWithRows_(resp.schema, resp.rows);
      }

      var nextQuery = null;
      if (resp.jobComplete === false) {
        // Query is still running.
        nextQuery = extend({}, options);
      } else if (resp.pageToken) {
        // More results exist.
        nextQuery = extend({}, options, {
          pageToken: resp.pageToken,
        });
      }

      callback(null, rows, nextQuery, resp);
    }
  );
};

/**
 * Get the results of a job as a readable object stream.
 *
 * @param {object=} options - Configuration object. See
 *     {module:bigquery/job#getQueryResults} for a complete list of options.
 * @return {stream}
 *
 * @example
 * var through2 = require('through2');
 * var fs = require('fs');
 *
 * job.getQueryResultsStream()
 *   .pipe(through2.obj(function (row, enc, next) {
 *     this.push(JSON.stringify(row) + '\n');
 *     next();
 *   }))
 *   .pipe(fs.createWriteStream('./test/testdata/testfile.json'));
 */
Job.prototype.getQueryResultsStream = common.paginator.streamify(
  'getQueryResults'
);

/**
 * Poll for a status update. Execute the callback:
 *
 *   - callback(err): Job failed
 *   - callback(): Job incomplete
 *   - callback(null, metadata): Job complete
 *
 * @private
 *
 * @param {function} callback
 */
Job.prototype.poll_ = function(callback) {
  this.getMetadata(function(err, metadata, apiResponse) {
    if (!err && apiResponse.status && apiResponse.status.errors) {
      err = common.util.ApiError(apiResponse.status);
    }

    if (err) {
      callback(err);
      return;
    }

    if (metadata.status.state !== 'DONE') {
      callback();
      return;
    }

    callback(null, metadata);
  });
};

/*! Developer Documentation
 *
 * These methods can be auto-paginated.
 */
common.paginator.extend(Job, ['getQueryResults']);

/*! Developer Documentation
 *
 * All async methods (except for streams) will return a Promise in the event
 * that a callback is omitted.
 */
common.util.promisifyAll(Job);

module.exports = Job;
<commit_msg>Fix Job.poll_ (#20)<commit_after>/*!
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*!
 * @module bigquery/job
 */

'use strict';

var common = require('@google-cloud/common');
var extend = require('extend');
var is = require('is');
var util = require('util');

/*! Developer Documentation
 *
 * @param {module:bigquery} bigQuery - BigQuery instance.
 * @param {string} id - The ID of the job.
 */
/**
 * Job objects are returned from various places in the BigQuery API:
 *
 * - {module:bigquery#getJobs}
 * - {module:bigquery#job}
 * - {module:bigquery#query}
 * - {module:bigquery#startJob}
 * - {module:bigquery/table#copy}
 * - {module:bigquery/table#createWriteStream}
 * - {module:bigquery/table#export}
 * - {module:bigquery/table#import}
 *
 * They can be used to check the status of a running job or fetching the results
 * of a previously-executed one.
 *
 * @alias module:bigquery/job
 * @constructor
 *
 * @example
 * var job = bigquery.job('job-id');
 *
 * //-
 * // All jobs are event emitters. The status of each job is polled
 * // continuously, starting only after you register a "complete" listener.
 * //-
 * job.on('complete', function(metadata) {
 *   // The job is complete.
 * });
 *
 * //-
 * // Be sure to register an error handler as well to catch any issues which
 * // impeded the job.
 * //-
 * job.on('error', function(err) {
 *   // An error occurred during the job.
 * });
 *
 * //-
 * // To force the Job object to stop polling for updates, simply remove any
 * // "complete" listeners you've registered.
 * //
 * // The easiest way to do this is with `removeAllListeners()`.
 * //-
 * job.removeAllListeners();
 */
function Job(bigQuery, id) {
  var methods = {
    /**
     * Check if the job exists.
     *
     * @param {function} callback - The callback function.
     * @param {?error} callback.err - An error returned while making this
     *     request.
     * @param {boolean} callback.exists - Whether the job exists or not.
     *
     * @example
     * job.exists(function(err, exists) {});
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.exists().then(function(data) {
     *   var exists = data[0];
     * });
     */
    exists: true,

    /**
     * Get a job if it exists.
     *
     * @example
     * job.get(function(err, job, apiResponse) {
     *   if (!err) {
     *     // `job.metadata` has been populated.
     *   }
     * });
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.get().then(function(data) {
     *   var job = data[0];
     *   var apiResponse = data[1];
     * });
     */
    get: true,

    /**
     * Get the metadata of the job. This will mostly be useful for checking the
     * status of a previously-run job.
     *
     * @resource [Jobs: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/get}
     *
     * @param {function} callback - The callback function.
     * @param {?error} callback.err - An error returned while making this
     *     request.
     * @param {object} callback.metadata - The metadata of the job.
     * @param {object} callback.apiResponse - The full API response.
     *
     * @example
     * var job = bigquery.job('id');
     * job.getMetadata(function(err, metadata, apiResponse) {});
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.getMetadata().then(function(data) {
     *   var metadata = data[0];
     *   var apiResponse = data[1];
     * });
     */
    getMetadata: true,

    /**
     * Set the metadata for this job. This can be useful for updating job
     * labels.
     *
     * @resource [Jobs: patch API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/patch}
     *
     * @param {object} metadata - Metadata to save on the Job.
     * @param {function} callback - The callback function.
     * @param {?error} callback.err - An error returned while making this
     *     request.
     * @param {object} callback.apiResponse - The full API response.
     *
     * @example
     * var metadata = {
     *   configuration: {
     *     labels: {
     *       foo: 'bar'
     *     }
     *   }
     * };
     *
     * job.setMetadata(metadata, function(err, apiResponse) {});
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * job.setMetadata(metadata).then(function(data) {
     *   var apiResponse = data[0];
     * });
     */
    setMetadata: true,
  };

  common.Operation.call(this, {
    parent: bigQuery,
    baseUrl: '/jobs',
    id: id,
    methods: methods,
  });

  this.bigQuery = bigQuery;

  // The API endpoint for cancel is:    .../bigquery/v2/project/projectId/...
  // The rest of the API endpoints are: .../bigquery/v2/projects/projectId/...
  // Reference: https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1027
  this.interceptors.push({
    request: function(reqOpts) {
      if (reqOpts.uri.indexOf('/cancel') > -1) {
        reqOpts.uri = reqOpts.uri.replace('/projects/', '/project/');
      }
      return reqOpts;
    },
  });
}

util.inherits(Job, common.Operation);

/**
 * Cancel a job. Use {module:bigquery/job#getMetadata} to see if the cancel
 * completes successfully. See an example implementation below.
 *
 * @resource [Jobs: get API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/cancel}
 *
 * @param {function=} callback - The callback function.
 * @param {?error} callback.err - An error returned while making this request.
 * @param {object} callback.apiResponse - The full API response.
 *
 * @example
 * job.cancel(function(err, apiResponse) {
 *   // Check to see if the job completes successfully.
 *   job.on('error', function(err) {});
 *   job.on('complete', function(metadata) {});
 * });
 *
 * //-
 * // If the callback is omitted, we'll return a Promise.
 * //-
 * job.cancel().then(function(data) {
 *   var apiResponse = data[0];
 * });
 */
Job.prototype.cancel = function(callback) {
  callback = callback || common.util.noop;

  this.request(
    {
      method: 'POST',
      uri: '/cancel',
    },
    function(err, resp) {
      callback(err, resp);
    }
  );
};

/**
 * Get the results of a job.
 *
 * @resource [Jobs: getQueryResults API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/getQueryResults}
 *
 * @param {object=} options - Configuration object.
 * @param {boolean} options.autoPaginate - Have pagination handled
 *     automatically. Default: true.
 * @param {number} options.maxApiCalls - Maximum number of API calls to make.
 * @param {number} options.maxResults - Maximum number of results to read.
 * @param {string} options.pageToken - Page token, returned by a previous call,
 *     to request the next page of results. Note: This is automatically added to
 *     the `nextQuery` argument of your callback.
 * @param {number} options.startIndex - Zero-based index of the starting row.
 * @param {number} options.timeoutMs - How long to wait for the query to
 *     complete, in milliseconds, before returning. Default is to return
 *     immediately. If the timeout passes before the job completes, the request
 *     will fail with a `TIMEOUT` error.
 * @param {function=} callback - The callback function. If you intend to
 *     continuously run this query until all results are in as part of a stream,
 *     do not pass a callback.
 * @param {?error} callback.err - An error returned while making this request
 * @param {array} callback.rows - The results of a job.
 *
 * @example
 * //-
 * // Get all of the results of a query.
 * //-
 * job.getQueryResults(function(err, rows) {
 *   if (!err) {
 *     // rows is an array of results.
 *   }
 * });
 *
 * //-
 * // Customize the results you want to fetch.
 * //-
 * job.getQueryResults({
 *   maxResults: 100
 * }, function(err, rows) {});
 *
 * //-
 * // To control how many API requests are made and page through the results
 * // manually, set `autoPaginate` to `false`.
 * //-
 * function manualPaginationCallback(err, rows, nextQuery, apiResponse) {
 *   if (nextQuery) {
 *     // More results exist.
 *     job.getQueryResults(nextQuery, manualPaginationCallback);
 *   }
 * }
 *
 * job.getQueryResults({
 *   autoPaginate: false
 * }, manualPaginationCallback);
 *
 * //-
 * // If the callback is omitted, we'll return a Promise.
 * //-
 * job.getQueryResults().then(function(data) {
 *   var rows = data[0];
 * });
 */
Job.prototype.getQueryResults = function(options, callback) {
  var self = this;

  if (is.fn(options)) {
    callback = options;
    options = {};
  }

  this.bigQuery.request(
    {
      uri: '/queries/' + this.id,
      qs: options,
    },
    function(err, resp) {
      if (err) {
        callback(err, null, null, resp);
        return;
      }

      var rows = [];

      if (resp.schema && resp.rows) {
        rows = self.bigQuery.mergeSchemaWithRows_(resp.schema, resp.rows);
      }

      var nextQuery = null;
      if (resp.jobComplete === false) {
        // Query is still running.
        nextQuery = extend({}, options);
      } else if (resp.pageToken) {
        // More results exist.
        nextQuery = extend({}, options, {
          pageToken: resp.pageToken,
        });
      }

      callback(null, rows, nextQuery, resp);
    }
  );
};

/**
 * Get the results of a job as a readable object stream.
 *
 * @param {object=} options - Configuration object. See
 *     {module:bigquery/job#getQueryResults} for a complete list of options.
 * @return {stream}
 *
 * @example
 * var through2 = require('through2');
 * var fs = require('fs');
 *
 * job.getQueryResultsStream()
 *   .pipe(through2.obj(function (row, enc, next) {
 *     this.push(JSON.stringify(row) + '\n');
 *     next();
 *   }))
 *   .pipe(fs.createWriteStream('./test/testdata/testfile.json'));
 */
Job.prototype.getQueryResultsStream = common.paginator.streamify(
  'getQueryResults'
);

/**
 * Poll for a status update. Execute the callback:
 *
 *   - callback(err): Job failed
 *   - callback(): Job incomplete
 *   - callback(null, metadata): Job complete
 *
 * @private
 *
 * @param {function} callback
 */
Job.prototype.poll_ = function(callback) {
  this.getMetadata(function(err, metadata, apiResponse) {
    if (!err && apiResponse.status && apiResponse.status.errors) {
      err = new common.util.ApiError(apiResponse.status);
    }

    if (err) {
      callback(err);
      return;
    }

    if (metadata.status.state !== 'DONE') {
      callback();
      return;
    }

    callback(null, metadata);
  });
};

/*! Developer Documentation
 *
 * These methods can be auto-paginated.
 */
common.paginator.extend(Job, ['getQueryResults']);

/*! Developer Documentation
 *
 * All async methods (except for streams) will return a Promise in the event
 * that a callback is omitted.
 */
common.util.promisifyAll(Job);

module.exports = Job;
<|endoftext|>


<commit_before>/* jshint camelcase:false */
//@exclude
'use strict';
//@endexclude

(function() {

    var jwt = corbel.jwt = {

        EXPIRATION: 3500,
        ALGORITHM: 'HS256',
        TYP: 'JWT',
        VERSION: '1.0.0',

        /**
         * JWT-HmacSHA256 generator
         * http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html
         * @param  {Object}                                 claims Specific claims to include in the JWT (iss, aud, exp, scope, ...)
         * @param  {String} secret                          String with the client assigned secret
         * @param  {Object} [alg='corbel.jwt.ALGORITHM']    Object with the algorithm type
         * @return {String} jwt                             JWT string
         */
        generate: function(claims, secret, alg) {
            claims = claims || {};
            alg = alg || jwt.ALGORITHM;

            claims.exp = claims.exp || jwt._generateExp();

            if (!claims.iss) {
                throw new Error('jwt:undefined:iss');
            }
            if (!claims.aud) {
                throw new Error('jwt:undefined:aud');
            }
            if (!claims.scope) {
                throw new Error('jwt:undefined:scope');
            }

            // Ensure claims specific order
            var claimsKeys = [
                'iss',
                'aud',
                'exp',
                'scope',
                'prn',
                'version',
                'refresh_token',
                'request_domain',

                'basic_auth.username',
                'basic_auth.password',

                'device_id'
            ];

            var finalClaims = {};
            claimsKeys.forEach(function(key) {
                if (claims[key]) {
                    finalClaims[key] = claims[key];
                }
            });

            corbel.utils.extend(finalClaims, claims);

            if (Array.isArray(finalClaims.scope)) {
                finalClaims.scope = finalClaims.scope.join(' ');
            }

            var bAlg = corbel.cryptography.rstr2b64(corbel.cryptography.str2rstr_utf8(JSON.stringify({
                    typ: jwt.TYP,
                    alg: alg
                }))),
                bClaims = corbel.cryptography.rstr2b64(corbel.cryptography.str2rstr_utf8(JSON.stringify(finalClaims))),
                segment = bAlg + '.' + bClaims,
                assertion = corbel.cryptography.b64tob64u(corbel.cryptography.b64_hmac_sha256(secret, segment));

            return segment + '.' + assertion;
        },

        _generateExp: function() {
            return Math.round((new Date().getTime() / 1000)) + jwt.EXPIRATION;
        },

        decode: function(assertion) {
            var serialize;
            if (!root.atob) {
                // node environment
                serialize = require('atob');
            } else {
                serialize = root.atob;
            }
            var decoded = assertion.split('.');
            return [JSON.parse(serialize(decoded[0])), JSON.parse(serialize(decoded[1]))];
        }

    };

    return jwt;

})();
<commit_msg>fallback for second member decode<commit_after>/* jshint camelcase:false */
//@exclude
'use strict';
//@endexclude

(function() {

    var jwt = corbel.jwt = {

        EXPIRATION: 3500,
        ALGORITHM: 'HS256',
        TYP: 'JWT',
        VERSION: '1.0.0',

        /**
         * JWT-HmacSHA256 generator
         * http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html
         * @param  {Object}                                 claims Specific claims to include in the JWT (iss, aud, exp, scope, ...)
         * @param  {String} secret                          String with the client assigned secret
         * @param  {Object} [alg='corbel.jwt.ALGORITHM']    Object with the algorithm type
         * @return {String} jwt                             JWT string
         */
        generate: function(claims, secret, alg) {
            claims = claims || {};
            alg = alg || jwt.ALGORITHM;

            claims.exp = claims.exp || jwt._generateExp();

            if (!claims.iss) {
                throw new Error('jwt:undefined:iss');
            }
            if (!claims.aud) {
                throw new Error('jwt:undefined:aud');
            }
            if (!claims.scope) {
                throw new Error('jwt:undefined:scope');
            }

            // Ensure claims specific order
            var claimsKeys = [
                'iss',
                'aud',
                'exp',
                'scope',
                'prn',
                'version',
                'refresh_token',
                'request_domain',

                'basic_auth.username',
                'basic_auth.password',

                'device_id'
            ];

            var finalClaims = {};
            claimsKeys.forEach(function(key) {
                if (claims[key]) {
                    finalClaims[key] = claims[key];
                }
            });

            corbel.utils.extend(finalClaims, claims);

            if (Array.isArray(finalClaims.scope)) {
                finalClaims.scope = finalClaims.scope.join(' ');
            }

            var bAlg = corbel.cryptography.rstr2b64(corbel.cryptography.str2rstr_utf8(JSON.stringify({
                    typ: jwt.TYP,
                    alg: alg
                }))),
                bClaims = corbel.cryptography.rstr2b64(corbel.cryptography.str2rstr_utf8(JSON.stringify(finalClaims))),
                segment = bAlg + '.' + bClaims,
                assertion = corbel.cryptography.b64tob64u(corbel.cryptography.b64_hmac_sha256(secret, segment));

            return segment + '.' + assertion;
        },

        _generateExp: function() {
            return Math.round((new Date().getTime() / 1000)) + jwt.EXPIRATION;
        },

        decode: function(assertion) {
            var serialize;
            if (!root.atob) {
                // node environment
                serialize = require('atob');
            } else {
                serialize = root.atob;
            }
            var decoded = assertion.split('.');
            decoded[0] = JSON.parse(serialize(decoded[0]));
            try {
                decoded[1] = JSON.parse(serialize(decoded[1]));
            } catch (e) {
                decoded[1] = {};
            }
            return [decoded[0], decoded[1]];
        }

    };

    return jwt;

})();
<|endoftext|>


<commit_before>require.config({
    baseUrl: '/build',
    paths: {
        // Modules
        "util": "util",
        "downloads": "downloads",
        "apiclient": "apiclient",
        "main": "main",
        "oauth": "oauth",
        "models": "models",
        "notifications": "notifications",
        "cache": "cache",

        // Modules to test the app
        "test": "../test/test",
        "test-react": "../test/test-react",
        "sinon": "../test/sinon-1.1.0.3",

        // Third party libs
        "react": "../bower_components/react/react-with-addons",
        //"react": "../bower_components/react/react-with-addons.min",
        "underscore": "../bower_components/underscore/underscore-min",
        "jquery": "../bower_components/jquery/dist/jquery.min",
        "backbone": "../bower_components/backbone/backbone",
        "perseus": "../webapp/javascript/perseus-package/perseus-2",
        "katex": "../bower_components/katex/build/katex.min",
        "videojs": "../bower_components/videojs/dist/video-js/video",
        "kas": "../bower_components/KAS/kas",
        "mathjax": "../bower_components/MathJax/MathJax",

        // Views
        "article": "./views/article",
        "exercise": "./views/exercise",
        "chrome": "./views/chrome",
        "search": "./views/search",
        "topic": "./views/topic",
        "video": "./views/video",
        "pane": "./views/pane",
    },
    shim: {
        jquery: {
          exports: '$'
        },
        underscore: {
          deps: ["jquery"],
          exports: '_'
        },
        kas: {
            exports: 'KAS'
        },
        katex: {
          exports: 'katex'
        },
        perseus: {
            deps: ["react", "katex", "jquery"],
        },
        backbone: {
          deps:["underscore", "jquery"],
          exports: 'Backbone'
        },
        videojs: {
          exports: 'videojs'
        },
        mathjax: {
          exports: 'MathJax'
        },
        waitSeconds: 15
   }

});

// Uncomment to visually test localization.
// Replaces all localized strings with boxes.
//window.translateToBoxes = true;

var initModules = [];
if (window.isTest) {
    initModules.push('test-react');
    initModules.push('test');
    initModules.push('sinon');
} else {
    initModules.push('main');
}

window.Exercises = {
    cluesEnabled: false
};

// Localization shim within perseus, we want to do nothing for it
// since we aren't repsonsible for its localization
//$._ = function(x) { return x; };

requirejs(initModules);
<commit_msg>Remove unused commented code<commit_after>require.config({
    baseUrl: '/build',
    paths: {
        // Modules
        "util": "util",
        "downloads": "downloads",
        "apiclient": "apiclient",
        "main": "main",
        "oauth": "oauth",
        "models": "models",
        "notifications": "notifications",
        "cache": "cache",

        // Modules to test the app
        "test": "../test/test",
        "test-react": "../test/test-react",
        "sinon": "../test/sinon-1.1.0.3",

        // Third party libs
        "react": "../bower_components/react/react-with-addons",
        //"react": "../bower_components/react/react-with-addons.min",
        "underscore": "../bower_components/underscore/underscore-min",
        "jquery": "../bower_components/jquery/dist/jquery.min",
        "backbone": "../bower_components/backbone/backbone",
        "perseus": "../webapp/javascript/perseus-package/perseus-2",
        "katex": "../bower_components/katex/build/katex.min",
        "videojs": "../bower_components/videojs/dist/video-js/video",
        "kas": "../bower_components/KAS/kas",
        "mathjax": "../bower_components/MathJax/MathJax",

        // Views
        "article": "./views/article",
        "exercise": "./views/exercise",
        "chrome": "./views/chrome",
        "search": "./views/search",
        "topic": "./views/topic",
        "video": "./views/video",
        "pane": "./views/pane",
    },
    shim: {
        jquery: {
          exports: '$'
        },
        underscore: {
          deps: ["jquery"],
          exports: '_'
        },
        kas: {
            exports: 'KAS'
        },
        katex: {
          exports: 'katex'
        },
        perseus: {
            deps: ["react", "katex", "jquery"],
        },
        backbone: {
          deps:["underscore", "jquery"],
          exports: 'Backbone'
        },
        videojs: {
          exports: 'videojs'
        },
        mathjax: {
          exports: 'MathJax'
        },
        waitSeconds: 15
   }

});

// Uncomment to visually test localization.
// Replaces all localized strings with boxes.
//window.translateToBoxes = true;

var initModules = [];
if (window.isTest) {
    initModules.push('test-react');
    initModules.push('test');
    initModules.push('sinon');
} else {
    initModules.push('main');
}

window.Exercises = {
    cluesEnabled: false
};

requirejs(initModules);
<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');

require('colors')
const _ = require('lodash');
const ask = require('inquirer');
const mkdirp = require('mkdirp');
const mongoose = require('mongoose');
const Promise = require('bluebird');

const MigrationModelFactory = require('./db');
let MigrationModel;

Promise.config({
  warnings: false
});

const migrationTemplate =`/**
 * Make any changes you need to make to the database here
 */
async function up () {
  // Write migration here
}

/**
 * Make any changes that UNDO the up function side effects here (if possible)
 */
async function down () {
  // Write migration here
}

module.exports = { up, down };
`;

class Migrator {
  constructor({
    templatePath,
    migrationsPath = './migrations',
    dbConnectionUri,
    collectionName = 'migrations',
    autosync = false,
    cli = false,
    connection
  }) {
    const defaultTemplate = migrationTemplate;
    this.template = templatePath ? fs.readFileSync(templatePath, 'utf-8') : defaultTemplate;
    this.migrationPath = path.resolve(migrationsPath);
    this.connection = connection || mongoose.createConnection(dbConnectionUri, { useNewUrlParser: true });
    this.collection = collectionName;
    this.autosync = autosync;
    this.cli = cli;
    MigrationModel = MigrationModelFactory(collectionName, this.connection);
  }

  log(logString, force = false) {
    if (force || this.cli) {
      console.log(logString);
    }
  }

  /**
   * Use your own Mongoose connection object (so you can use this('modelname')
   * @param {mongoose.connection} connection - Mongoose connection
   */
  setMongooseConnection(connection) {
    MigrationModel = MigrationModelFactory(this.collection, connection)
    return this
  }

  /**
   * Close the underlying connection to mongo
   * @returns {Promise} A promise that resolves when connection is closed
   */
  close() {
    return this.connection ? this.connection.close() : Promise.resolve();
  }

  /**
   * Create a new migration
   * @param {string} migrationName
   * @returns {Promise<Object>} A promise of the Migration created
   */
  async create(migrationName) {
    try {
      const existingMigration = await MigrationModel.findOne({ name: migrationName });
      if (!!existingMigration) {
        throw new Error(`There is already a migration with name '${migrationName}' in the database`.red);
      }

      await this.sync();
      const now = Date.now();
      const newMigrationFile = `${now}-${migrationName}.js`;
      mkdirp.sync(this.migrationPath);
      fs.writeFileSync(path.join(this.migrationPath, newMigrationFile), this.template);
      // create instance in db
      await this.connection;
      const migrationCreated = await MigrationModel.create({
        name: migrationName,
        createdAt: now
      });
      this.log(`Created migration ${migrationName} in ${this.migrationPath}.`);
      return migrationCreated;
    } catch (error) {
      this.log(error.stack);
      fileRequired(error);
    }
  }

  /**
   * Runs migrations up to or down to a given migration name
   *
   * @param migrationName
   * @param direction
   */
  async run(direction = 'up', migrationName) {
    await this.sync();

    if (direction !== 'up' && direction !== 'down') {
      throw new Error(`The '${direction}' is not supported, use the 'up' or 'down' direction`);
    }

    const untilMigration = migrationName ?
      await MigrationModel.findOne({ name: migrationName }) :
      await MigrationModel.findOne().sort({ createdAt: direction === 'up' ? -1 : 1 });

    if (!untilMigration) {
      if (migrationName) throw new ReferenceError("Could not find that migration in the database");
      else throw new Error("There are no pending migrations.");
    }

    let query = {
      createdAt: { $lte: untilMigration.createdAt },
      state: 'down'
    };

    if (direction == 'down') {
      query = {
        createdAt: { $gte: untilMigration.createdAt },
        state: 'up'
      };
    }

    const sortDirection = direction == 'up' ? 1 : -1;
    const migrationsToRun = await MigrationModel.find(query)
      .sort({ createdAt: sortDirection });

    if (!migrationsToRun.length) {
      if (this.cli) {
        this.log('There are no migrations to run'.yellow);
        this.log(`Current Migrations' Statuses: `);
        await this.list();
      }
    }

    let self = this;
    let numMigrationsRan = 0;
    let migrationsRan = [];

    for (const migration of migrationsToRun) {
      const migrationFilePath = path.join(self.migrationPath, migration.filename);
      let migrationFunctions;
      migrationFunctions = require(migrationFilePath);

      if (!migrationFunctions[direction]) {
        throw new Error(`The "${direction}" export is not defined in ${migration.filename}.`.red);
      }

      try {
        await new Promise((resolve, reject) => {
          const callPromise = migrationFunctions[direction].call(
            this.connection.model.bind(this.connection),
            function callback(err) {
              if (err) return reject(err);
              resolve();
            }
          );

          if (callPromise && typeof callPromise.then === 'function') {
            callPromise.then(resolve).catch(reject);
          }
        });

        this.log(`${direction.toUpperCase()}:   `[direction == 'up' ? 'green' : 'red'] + ` ${migration.filename} `);

        await MigrationModel.where({ name: migration.name }).updateMany({ $set: { state: direction } });
        migrationsRan.push(migration.toJSON());
        numMigrationsRan++;
      } catch (err) {
        this.log(`Failed to run migration ${migration.name} due to an error.`.red);
        this.log(`Not continuing. Make sure your data is in consistent state`.red);
        throw err instanceof (Error) ? err : new Error(err);
      }
    }

    if (migrationsToRun.length == numMigrationsRan && numMigrationsRan > 0) this.log('All migrations finished successfully.'.green);
    return migrationsRan;
  }

  /**
   * sync file system -> database
   *
   * Imports any migrations that are on the file system but
   * missing in the database into the database
   *
   * This functionality is opposite of prune()
   */
  async sync() {
    try {
      const filesInMigrationFolder = fs.readdirSync(this.migrationPath);
      const migrationsInDatabase = await MigrationModel.find({});
      // Go over migrations in folder and delete any files not in DB
      const migrationsInFolder = _.filter(filesInMigrationFolder, file => /\d{13,}\-.+.js$/.test(file))
        .map(filename => {
          const fileCreatedAt = parseInt(filename.split('-')[0]);
          const existsInDatabase = migrationsInDatabase.some(m => filename == m.filename);
          return { createdAt: fileCreatedAt, filename, existsInDatabase };
        });

      const filesNotInDb = _.filter(migrationsInFolder, { existsInDatabase: false }).map(f => f.filename);
      let migrationsToImport = filesNotInDb;
      this.log('Synchronizing database with file system migrations...');
      if (!this.autosync && migrationsToImport.length) {
        const answers = await new Promise(function (resolve) {
          ask.prompt({
            type: 'checkbox',
            message: 'The following migrations exist in the migrations folder but not in the database. Select the ones you want to import into the database',
            name: 'migrationsToImport',
            choices: filesNotInDb
          }, (answers) => {
            resolve(answers);
          });
        });

        migrationsToImport = answers.migrationsToImport;
      }

      return Promise.map(migrationsToImport, async (migrationToImport) => {
        const filePath = path.join(this.migrationPath, migrationToImport),
          timestampSeparatorIndex = migrationToImport.indexOf('-'),
          timestamp = migrationToImport.slice(0, timestampSeparatorIndex),
          migrationName = migrationToImport.slice(timestampSeparatorIndex + 1, migrationToImport.lastIndexOf('.'));

        this.log(`Adding migration ${filePath} into database from file system. State is ` + `DOWN`.red);
        const createdMigration = await MigrationModel.create({
          name: migrationName,
          createdAt: timestamp
        });
        return createdMigration.toJSON();
      });
    } catch (error) {
      this.log(`Could not synchronise migrations in the migrations folder up to the database.`.red);
      throw error;
    }
  }

  /**
   * sync migration database -> file system
   *
   * Opposite of sync().
   * Removes files in migration directory which don't exist in database.
   */
  async prune() {
    try {
      const filesInMigrationFolder = fs.readdirSync(this.migrationPath);
      const migrationsInDatabase = await MigrationModel.find({});
      // Go over migrations in folder and delete any files not in DB
      const migrationsInFolder = _.filter(filesInMigrationFolder, file => /\d{13,}\-.+.js/.test(file))
        .map(filename => {
          const fileCreatedAt = parseInt(filename.split('-')[0]);
          const existsInDatabase = migrationsInDatabase.some(m => filename == m.filename);
          return { createdAt: fileCreatedAt, filename, existsInDatabase };
        });

      const dbMigrationsNotOnFs = _.filter(migrationsInDatabase, m => {
        return !_.find(migrationsInFolder, { filename: m.filename })
      });

      let migrationsToDelete = dbMigrationsNotOnFs.map(m => m.name);

      if (!this.autosync && !!migrationsToDelete.length) {
        const answers = await new Promise(function (resolve) {
          ask.prompt({
            type: 'checkbox',
            message: 'The following migrations exist in the database but not in the migrations folder. Select the ones you want to remove from the file system.',
            name: 'migrationsToDelete',
            choices: migrationsToDelete
          }, (answers) => {
            resolve(answers);
          });
        });

        migrationsToDelete = answers.migrationsToDelete;
      }

      const migrationsToDeleteDocs = await MigrationModel
        .find({
          name: { $in: migrationsToDelete }
        }).lean();

      if (migrationsToDelete.length) {
        this.log(`Removing migration(s) `, `${migrationsToDelete.join(', ')}`.cyan, ` from database`);
        await MigrationModel.deleteMany({
          name: { $in: migrationsToDelete }
        });
      }

      return migrationsToDeleteDocs;
    } catch (error) {
      this.log(`Could not prune extraneous migrations from database.`.red);
      throw error;
    }
  }

  /**
   * Lists the current migrations and their statuses
   * @returns {Promise<Array<Object>>}
   * @example
   *   [
   *    { name: 'my-migration', filename: '149213223424_my-migration.js', state: 'up' },
   *    { name: 'add-cows', filename: '149213223453_add-cows.js', state: 'down' }
   *   ]
   */
  async list() {
    await this.sync();
    const migrations = await MigrationModel.find().sort({ createdAt: 1 });
    if (!migrations.length) this.log('There are no migrations to list.'.yellow);
    return migrations.map((m) => {
      this.log(
        `${m.state == 'up' ? 'UP:  \t' : 'DOWN:\t'}`[m.state == 'up' ? 'green' : 'red'] +
        ` ${m.filename}`
      );
      return m.toJSON();
    });
  }
}

function fileRequired(error) {
  if (error && error.code == 'ENOENT') {
    throw new ReferenceError(`Could not find any files at path '${error.path}'`);
  }
}

module.exports = Migrator;

<commit_msg>Pass additional run args onto migration functions<commit_after>const fs = require('fs');
const path = require('path');

require('colors')
const _ = require('lodash');
const ask = require('inquirer');
const mkdirp = require('mkdirp');
const mongoose = require('mongoose');
const Promise = require('bluebird');

const MigrationModelFactory = require('./db');
let MigrationModel;

Promise.config({
  warnings: false
});

const migrationTemplate =`/**
 * Make any changes you need to make to the database here
 */
async function up () {
  // Write migration here
}

/**
 * Make any changes that UNDO the up function side effects here (if possible)
 */
async function down () {
  // Write migration here
}

module.exports = { up, down };
`;

class Migrator {
  constructor({
    templatePath,
    migrationsPath = './migrations',
    dbConnectionUri,
    collectionName = 'migrations',
    autosync = false,
    cli = false,
    connection
  }) {
    const defaultTemplate = migrationTemplate;
    this.template = templatePath ? fs.readFileSync(templatePath, 'utf-8') : defaultTemplate;
    this.migrationPath = path.resolve(migrationsPath);
    this.connection = connection || mongoose.createConnection(dbConnectionUri, { useNewUrlParser: true });
    this.collection = collectionName;
    this.autosync = autosync;
    this.cli = cli;
    MigrationModel = MigrationModelFactory(collectionName, this.connection);
  }

  log(logString, force = false) {
    if (force || this.cli) {
      console.log(logString);
    }
  }

  /**
   * Use your own Mongoose connection object (so you can use this('modelname')
   * @param {mongoose.connection} connection - Mongoose connection
   */
  setMongooseConnection(connection) {
    MigrationModel = MigrationModelFactory(this.collection, connection)
    return this
  }

  /**
   * Close the underlying connection to mongo
   * @returns {Promise} A promise that resolves when connection is closed
   */
  close() {
    return this.connection ? this.connection.close() : Promise.resolve();
  }

  /**
   * Create a new migration
   * @param {string} migrationName
   * @returns {Promise<Object>} A promise of the Migration created
   */
  async create(migrationName) {
    try {
      const existingMigration = await MigrationModel.findOne({ name: migrationName });
      if (!!existingMigration) {
        throw new Error(`There is already a migration with name '${migrationName}' in the database`.red);
      }

      await this.sync();
      const now = Date.now();
      const newMigrationFile = `${now}-${migrationName}.js`;
      mkdirp.sync(this.migrationPath);
      fs.writeFileSync(path.join(this.migrationPath, newMigrationFile), this.template);
      // create instance in db
      await this.connection;
      const migrationCreated = await MigrationModel.create({
        name: migrationName,
        createdAt: now
      });
      this.log(`Created migration ${migrationName} in ${this.migrationPath}.`);
      return migrationCreated;
    } catch (error) {
      this.log(error.stack);
      fileRequired(error);
    }
  }

  /**
   * Runs migrations up to or down to a given migration name
   *
   * @param migrationName
   * @param direction
   */
  async run(direction = 'up', migrationName, ...args) {
    await this.sync();

    if (direction !== 'up' && direction !== 'down') {
      throw new Error(`The '${direction}' is not supported, use the 'up' or 'down' direction`);
    }

    const untilMigration = migrationName ?
      await MigrationModel.findOne({ name: migrationName }) :
      await MigrationModel.findOne().sort({ createdAt: direction === 'up' ? -1 : 1 });

    if (!untilMigration) {
      if (migrationName) throw new ReferenceError("Could not find that migration in the database");
      else throw new Error("There are no pending migrations.");
    }

    let query = {
      createdAt: { $lte: untilMigration.createdAt },
      state: 'down'
    };

    if (direction == 'down') {
      query = {
        createdAt: { $gte: untilMigration.createdAt },
        state: 'up'
      };
    }

    const sortDirection = direction == 'up' ? 1 : -1;
    const migrationsToRun = await MigrationModel.find(query)
      .sort({ createdAt: sortDirection });

    if (!migrationsToRun.length) {
      if (this.cli) {
        this.log('There are no migrations to run'.yellow);
        this.log(`Current Migrations' Statuses: `);
        await this.list();
      }
    }

    let self = this;
    let numMigrationsRan = 0;
    let migrationsRan = [];

    for (const migration of migrationsToRun) {
      const migrationFilePath = path.join(self.migrationPath, migration.filename);
      let migrationFunctions;
      migrationFunctions = require(migrationFilePath);

      if (!migrationFunctions[direction]) {
        throw new Error(`The "${direction}" export is not defined in ${migration.filename}.`.red);
      }

      try {
        await new Promise((resolve, reject) => {
          const callPromise = migrationFunctions[direction].call(
            this.connection.model.bind(this.connection),
            function callback(err) {
              if (err) return reject(err);
              resolve();
            },
            ...args
          );

          if (callPromise && typeof callPromise.then === 'function') {
            callPromise.then(resolve).catch(reject);
          }
        });

        this.log(`${direction.toUpperCase()}:   `[direction == 'up' ? 'green' : 'red'] + ` ${migration.filename} `);

        await MigrationModel.where({ name: migration.name }).updateMany({ $set: { state: direction } });
        migrationsRan.push(migration.toJSON());
        numMigrationsRan++;
      } catch (err) {
        this.log(`Failed to run migration ${migration.name} due to an error.`.red);
        this.log(`Not continuing. Make sure your data is in consistent state`.red);
        throw err instanceof (Error) ? err : new Error(err);
      }
    }

    if (migrationsToRun.length == numMigrationsRan && numMigrationsRan > 0) this.log('All migrations finished successfully.'.green);
    return migrationsRan;
  }

  /**
   * sync file system -> database
   *
   * Imports any migrations that are on the file system but
   * missing in the database into the database
   *
   * This functionality is opposite of prune()
   */
  async sync() {
    try {
      const filesInMigrationFolder = fs.readdirSync(this.migrationPath);
      const migrationsInDatabase = await MigrationModel.find({});
      // Go over migrations in folder and delete any files not in DB
      const migrationsInFolder = _.filter(filesInMigrationFolder, file => /\d{13,}\-.+.js$/.test(file))
        .map(filename => {
          const fileCreatedAt = parseInt(filename.split('-')[0]);
          const existsInDatabase = migrationsInDatabase.some(m => filename == m.filename);
          return { createdAt: fileCreatedAt, filename, existsInDatabase };
        });

      const filesNotInDb = _.filter(migrationsInFolder, { existsInDatabase: false }).map(f => f.filename);
      let migrationsToImport = filesNotInDb;
      this.log('Synchronizing database with file system migrations...');
      if (!this.autosync && migrationsToImport.length) {
        const answers = await new Promise(function (resolve) {
          ask.prompt({
            type: 'checkbox',
            message: 'The following migrations exist in the migrations folder but not in the database. Select the ones you want to import into the database',
            name: 'migrationsToImport',
            choices: filesNotInDb
          }, (answers) => {
            resolve(answers);
          });
        });

        migrationsToImport = answers.migrationsToImport;
      }

      return Promise.map(migrationsToImport, async (migrationToImport) => {
        const filePath = path.join(this.migrationPath, migrationToImport),
          timestampSeparatorIndex = migrationToImport.indexOf('-'),
          timestamp = migrationToImport.slice(0, timestampSeparatorIndex),
          migrationName = migrationToImport.slice(timestampSeparatorIndex + 1, migrationToImport.lastIndexOf('.'));

        this.log(`Adding migration ${filePath} into database from file system. State is ` + `DOWN`.red);
        const createdMigration = await MigrationModel.create({
          name: migrationName,
          createdAt: timestamp
        });
        return createdMigration.toJSON();
      });
    } catch (error) {
      this.log(`Could not synchronise migrations in the migrations folder up to the database.`.red);
      throw error;
    }
  }

  /**
   * sync migration database -> file system
   *
   * Opposite of sync().
   * Removes files in migration directory which don't exist in database.
   */
  async prune() {
    try {
      const filesInMigrationFolder = fs.readdirSync(this.migrationPath);
      const migrationsInDatabase = await MigrationModel.find({});
      // Go over migrations in folder and delete any files not in DB
      const migrationsInFolder = _.filter(filesInMigrationFolder, file => /\d{13,}\-.+.js/.test(file))
        .map(filename => {
          const fileCreatedAt = parseInt(filename.split('-')[0]);
          const existsInDatabase = migrationsInDatabase.some(m => filename == m.filename);
          return { createdAt: fileCreatedAt, filename, existsInDatabase };
        });

      const dbMigrationsNotOnFs = _.filter(migrationsInDatabase, m => {
        return !_.find(migrationsInFolder, { filename: m.filename })
      });

      let migrationsToDelete = dbMigrationsNotOnFs.map(m => m.name);

      if (!this.autosync && !!migrationsToDelete.length) {
        const answers = await new Promise(function (resolve) {
          ask.prompt({
            type: 'checkbox',
            message: 'The following migrations exist in the database but not in the migrations folder. Select the ones you want to remove from the file system.',
            name: 'migrationsToDelete',
            choices: migrationsToDelete
          }, (answers) => {
            resolve(answers);
          });
        });

        migrationsToDelete = answers.migrationsToDelete;
      }

      const migrationsToDeleteDocs = await MigrationModel
        .find({
          name: { $in: migrationsToDelete }
        }).lean();

      if (migrationsToDelete.length) {
        this.log(`Removing migration(s) `, `${migrationsToDelete.join(', ')}`.cyan, ` from database`);
        await MigrationModel.deleteMany({
          name: { $in: migrationsToDelete }
        });
      }

      return migrationsToDeleteDocs;
    } catch (error) {
      this.log(`Could not prune extraneous migrations from database.`.red);
      throw error;
    }
  }

  /**
   * Lists the current migrations and their statuses
   * @returns {Promise<Array<Object>>}
   * @example
   *   [
   *    { name: 'my-migration', filename: '149213223424_my-migration.js', state: 'up' },
   *    { name: 'add-cows', filename: '149213223453_add-cows.js', state: 'down' }
   *   ]
   */
  async list() {
    await this.sync();
    const migrations = await MigrationModel.find().sort({ createdAt: 1 });
    if (!migrations.length) this.log('There are no migrations to list.'.yellow);
    return migrations.map((m) => {
      this.log(
        `${m.state == 'up' ? 'UP:  \t' : 'DOWN:\t'}`[m.state == 'up' ? 'green' : 'red'] +
        ` ${m.filename}`
      );
      return m.toJSON();
    });
  }
}

function fileRequired(error) {
  if (error && error.code == 'ENOENT') {
    throw new ReferenceError(`Could not find any files at path '${error.path}'`);
  }
}

module.exports = Migrator;

<|endoftext|>


<commit_before>"use strict";

var
	path = require('path'),
	dir = require('../lib/dir'),
	fs = require('fs'),
	mkdirp = require('mkdirp'),
	_ = require('lodash'),
	marked = require('marked'),
	parse = require('./parser'),
	compile = require('./compile'),
	symbols = require('./symbols'),
	defaults = require('./defaults');

/**
 * Options & Defaults
 */
var ignoredDirs = defaults.ignoredDirs,
	pkg = defaults.pkg,
	target_extension = defaults.target_extension;

module.exports = function (options) {

	if (options.target_extension) {
		target_extension = options.target_extension;
	}

	if (options.template) {
		compile.tpl = fs.readFileSync(options.template).toString();
		compile.tplFileName = options.template;
	}

	if (!options.source) {
		console.error("  Error you must define a source\n");
		return;
	}

	var target, ignore;
	if (!options.target) {
		target = process.cwd() + '/docs';
	} else {
		target = path.resolve(process.cwd(), options.target) || process.cwd() + '/docs';
	}
	ignore = options.ignore || ignoredDirs;

	//Cleanup and turn into an array the ignoredDirs
	ignore = ignore.trim().replace(' ', '').split(',');

	mkdirp.sync(target);

	var source;

	if (options.source instanceof Array) {
		source = options.source;
		//Handle already compiled input
		var files = source.map(function (doc) {
			var targetName = doc.name + '.' + target_extension;
			if (!doc.targetName) doc.targetName = targetName;
			doc.symbols = symbols(doc.dox, doc.targetName);
			return doc;
		});
	} else {
		//Compile files
		//Find, cleanup and validate all potential files
		source = path.resolve(process.cwd(), options.source);
		var files = dir.collectFiles(source, {
			ignore: ignore
		});

		//Parse each file
		files = files.map(function (file) {
			var dox = parse(path.join(source, file), {});
			var targetName = file + '.' + target_extension;
			return {
				name: file.replace(/\\/g, '/'),
				targetName: targetName.replace(/\\/g, '/'),
				dox: dox,
				symbols: symbols(dox, targetName)
			};
		});

	}

	//Compute all symboles
	var allSymbols = files.reduce(function (m, a) {
		m = m.concat(a.symbols || []);
		return m;
	}, []);

	//Get package.json
	try {
		pkg = require(process.cwd() + '/package')
	} catch (err) {}

	var readme = pkg && pkg.readme,
		readMeFile = path.resolve(process.cwd(), options.readme || (pkg && pkg.readmeFileName) || 'README.md')

	if (!readme && fs.existsSync(readMeFile)) {
		readme = fs.readFileSync(readMeFile).toString()
	} else {
		console.warn(new Error('No README.md file found at ' + readMeFile));
	}

	readme = readme || (pkg && pkg.description)

	//Enable line-breaks ala github markdown
	marked.setOptions({
		breaks: true,
		smartLists: true
	})

	//Get readme data
	files.unshift({
		name: "Main",
		targetName: "index.html",
		readme: marked(readme),
		dox: [],
		symbols: []
	});

	//Make sure the folder structure in target mirrors source
	var folders = [];

	files.forEach(function (file) {
		var folder = file.targetName.substr(0, file.targetName.lastIndexOf(path.sep));

		if ((folder !== '') && (folders.indexOf(folder) === -1)) {
			folders.push(folder);
			mkdirp.sync(target + '/' + folder);
		}
	});

	//Render and write each file
	files.forEach(function (file) {

		// Set each files relName in relation to where this file is in the directory tree
		files.forEach(function (f) {

			// Count how deep the current file is in relation to base
			var count = file.name.split('/');
			count = count === null ? 0 : count.length - 1;

			// relName is equal to targetName at the base dir
			f.relName = f.targetName;

			// For each directory in depth of current file add a ../ to the relative filename of this link
			while (count > 0) {
				f.relName = '../' + f.relName;
				count--;
			}

		});

		var title = options.title;

		if (!title) {
			title = pkg && pkg.name || 'Title Not Set'
		}

		var compileOptions = _.extend({}, file, {
			title: title,
			allSymbols: allSymbols,
			files: files,
			currentName: file.name
		});

		var compiled = compile(compileOptions);
		fs.writeFileSync(path.join(target, file.targetName), compiled);
	});

}
<commit_msg>fix(doxx): handle empty README.md, fixes #64<commit_after>"use strict";

var
	path = require('path'),
	dir = require('../lib/dir'),
	fs = require('fs'),
	mkdirp = require('mkdirp'),
	_ = require('lodash'),
	marked = require('marked'),
	parse = require('./parser'),
	compile = require('./compile'),
	symbols = require('./symbols'),
	defaults = require('./defaults');

/**
 * Options & Defaults
 */
var ignoredDirs = defaults.ignoredDirs,
	pkg = defaults.pkg,
	target_extension = defaults.target_extension;

module.exports = function (options) {

	if (options.target_extension) {
		target_extension = options.target_extension;
	}

	if (options.template) {
		compile.tpl = fs.readFileSync(options.template).toString();
		compile.tplFileName = options.template;
	}

	if (!options.source) {
		console.error("  Error you must define a source\n");
		return;
	}

	var target, ignore;
	if (!options.target) {
		target = process.cwd() + '/docs';
	} else {
		target = path.resolve(process.cwd(), options.target) || process.cwd() + '/docs';
	}
	ignore = options.ignore || ignoredDirs;

	//Cleanup and turn into an array the ignoredDirs
	ignore = ignore.trim().replace(' ', '').split(',');

	mkdirp.sync(target);

	var source;

	if (options.source instanceof Array) {
		source = options.source;
		//Handle already compiled input
		var files = source.map(function (doc) {
			var targetName = doc.name + '.' + target_extension;
			if (!doc.targetName) doc.targetName = targetName;
			doc.symbols = symbols(doc.dox, doc.targetName);
			return doc;
		});
	} else {
		//Compile files
		//Find, cleanup and validate all potential files
		source = path.resolve(process.cwd(), options.source);
		var files = dir.collectFiles(source, {
			ignore: ignore
		});

		//Parse each file
		files = files.map(function (file) {
			var dox = parse(path.join(source, file), {});
			var targetName = file + '.' + target_extension;
			return {
				name: file.replace(/\\/g, '/'),
				targetName: targetName.replace(/\\/g, '/'),
				dox: dox,
				symbols: symbols(dox, targetName)
			};
		});

	}

	//Compute all symboles
	var allSymbols = files.reduce(function (m, a) {
		m = m.concat(a.symbols || []);
		return m;
	}, []);

	//Get package.json
	try {
		pkg = require(process.cwd() + '/package')
	} catch (err) {}

	var readme = pkg && pkg.readme,
		readMeFile = path.resolve(process.cwd(), options.readme || (pkg && pkg.readmeFileName) || 'README.md')

	if (!readme && fs.existsSync(readMeFile)) {
		readme = fs.readFileSync(readMeFile).toString()
	} else {
		console.warn(new Error('No README.md file found at ' + readMeFile));
	}

	readme = readme || (pkg && pkg.description)

	if (!readme) {
		console.warn(new Error('Empty README.md ' + readMeFile));
		readme = '';
	}

	//Enable line-breaks ala github markdown
	marked.setOptions({
		breaks: true,
		smartLists: true
	})

	//Get readme data
	files.unshift({
		name: "Main",
		targetName: "index.html",
		readme: marked(readme),
		dox: [],
		symbols: []
	});

	//Make sure the folder structure in target mirrors source
	var folders = [];

	files.forEach(function (file) {
		var folder = file.targetName.substr(0, file.targetName.lastIndexOf(path.sep));

		if ((folder !== '') && (folders.indexOf(folder) === -1)) {
			folders.push(folder);
			mkdirp.sync(target + '/' + folder);
		}
	});

	//Render and write each file
	files.forEach(function (file) {

		// Set each files relName in relation to where this file is in the directory tree
		files.forEach(function (f) {

			// Count how deep the current file is in relation to base
			var count = file.name.split('/');
			count = count === null ? 0 : count.length - 1;

			// relName is equal to targetName at the base dir
			f.relName = f.targetName;

			// For each directory in depth of current file add a ../ to the relative filename of this link
			while (count > 0) {
				f.relName = '../' + f.relName;
				count--;
			}

		});

		var title = options.title;

		if (!title) {
			title = pkg && pkg.name || 'Title Not Set'
		}

		var compileOptions = _.extend({}, file, {
			title: title,
			allSymbols: allSymbols,
			files: files,
			currentName: file.name
		});

		var compiled = compile(compileOptions);
		fs.writeFileSync(path.join(target, file.targetName), compiled);
	});

}
<|endoftext|>


<commit_before>var webui = angular.module('webui', [
  'webui.services.utils', 'webui.services.deps', 'webui.services.base64',
  'webui.services.configuration', 'webui.services.rpc',
  'webui.services.modals', 'webui.services.alerts',
  'webui.services.settings', 'webui.services.settings.filters',
  'webui.filters.bytes','webui.filters.url',
  'webui.directives.chunkbar', 'webui.directives.dgraph', 'webui.directives.fselect',
  'webui.ctrls.download', 'webui.ctrls.nav', 'webui.ctrls.modal', 'webui.ctrls.alert',
  'webui.ctrls.props',
  // external deps
  'ui.bootstrap',
  // translate
  'pascalprecht.translate'
]);

function mergeTranslation(translation, base) {
	for (var i in base) {
		if (!base.hasOwnProperty(i)) {
			continue;
		}

		if (!translation[i] || !translation[i].length) {
			translation[i] = base[i];
		}
	}

	return translation;
}

webui.config(['$translateProvider', function ($translateProvider) {
  $translateProvider
      .translations('en_US', translations.en_US)
      .translations('nl_NL', mergeTranslation(translations.nl_NL, translations.en_US))
      .translations('th_TH', mergeTranslation(translations.th_TH, translations.en_US))
      .translations('zh_CN', mergeTranslation(translations.zh_CN, translations.en_US))
      .translations('zh_TW', mergeTranslation(translations.zh_TW, translations.en_US))
      .translations('pl_PL', mergeTranslation(translations.pl_PL, translations.en_US))
      .translations('fr_FR', mergeTranslation(translations.fr_FR, translations.en_US))
      .translations('de_DE', mergeTranslation(translations.de_DE, translations.en_US))
      .translations('es_ES', mergeTranslation(translations.es_ES, translations.en_US))
      .translations('ru_RU', mergeTranslation(translations.ru_RU, translations.en_US))
      .translations('it_IT', mergeTranslation(translations.it_IT, translations.en_US))
      .translations('tr_TR', mergeTranslation(translations.tr_TR, translations.en_US))
      .determinePreferredLanguage();
}]);

$(function() {
  if (!String.prototype.startsWith) {
    Object.defineProperty(String.prototype, 'startsWith', {
          enumerable: false, configurable: false, writable: false,
          value: function (searchString, position) {
            position = position || 0;
            return this.indexOf(searchString, position) === position;
          }
    });
  }
  angular.bootstrap(document, ['webui'])
});
<commit_msg>Avoid angular translate security warning<commit_after>var webui = angular.module('webui', [
  'webui.services.utils', 'webui.services.deps', 'webui.services.base64',
  'webui.services.configuration', 'webui.services.rpc',
  'webui.services.modals', 'webui.services.alerts',
  'webui.services.settings', 'webui.services.settings.filters',
  'webui.filters.bytes','webui.filters.url',
  'webui.directives.chunkbar', 'webui.directives.dgraph', 'webui.directives.fselect',
  'webui.ctrls.download', 'webui.ctrls.nav', 'webui.ctrls.modal', 'webui.ctrls.alert',
  'webui.ctrls.props',
  // external deps
  'ui.bootstrap',
  // translate
  'pascalprecht.translate'
]);

function mergeTranslation(translation, base) {
	for (var i in base) {
		if (!base.hasOwnProperty(i)) {
			continue;
		}

		if (!translation[i] || !translation[i].length) {
			translation[i] = base[i];
		}
	}

	return translation;
}

webui.config(['$translateProvider', function ($translateProvider) {
  $translateProvider
      .translations('en_US', translations.en_US)
      .translations('nl_NL', mergeTranslation(translations.nl_NL, translations.en_US))
      .translations('th_TH', mergeTranslation(translations.th_TH, translations.en_US))
      .translations('zh_CN', mergeTranslation(translations.zh_CN, translations.en_US))
      .translations('zh_TW', mergeTranslation(translations.zh_TW, translations.en_US))
      .translations('pl_PL', mergeTranslation(translations.pl_PL, translations.en_US))
      .translations('fr_FR', mergeTranslation(translations.fr_FR, translations.en_US))
      .translations('de_DE', mergeTranslation(translations.de_DE, translations.en_US))
      .translations('es_ES', mergeTranslation(translations.es_ES, translations.en_US))
      .translations('ru_RU', mergeTranslation(translations.ru_RU, translations.en_US))
      .translations('it_IT', mergeTranslation(translations.it_IT, translations.en_US))
      .translations('tr_TR', mergeTranslation(translations.tr_TR, translations.en_US))
      .useSanitizeValueStrategy('escapeParameters')
      .determinePreferredLanguage();
}]);

$(function() {
  if (!String.prototype.startsWith) {
    Object.defineProperty(String.prototype, 'startsWith', {
          enumerable: false, configurable: false, writable: false,
          value: function (searchString, position) {
            position = position || 0;
            return this.indexOf(searchString, position) === position;
          }
    });
  }
  angular.bootstrap(document, ['webui'])
});
<|endoftext|>


<commit_before>/* global Zepto:true */
+function ($) {
  "use strict";

  //初始化页面中的JS组件
  $.initPage = function(page) {
    var $page = $(page);
    if(!$page[0]) $page = $(document.body);
    var $content = $page.find(".content");
    $.initSwiper($content);
    $content.scroller();
    $.initPullToRefresh($content);
    $.initInfiniteScroll($content);
  };

  //全局配置

  var defaults = $.extend({
    autoInit: true
  }, $.config);

  if(defaults.autoInit) {
    $(window).on("push", function() {
      $.initPage();
    });
    $(function() {
      $.initPage();
    });
  }

}(Zepto);
<commit_msg>fix scroller bug<commit_after>/* global Zepto:true */
+function ($) {
  "use strict";

  //初始化页面中的JS组件
  $.initPage = function(page) {
    var $page = $(page);
    if(!$page[0]) $page = $(document.body);
    var $content = $page.find(".content");
    $content.scroller();  //注意滚动条一定要最先初始化
    $.initSwiper($content);
    $.initPullToRefresh($content);
    $.initInfiniteScroll($content);
  };

  //全局配置

  var defaults = $.extend({
    autoInit: true
  }, $.config);

  if(defaults.autoInit) {
    $(window).on("push", function() {
      $.initPage();
    });
    $(function() {
      $.initPage();
    });
  }

}(Zepto);
<|endoftext|>


<commit_before>(function($){
  $(function(){

    $('.button-collapse').sideNav();

  }); // end of document ready
})(jQuery); // end of jQuery name space

(function($){
	$(document).ready(function(){
		$("a[href^='#']").click(function(){
			$(document.body).animate({
				'scrollTop':   $($(this).attr('href')).offset().top
			}, 50);
		})
	});
})(jQuery);

$(function() {
    $('.card').hover(
        function() {
            $(this).find('> .card-image > img.activator').click();
        }, function() {
            $(this).find('> .card-reveal > .card-title').click();
        }
    );
});
<commit_msg>fixed stupid hover bug<commit_after>(function($){
  $(function(){

    $('.button-collapse').sideNav();

  }); // end of document ready
})(jQuery); // end of jQuery name space

(function($){
	$(document).ready(function(){
		$("a[href^='#']").click(function(){
			$(document.body).animate({
				'scrollTop':   $($(this).attr('href')).offset().top
			}, 50);
		})
	});
})(jQuery);

$(function() {
    $('.card-image').hover(
        function() {
            $(this).find('> img.activator').click();
        }, function() {
            $(this).parent().find('> .card-reveal > .card-title').click();
        }
    );
});
<|endoftext|>