<commit_before>import $ from "jquery";
import _ from "underscore";
import Backbone from "backbone";
import React from "react";
import ReactDOM from "react-dom";
import SplashScreen from "components/SplashScreen.react";
import MaintenanceScreen from "components/MaintenanceScreen.react";
import FunctionalCollection from "collections/FunctionalCollection";

// Important:
//   Disconnect all Backbone Events from Models and Collections
Object.keys(Backbone.Events).forEach(function(functionName) {
    Backbone.Model.prototype[functionName] = function() {};
    Backbone.Collection.prototype[functionName] = function() {};
});

Backbone.Collection.prototype.get = function(obj) {
    if (obj == null) return void 0;
    return _.find(this.models, function(model) {
        return model.id == obj || model.id === obj.id || model.cid === obj.cid;
    });
};

// Extend the base collection to include useful functions
_.extend(Backbone.Collection.prototype, FunctionalCollection);

// Register which stores the image should use
import stores from "stores";

stores.AllocationStore = require("stores/AllocationStore");
stores.BadgeStore = require("stores/BadgeStore");
stores.ExternalLinkStore = require("stores/ExternalLinkStore");
stores.HelpLinkStore = require("stores/HelpLinkStore");
stores.ImageStore = require("stores/ImageStore");
stores.ImageVersionStore = require("stores/ImageVersionStore");
stores.ImageVersionMembershipStore = require("stores/ImageVersionMembershipStore");
stores.ImageVersionLicenseStore = require("stores/ImageVersionLicenseStore");
stores.ImageVersionScriptStore = require("stores/ImageVersionScriptStore");
stores.IdentityStore = require("stores/IdentityStore");
stores.ImageBookmarkStore = require("stores/ImageBookmarkStore");
stores.InstanceHistoryStore = require("stores/InstanceHistoryStore");
stores.ImageRequestStore = require("stores/ImageRequestStore");
stores.InstanceStore = require("stores/InstanceStore");
stores.InstanceTagStore = require("stores/InstanceTagStore");
stores.LicenseStore = require("stores/LicenseStore");
stores.ScriptStore = require("stores/ScriptStore");
stores.MaintenanceMessageStore = require("stores/MaintenanceMessageStore");
stores.MyBadgeStore = require("stores/MyBadgeStore");
stores.MembershipStore = require("stores/MembershipStore");
stores.ProfileStore = require("stores/ProfileStore");
stores.ProjectStore = require("stores/ProjectStore");
stores.ProjectExternalLinkStore = require("stores/ProjectExternalLinkStore");
stores.ProjectImageStore = require("stores/ProjectImageStore");
stores.ProjectInstanceStore = require("stores/ProjectInstanceStore");
stores.ProjectVolumeStore = require("stores/ProjectVolumeStore");
stores.ProviderMachineStore = require("stores/ProviderMachineStore");
stores.ProviderStore = require("stores/ProviderStore");
stores.ResourceRequestStore = require("stores/ResourceRequestStore");
stores.IdentityMembershipStore = require("stores/IdentityMembershipStore");
stores.StatusStore = require("stores/StatusStore");
stores.SSHKeyStore = require("stores/SSHKeyStore");
stores.QuotaStore = require("stores/QuotaStore");
stores.SizeStore = require("stores/SizeStore");
stores.TagStore = require("stores/TagStore");
stores.UserStore = require("stores/UserStore");
stores.VersionStore = require("stores/VersionStore");
stores.VolumeStore = require("stores/VolumeStore");
stores.AllocationSourceStore = require("stores/AllocationSourceStore");

import actions from "actions";

actions.BadgeActions = require("actions/BadgeActions");
actions.ExternalLinkActions = require("actions/ExternalLinkActions");
actions.HelpActions = require("actions/HelpActions");
actions.IdentityMembershipActions = require("actions/IdentityMembershipActions");
actions.ImageActions = require("actions/ImageActions");
actions.ImageVersionActions = require("actions/ImageVersionActions");
actions.ImageVersionMembershipActions = require("actions/ImageVersionMembershipActions");
actions.ImageVersionLicenseActions = require("actions/ImageVersionLicenseActions");
actions.ImageVersionScriptActions = require("actions/ImageVersionScriptActions");
actions.ImageBookmarkActions = require("actions/ImageBookmarkActions");
actions.InstanceActions = require("actions/InstanceActions");
actions.InstanceTagActions = require("actions/InstanceTagActions");
actions.InstanceVolumeActions = require("actions/InstanceVolumeActions");
actions.LicenseActions = require("actions/LicenseActions");
actions.ScriptActions = require("actions/ScriptActions");
actions.NullProjectActions = require("actions/NullProjectActions");
actions.ProfileActions = require("actions/ProfileActions");
actions.ProjectActions = require("actions/ProjectActions");
actions.ProviderMachineActions = require("actions/ProviderMachineActions");
actions.ProjectExternalLinkActions = require("actions/ProjectExternalLinkActions");
actions.ProjectImageActions = require("actions/ProjectImageActions");
actions.ProjectInstanceActions = require("actions/ProjectInstanceActions");
actions.ProjectVolumeActions = require("actions/ProjectVolumeActions");
actions.ResourceActions = require("actions/ResourceActions");
actions.TagActions = require("actions/TagActions");
actions.UserActions = require("actions/UserActions");
actions.VolumeActions = require("actions/VolumeActions");

import modals from "modals";

modals.BadgeModals = require("modals/BadgeModals");
modals.ExternalLinkModals = require("modals/ExternalLinkModals");
modals.HelpModals = require("modals/HelpModals");
modals.InstanceModals = require("modals/InstanceModals");
modals.InstanceVolumeModals = require("modals/InstanceVolumeModals");
modals.ProjectModals = require("modals/ProjectModals");
modals.TagModals = require("modals/TagModals");
modals.VersionModals = require("modals/VersionModals");
modals.VolumeModals = require("modals/VolumeModals");
modals.UnsupportedModal = require("modals/UnsupportedModal");

export default {
    run: function() {
        let authHeaders = {
            "Content-Type": "application/json"
        }

        // Assure that an auth header is only included when we have
        // an actually `access_token` to provide.
        if (window.access_token) {
            authHeaders["Authorization"] = "Token " + window.access_token;
        }

        // Make sure the Authorization header is added to every AJAX request
        $.ajaxSetup({
            headers: authHeaders
        });

        // We're wrapping Backbone.sync so that we can observe every AJAX request.
        // If any request returns a 503 (service unavailable) then we're going to
        // throw up the maintenance splash page. Otherwise, just pass the response
        // up to chain.
        var originalSync = Backbone.sync;
        Backbone.sync = function(attrs, textStatus, xhr) {
            // NOTE: a conceptually simpler solution would be to do this:
            //
            //    var xhr = originalSync.apply(this, arguments).catch(function(response){
            //      if(response.status === 503) {
            //        $('.splash-image').remove();
            //        var MaintenanceComponent = React.createFactory(MaintenanceScreen);
            //        ReactDOM.render(MaintenanceComponent(), document.getElementById('application'));
            //      }
            //    });
            //
            //    return xhr;
            //
            // However, since we're using jQuery deferred objects for the promise chain, and they
            // don't have a way to cancel promise propagation, we can end up in a scenario where we
            // display a toast with an error on the maintenance splash screen (because other error
            // handlers can still get called).  To get around that, we need to create our own promise
            // and, based on the result of the AJAX request, either manually resolve or reject it.

            var dfd = $.Deferred();

            originalSync.apply(this, arguments).then(function() {
                dfd.resolve.apply(this, arguments);
            }).fail(function(response) {
                if (response.status === 503) {
                    // need to make sure we remove the splash-image element is included in the HTML
                    // template by default but re-apply the splash screen-class to body so that the
                    // splash page displays correctly
                    //FIXME: Either a. make this page look good or b. remove the entire snippet in favor of window.location below
                    //$(".splash-image").remove();
                    //$("body").addClass("splash-screen");

                    //// replace the current view with the
                    //var MaintenanceComponent = React.createFactory(MaintenanceScreen);
                    //ReactDOM.render(MaintenanceComponent(), document.getElementById("application"));

                    //END-FIXME:
                    window.location = '/maintenance'
                } else {
                    dfd.reject.apply(this, arguments);
                }
            });

            return dfd.promise();
        };

        // render the splash page which will load the rest of the application
        $(document).ready(function() {
            var SplashScreenComponent = React.createFactory(SplashScreen);
            ReactDOM.render(SplashScreenComponent(), document.getElementById("application"));
        });
    }
}
<commit_msg>resolve travis error<commit_after>import $ from "jquery";
import _ from "underscore";
import Backbone from "backbone";
import React from "react";
import ReactDOM from "react-dom";
import SplashScreen from "components/SplashScreen.react";
// See FIXME below where MaintenanceScreen would have been used
//import MaintenanceScreen from "components/MaintenanceScreen.react";
import FunctionalCollection from "collections/FunctionalCollection";

// Important:
//   Disconnect all Backbone Events from Models and Collections
Object.keys(Backbone.Events).forEach(function(functionName) {
    Backbone.Model.prototype[functionName] = function() {};
    Backbone.Collection.prototype[functionName] = function() {};
});

Backbone.Collection.prototype.get = function(obj) {
    if (obj == null) return void 0;
    return _.find(this.models, function(model) {
        return model.id == obj || model.id === obj.id || model.cid === obj.cid;
    });
};

// Extend the base collection to include useful functions
_.extend(Backbone.Collection.prototype, FunctionalCollection);

// Register which stores the image should use
import stores from "stores";

stores.AllocationStore = require("stores/AllocationStore");
stores.BadgeStore = require("stores/BadgeStore");
stores.ExternalLinkStore = require("stores/ExternalLinkStore");
stores.HelpLinkStore = require("stores/HelpLinkStore");
stores.ImageStore = require("stores/ImageStore");
stores.ImageVersionStore = require("stores/ImageVersionStore");
stores.ImageVersionMembershipStore = require("stores/ImageVersionMembershipStore");
stores.ImageVersionLicenseStore = require("stores/ImageVersionLicenseStore");
stores.ImageVersionScriptStore = require("stores/ImageVersionScriptStore");
stores.IdentityStore = require("stores/IdentityStore");
stores.ImageBookmarkStore = require("stores/ImageBookmarkStore");
stores.InstanceHistoryStore = require("stores/InstanceHistoryStore");
stores.ImageRequestStore = require("stores/ImageRequestStore");
stores.InstanceStore = require("stores/InstanceStore");
stores.InstanceTagStore = require("stores/InstanceTagStore");
stores.LicenseStore = require("stores/LicenseStore");
stores.ScriptStore = require("stores/ScriptStore");
stores.MaintenanceMessageStore = require("stores/MaintenanceMessageStore");
stores.MyBadgeStore = require("stores/MyBadgeStore");
stores.MembershipStore = require("stores/MembershipStore");
stores.ProfileStore = require("stores/ProfileStore");
stores.ProjectStore = require("stores/ProjectStore");
stores.ProjectExternalLinkStore = require("stores/ProjectExternalLinkStore");
stores.ProjectImageStore = require("stores/ProjectImageStore");
stores.ProjectInstanceStore = require("stores/ProjectInstanceStore");
stores.ProjectVolumeStore = require("stores/ProjectVolumeStore");
stores.ProviderMachineStore = require("stores/ProviderMachineStore");
stores.ProviderStore = require("stores/ProviderStore");
stores.ResourceRequestStore = require("stores/ResourceRequestStore");
stores.IdentityMembershipStore = require("stores/IdentityMembershipStore");
stores.StatusStore = require("stores/StatusStore");
stores.SSHKeyStore = require("stores/SSHKeyStore");
stores.QuotaStore = require("stores/QuotaStore");
stores.SizeStore = require("stores/SizeStore");
stores.TagStore = require("stores/TagStore");
stores.UserStore = require("stores/UserStore");
stores.VersionStore = require("stores/VersionStore");
stores.VolumeStore = require("stores/VolumeStore");
stores.AllocationSourceStore = require("stores/AllocationSourceStore");

import actions from "actions";

actions.BadgeActions = require("actions/BadgeActions");
actions.ExternalLinkActions = require("actions/ExternalLinkActions");
actions.HelpActions = require("actions/HelpActions");
actions.IdentityMembershipActions = require("actions/IdentityMembershipActions");
actions.ImageActions = require("actions/ImageActions");
actions.ImageVersionActions = require("actions/ImageVersionActions");
actions.ImageVersionMembershipActions = require("actions/ImageVersionMembershipActions");
actions.ImageVersionLicenseActions = require("actions/ImageVersionLicenseActions");
actions.ImageVersionScriptActions = require("actions/ImageVersionScriptActions");
actions.ImageBookmarkActions = require("actions/ImageBookmarkActions");
actions.InstanceActions = require("actions/InstanceActions");
actions.InstanceTagActions = require("actions/InstanceTagActions");
actions.InstanceVolumeActions = require("actions/InstanceVolumeActions");
actions.LicenseActions = require("actions/LicenseActions");
actions.ScriptActions = require("actions/ScriptActions");
actions.NullProjectActions = require("actions/NullProjectActions");
actions.ProfileActions = require("actions/ProfileActions");
actions.ProjectActions = require("actions/ProjectActions");
actions.ProviderMachineActions = require("actions/ProviderMachineActions");
actions.ProjectExternalLinkActions = require("actions/ProjectExternalLinkActions");
actions.ProjectImageActions = require("actions/ProjectImageActions");
actions.ProjectInstanceActions = require("actions/ProjectInstanceActions");
actions.ProjectVolumeActions = require("actions/ProjectVolumeActions");
actions.ResourceActions = require("actions/ResourceActions");
actions.TagActions = require("actions/TagActions");
actions.UserActions = require("actions/UserActions");
actions.VolumeActions = require("actions/VolumeActions");

import modals from "modals";

modals.BadgeModals = require("modals/BadgeModals");
modals.ExternalLinkModals = require("modals/ExternalLinkModals");
modals.HelpModals = require("modals/HelpModals");
modals.InstanceModals = require("modals/InstanceModals");
modals.InstanceVolumeModals = require("modals/InstanceVolumeModals");
modals.ProjectModals = require("modals/ProjectModals");
modals.TagModals = require("modals/TagModals");
modals.VersionModals = require("modals/VersionModals");
modals.VolumeModals = require("modals/VolumeModals");
modals.UnsupportedModal = require("modals/UnsupportedModal");

export default {
    run: function() {
        let authHeaders = {
            "Content-Type": "application/json"
        }

        // Assure that an auth header is only included when we have
        // an actually `access_token` to provide.
        if (window.access_token) {
            authHeaders["Authorization"] = "Token " + window.access_token;
        }

        // Make sure the Authorization header is added to every AJAX request
        $.ajaxSetup({
            headers: authHeaders
        });

        // We're wrapping Backbone.sync so that we can observe every AJAX request.
        // If any request returns a 503 (service unavailable) then we're going to
        // throw up the maintenance splash page. Otherwise, just pass the response
        // up to chain.
        var originalSync = Backbone.sync;
        Backbone.sync = function(attrs, textStatus, xhr) {
            // NOTE: a conceptually simpler solution would be to do this:
            //
            //    var xhr = originalSync.apply(this, arguments).catch(function(response){
            //      if(response.status === 503) {
            //        $('.splash-image').remove();
            //        var MaintenanceComponent = React.createFactory(MaintenanceScreen);
            //        ReactDOM.render(MaintenanceComponent(), document.getElementById('application'));
            //      }
            //    });
            //
            //    return xhr;
            //
            // However, since we're using jQuery deferred objects for the promise chain, and they
            // don't have a way to cancel promise propagation, we can end up in a scenario where we
            // display a toast with an error on the maintenance splash screen (because other error
            // handlers can still get called).  To get around that, we need to create our own promise
            // and, based on the result of the AJAX request, either manually resolve or reject it.

            var dfd = $.Deferred();

            originalSync.apply(this, arguments).then(function() {
                dfd.resolve.apply(this, arguments);
            }).fail(function(response) {
                if (response.status === 503) {
                    // need to make sure we remove the splash-image element is included in the HTML
                    // template by default but re-apply the splash screen-class to body so that the
                    // splash page displays correctly
                    //FIXME: Either a. make this page look good or b. remove the entire snippet in favor of window.location below
                    //$(".splash-image").remove();
                    //$("body").addClass("splash-screen");

                    //// replace the current view with the
                    //var MaintenanceComponent = React.createFactory(MaintenanceScreen);
                    //ReactDOM.render(MaintenanceComponent(), document.getElementById("application"));

                    //END-FIXME:
                    window.location = '/maintenance'
                } else {
                    dfd.reject.apply(this, arguments);
                }
            });

            return dfd.promise();
        };

        // render the splash page which will load the rest of the application
        $(document).ready(function() {
            var SplashScreenComponent = React.createFactory(SplashScreen);
            ReactDOM.render(SplashScreenComponent(), document.getElementById("application"));
        });
    }
}
<|endoftext|>


<commit_before>var co = require('co');
var cheerio = require('cheerio');
var config = require('../config');
var request = require('co-request');
var archive = require('../citiesArchive.js');
var geolocation = require('../util/geolocation');
var timeIdentifiers = require('../metadata/timeIdentifiers');
var lifeshieldShelters = require('../metadata/lifeshieldShelters');

module.exports = function (callback, options) {
    // Fallback options param
    options = options || {};

    // Chrome user agent to avoid being blocked (strange 404 error)
    options.headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
    };

    // Make sure Google Maps API key passed in
    if (!options.googleMapsApiKey) {
        return callback(new Error(`Please provide a Google Maps API Key and try again.`));
    }

    // Magical ES6 generator wrapper
    co(function* () {
        try {
            // Fetch city lists in both Hebrew and English from Pikud Haoref's official website
            var citiesHeb = yield extractCitiesFromUrl(config.hfc.website.hebUrl, options, false);
            var citiesEng = yield extractCitiesFromUrl(config.hfc.website.engUrl, options, true);

            // Final cities metadata array
            var metadata = [];

            // Loop over hebrew cities
            for (var cityId in citiesHeb) {
                // Fetch both cities by unique ID
                var cityHeb = citiesHeb[cityId];
                var cityEng = citiesEng[cityId];

                // Can't match cities by city ID?
                if (!cityEng) {
                    console.error(`Failed to find English locale for city ${cityHeb.name} (ID: ${cityId})`);
                    continue;
                }

                // Attempt to fetch countdown info from Pikud Haoref
                var countdown = null;

                // Check for cached countdown for this city (speed things up)
                for (var cityArchive of archive) {
                    if (cityArchive.name === cityHeb.name) {
                        countdown = {
                            time: cityArchive.time,
                            time_en: cityArchive.time_en,
                            countdown: cityArchive.countdown
                        }
                        break;
                    }
                }

                // Not found, query Pikud Haoref for it
                if (!countdown) {
                    console.log('Fetching countdown for ' + cityHeb.name);
                    countdown = yield fetchCountdown(cityHeb, options);
                }

                // If lat/lng not extracted from Pikud Haoref's website, geocode using Google Maps API
                if (!cityHeb.lat || !cityHeb.lng) {
                    // Fetch geolocation info from Google Maps
                    var location = yield geocodeCity(cityHeb, options);

                    // Geocoding failed?
                    if (location.lat == 0) {
                        // Attempt one more time with English city name
                        location = yield geocodeCity(cityEng, options);
                    }

                    // Match?
                    if (location.lat != 0) {
                        cityHeb.lat = location.lat;
                        cityHeb.lng = location.lng
                    }
                }

                // Dead Sea fail WTF LOL
                cityEng.zone = cityHeb.zone === 'דן' ? 'Dan' : cityEng.zone;

                // Prepare finalized city object
                var city = {
                    name: cityHeb.name,
                    name_en: cityEng.name,
                    zone: cityHeb.zone,
                    zone_en: cityEng.zone,
                    time: countdown.time,
                    time_en: countdown.time_en,
                    countdown: countdown.countdown,
                    lat: cityHeb.lat,
                    lng: cityHeb.lng,
                    value: cityHeb.name
                };

                // Special value for Tel Aviv due to multiple alert codes
                if (city.name == "תל אביב יפו") {
                    city.value = "תל אביב יפו (דן 156) (דן 157) (דן 158) (דן 159)";
                }

                // Lifeshield shelter count exists for this city?
                if (lifeshieldShelters[cityHeb.name]) {
                    city.shelters = lifeshieldShelters[cityHeb.name];
                }

                // Done with this city
                metadata.push(city);
            }

            // Sort cities by name ASC
            metadata.sort(function (a, b) {
                if (a.name < b.name)
                    return -1;
                if (a.name > b.name)
                    return 1;
                return 0;
            });

            // All done
            callback(null, metadata);
        }
        catch (err) {
            // Error
            callback(err);
        }
    });
}

function* extractCitiesFromUrl(url, options, isEnglish) {
    // Execute GET request
    var html = yield request(url, options);

    // Load HTML into Cheerio
    var $ = cheerio.load(html.body, { xmlMode: false });

    // Get all <script> tags in page
    var scripts = $('script');

    // Fallback variables
    var cities = [], areas = [], districts = [];

    // Traverse scripts
    for (var i in scripts) {
        // Get current <script> tag
        var script = scripts[i];

        // Skip non-inline script elements
        if (!Array.isArray(script.children) || script.children.length === 0) {
            continue;
        }

        // Extract script JS code
        var snippet = script.children[0].data;

        // Does the code snippet contain the variable declarations we're looking for?
        if (snippet.includes('var cities ') || snippet.includes('var areas ') || snippet.includes('var districts')) {
            // Remove line breaks
            snippet = snippet.replace(/\r?\n/g, '');

            // Execute code (risky?)
            eval(snippet);
        }
    }

    // We should now have two variables defined: areas, cities
    if (cities.length === 0 || areas.length === 0 || districts.length === 0) {
        throw new Error('Unable to extract areas and districts JSON variables.');
    }

    // Convet areas into JS dictionary object
    var areasDictionary = getAreasDictionary(areas);

    // Final cities result array
    var citiesResult = {};

    // Traverse cities array from Pikud Haoref
    for (var city of districts) {
        // Empty city label?
        if (!city.label) {
            continue;
        }

        // Try to find area by area ID (city.value)
        var area = areasDictionary[city.areaid];

        // No such area with provided ID?
        if (!area) {
            console.error(`No area found for city ${city.label} (area ID: ${city.value})`);
            continue;
        }

        // Eliminate double spacing
        city.label = city.label.replace(/ {2}/g, ' ').trim();

        // Capitalize every English word in city name
        city.label = uppercaseWords(city.label);

        // Lowercase ' of '
        city.label = city.label.replace(' Of ', ' of ');

        // Remove duplicate single quote
        city.label = city.label.replace(/''/g, "'");

        // Add city to result
        citiesResult[city.id] = {
            areaId: area.id,
            name: city.label,
            zone: area.label,
            cityId: city.value
        };

        // Try to find geolocation for this city
        if (!isEnglish) {
            // Traverse geolocation list and match by ID
            for (var geoCity of cities) {
                if (geoCity.id === city.value) {
                    // Bingo
                    citiesResult[city.id].lat = parseFloat(geoCity.lat);
                    citiesResult[city.id].lng = parseFloat(geoCity.lng);

                    // Break
                    break;
                }
            }
        }
    }

    // Done with cities
    return citiesResult;
}

function uppercaseWords(str) {
    // Use regex for a more robusy solution
    return str.replace(/(^| )(\w)/g, function (x) {
        return x.toUpperCase();
    });
}

function getAreasDictionary(areas) {
    // Convert areas to dictionary
    var areasDictionary = {};

    // Traverse area objects
    for (var area of areas) {
        // Check for non-empty label and positive value
        if (!area.label || area.value === "0") continue;

        // Clean up area names
        area.label = area.label.replace(/\(.+?\)/g, '');
        area.label = area.label.replace(/ - [0-9]+.+/g, '');
        area.label = area.label.replace(/ - (דקה|One).*/g, '');
        area.label = area.label.replace('/^השפלה/', 'שפלה');
        area.label = area.label.replace(' - Lowlands', '');

        // Eliminate double spacing
        area.label = area.label.replace(/ {2}/g, ' ');

        // Capitalize every English word in area name
        area.label = uppercaseWords(area.label);

        // Trim leading/trailing spaces
        area.label = area.label.trim();

        // Store in dictionary
        areasDictionary[area.value] = { id: area.value, label: area.label };
    }

    // Done
    return areasDictionary;
}

function* fetchCountdown(city, options) {
    // Fetch shelter instructions by area ID
    var html = yield request('https://www.oref.org.il/Shared/Ajax/GetInstructionsByArea.aspx?lang=he&RiFid=1087&from=1&cityid=' + city.cityId + '&streetid=&ctlabel=' + encodeURIComponent(city.name) + '&stlabel=&house=&lat=0&lng=0&label=' + encodeURIComponent(city.name) + '&area=' + city.areaId + '&address=' + encodeURIComponent(city.label), options);

    // Load HTML into Cheerio
    var $ = cheerio.load(html.body);

    // Extract shelter time designation
    var countdownText = $('.timer span.bold').text().trim();

    // Some areas have no time designation
    if (!countdownText) {
        // Hard-code shfela instructions since Pikud Haoref returns empty instructions
        if (city.zone.includes('שפלה') || city.zone.includes('יהודה')) {
            return timeIdentifiers['דקה וחצי'];
        }

        // Hard-code lahish instructions since Pikud Haoref returns empty instructions
        if (city.zone.includes('לכיש') || city.zone === 'אשדוד 281') {
            return timeIdentifiers['45 שניות'];
        }

        // Hard-code negev instructions since Pikud Haoref returns empty instructions
        if (city.zone.includes('מרכז הנגב-עוטף')) {
            return timeIdentifiers['15 שניות'];
        }

        // Hard-code Tel Aviv instructions since Pikud Haoref returns empty instructions
        if (city.name.includes('תל אביב יפו')) {
            return timeIdentifiers['דקה וחצי'];
        }

        // Warn about missing instructions and default to 0 seconds
        console.error(`No time to shelter instuctions for city: ${city.name}, defaulting to 0 seconds`);
        return timeIdentifiers['מיידי'];
    }

    // Traverse designations
    for (var identifier in timeIdentifiers) {
        // Find match
        if (countdownText.includes(identifier)) {
            return timeIdentifiers[identifier];
        }
    }

    // Unfamiliar countdown time designation, default to 0 seconds
    console.error(`Unknown countdown designation '${countdownText}' for city: ${city.name}`);
    return timeIdentifiers["מיידי"];
}

function* geocodeCity(city, options) {
    // Geocode city by name
    var json = yield request({ url: 'https://maps.googleapis.com/maps/api/geocode/json?address=' + encodeURIComponent(city.name + ', Israel') + '&region=il&key=' + options.googleMapsApiKey, json: true });

    // Failed?
    if (json.body.status != 'OK' && json.body.status != 'ZERO_RESULTS') {
        // Output error
        throw new Error(`Geocoding error: ${json.body.status}`);
    }

    // Traverse results
    for (var result of json.body.results) {
        // Is result within Israel?
        if (isWithinIsraeliBorders(result.geometry.location)) {
            return result.geometry.location;
        }
        else {
            // Output error
            console.error(`Geocoding failed for ${city.name}, result is outside Israel`);
        }
    }

    // Output error
    console.error(`Geocoding failed for ${city.name}`);

    // Fallback coordinates
    return { lat: 0, lng: 0 };
}

function isWithinIsraeliBorders(location) {
    // Get distance of geocoded city from Israel's center in KM
    var distance = geolocation.getDistance(config.israel.center, location);

    // Within allowed radius?
    return distance <= config.israel.radius;
}<commit_msg>Add cities.json error checking<commit_after>var co = require('co');
var cheerio = require('cheerio');
var config = require('../config');
var request = require('co-request');
var archive = require('../citiesArchive.js');
var geolocation = require('../util/geolocation');
var timeIdentifiers = require('../metadata/timeIdentifiers');
var lifeshieldShelters = require('../metadata/lifeshieldShelters');

module.exports = function (callback, options) {
    // Fallback options param
    options = options || {};

    // Chrome user agent to avoid being blocked (strange 404 error)
    options.headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
    };

    // Make sure Google Maps API key passed in
    if (!options.googleMapsApiKey) {
        return callback(new Error(`Please provide a Google Maps API Key and try again.`));
    }

    // Magical ES6 generator wrapper
    co(function* () {
        try {
            // Fetch city lists in both Hebrew and English from Pikud Haoref's official website
            var citiesHeb = yield extractCitiesFromUrl(config.hfc.website.hebUrl, options, false);
            var citiesEng = yield extractCitiesFromUrl(config.hfc.website.engUrl, options, true);

            // Final cities metadata array
            var metadata = [];

            // Loop over hebrew cities
            for (var cityId in citiesHeb) {
                // Fetch both cities by unique ID
                var cityHeb = citiesHeb[cityId];
                var cityEng = citiesEng[cityId];

                // Can't match cities by city ID?
                if (!cityEng) {
                    console.error(`Failed to find English locale for city ${cityHeb.name} (ID: ${cityId})`);
                    continue;
                }

                // Attempt to fetch countdown info from Pikud Haoref
                var countdown = null;

                // Check for cached countdown for this city (speed things up)
                for (var cityArchive of archive) {
                    if (cityArchive.name === cityHeb.name) {
                        countdown = {
                            time: cityArchive.time,
                            time_en: cityArchive.time_en,
                            countdown: cityArchive.countdown
                        }
                        break;
                    }
                }

                // Not found, query Pikud Haoref for it
                if (!countdown) {
                    console.log('Fetching countdown for ' + cityHeb.name);
                    countdown = yield fetchCountdown(cityHeb, options);
                }

                // If lat/lng not extracted from Pikud Haoref's website, geocode using Google Maps API
                if (!cityHeb.lat || !cityHeb.lng) {
                    // Fetch geolocation info from Google Maps
                    var location = yield geocodeCity(cityHeb, options);

                    // Geocoding failed?
                    if (location.lat == 0) {
                        // Attempt one more time with English city name
                        location = yield geocodeCity(cityEng, options);
                    }

                    // Match?
                    if (location.lat != 0) {
                        cityHeb.lat = location.lat;
                        cityHeb.lng = location.lng
                    }
                }

                // Dead Sea fail WTF LOL
                cityEng.zone = cityHeb.zone === 'דן' ? 'Dan' : cityEng.zone;

                // Prepare finalized city object
                var city = {
                    name: cityHeb.name,
                    name_en: cityEng.name,
                    zone: cityHeb.zone,
                    zone_en: cityEng.zone,
                    time: countdown.time,
                    time_en: countdown.time_en,
                    countdown: countdown.countdown,
                    lat: cityHeb.lat,
                    lng: cityHeb.lng,
                    value: cityHeb.name
                };

                // Special value for Tel Aviv due to multiple alert codes
                if (city.name == "תל אביב יפו") {
                    city.value = "תל אביב יפו (דן 156) (דן 157) (דן 158) (דן 159)";
                }

                // Lifeshield shelter count exists for this city?
                if (lifeshieldShelters[cityHeb.name]) {
                    city.shelters = lifeshieldShelters[cityHeb.name];
                }

                // Done with this city
                metadata.push(city);
            }

            // Sort cities by name ASC
            metadata.sort(function (a, b) {
                if (a.name < b.name)
                    return -1;
                if (a.name > b.name)
                    return 1;
                return 0;
            });

            // All done
            callback(null, metadata);
        }
        catch (err) {
            // Error
            callback(err);
        }
    });
}

function* extractCitiesFromUrl(url, options, isEnglish) {
    // Execute GET request
    var html = yield request(url, options);

    // Load HTML into Cheerio
    var $ = cheerio.load(html.body, { xmlMode: false });

    // Get all <script> tags in page
    var scripts = $('script');

    // No JS tag found?
    if (scripts.length === 0) {
        throw new Error('Unable to extract <script> tags. Body: ' + html.body);
    }

    // Fallback variables
    var cities = [], areas = [], districts = [];

    // Traverse scripts
    for (var i in scripts) {
        // Get current <script> tag
        var script = scripts[i];

        // Skip non-inline script elements
        if (!Array.isArray(script.children) || script.children.length === 0) {
            continue;
        }

        // Extract script JS code
        var snippet = script.children[0].data;

        // No JS tag found?
        if (!snippet) {
            throw new Error('Unable to extract areas and districts <script> tags. Body: ' + html.body);
        }

        // Does the code snippet contain the variable declarations we're looking for?
        if (snippet.includes('var cities ') || snippet.includes('var areas ') || snippet.includes('var districts')) {
            // Remove line breaks
            snippet = snippet.replace(/\r?\n/g, '');

            // Execute code (risky?)
            eval(snippet);
        }
    }

    // We should now have two variables defined: areas, cities
    if (cities.length === 0 || areas.length === 0 || districts.length === 0) {
        throw new Error('Unable to extract areas and districts JSON variables.');
    }

    // Convet areas into JS dictionary object
    var areasDictionary = getAreasDictionary(areas);

    // Final cities result array
    var citiesResult = {};

    // Traverse cities array from Pikud Haoref
    for (var city of districts) {
        // Empty city label?
        if (!city.label) {
            continue;
        }

        // Try to find area by area ID (city.value)
        var area = areasDictionary[city.areaid];

        // No such area with provided ID?
        if (!area) {
            console.error(`No area found for city ${city.label} (area ID: ${city.value})`);
            continue;
        }

        // Eliminate double spacing
        city.label = city.label.replace(/ {2}/g, ' ').trim();

        // Capitalize every English word in city name
        city.label = uppercaseWords(city.label);

        // Lowercase ' of '
        city.label = city.label.replace(' Of ', ' of ');

        // Remove duplicate single quote
        city.label = city.label.replace(/''/g, "'");

        // Add city to result
        citiesResult[city.id] = {
            areaId: area.id,
            name: city.label,
            zone: area.label,
            cityId: city.value
        };

        // Try to find geolocation for this city
        if (!isEnglish) {
            // Traverse geolocation list and match by ID
            for (var geoCity of cities) {
                if (geoCity.id === city.value) {
                    // Bingo
                    citiesResult[city.id].lat = parseFloat(geoCity.lat);
                    citiesResult[city.id].lng = parseFloat(geoCity.lng);

                    // Break
                    break;
                }
            }
        }
    }

    // Done with cities
    return citiesResult;
}

function uppercaseWords(str) {
    // Use regex for a more robusy solution
    return str.replace(/(^| )(\w)/g, function (x) {
        return x.toUpperCase();
    });
}

function getAreasDictionary(areas) {
    // Convert areas to dictionary
    var areasDictionary = {};

    // Traverse area objects
    for (var area of areas) {
        // Check for non-empty label and positive value
        if (!area.label || area.value === "0") continue;

        // Clean up area names
        area.label = area.label.replace(/\(.+?\)/g, '');
        area.label = area.label.replace(/ - [0-9]+.+/g, '');
        area.label = area.label.replace(/ - (דקה|One).*/g, '');
        area.label = area.label.replace('/^השפלה/', 'שפלה');
        area.label = area.label.replace(' - Lowlands', '');

        // Eliminate double spacing
        area.label = area.label.replace(/ {2}/g, ' ');

        // Capitalize every English word in area name
        area.label = uppercaseWords(area.label);

        // Trim leading/trailing spaces
        area.label = area.label.trim();

        // Store in dictionary
        areasDictionary[area.value] = { id: area.value, label: area.label };
    }

    // Done
    return areasDictionary;
}

function* fetchCountdown(city, options) {
    // Fetch shelter instructions by area ID
    var html = yield request('https://www.oref.org.il/Shared/Ajax/GetInstructionsByArea.aspx?lang=he&RiFid=1087&from=1&cityid=' + city.cityId + '&streetid=&ctlabel=' + encodeURIComponent(city.name) + '&stlabel=&house=&lat=0&lng=0&label=' + encodeURIComponent(city.name) + '&area=' + city.areaId + '&address=' + encodeURIComponent(city.label), options);

    // Load HTML into Cheerio
    var $ = cheerio.load(html.body);

    // Extract shelter time designation
    var countdownText = $('.timer span.bold').text().trim();

    // Some areas have no time designation
    if (!countdownText) {
        // Hard-code shfela instructions since Pikud Haoref returns empty instructions
        if (city.zone.includes('שפלה') || city.zone.includes('יהודה')) {
            return timeIdentifiers['דקה וחצי'];
        }

        // Hard-code lahish instructions since Pikud Haoref returns empty instructions
        if (city.zone.includes('לכיש') || city.zone === 'אשדוד 281') {
            return timeIdentifiers['45 שניות'];
        }

        // Hard-code negev instructions since Pikud Haoref returns empty instructions
        if (city.zone.includes('מרכז הנגב-עוטף')) {
            return timeIdentifiers['15 שניות'];
        }

        // Hard-code Tel Aviv instructions since Pikud Haoref returns empty instructions
        if (city.name.includes('תל אביב יפו')) {
            return timeIdentifiers['דקה וחצי'];
        }

        // Warn about missing instructions and default to 0 seconds
        console.error(`No time to shelter instuctions for city: ${city.name}, defaulting to 0 seconds`);
        return timeIdentifiers['מיידי'];
    }

    // Traverse designations
    for (var identifier in timeIdentifiers) {
        // Find match
        if (countdownText.includes(identifier)) {
            return timeIdentifiers[identifier];
        }
    }

    // Unfamiliar countdown time designation, default to 0 seconds
    console.error(`Unknown countdown designation '${countdownText}' for city: ${city.name}`);
    return timeIdentifiers["מיידי"];
}

function* geocodeCity(city, options) {
    // Geocode city by name
    var json = yield request({ url: 'https://maps.googleapis.com/maps/api/geocode/json?address=' + encodeURIComponent(city.name + ', Israel') + '&region=il&key=' + options.googleMapsApiKey, json: true });

    // Failed?
    if (json.body.status != 'OK' && json.body.status != 'ZERO_RESULTS') {
        // Output error
        throw new Error(`Geocoding error: ${json.body.status}`);
    }

    // Traverse results
    for (var result of json.body.results) {
        // Is result within Israel?
        if (isWithinIsraeliBorders(result.geometry.location)) {
            return result.geometry.location;
        }
        else {
            // Output error
            console.error(`Geocoding failed for ${city.name}, result is outside Israel`);
        }
    }

    // Output error
    console.error(`Geocoding failed for ${city.name}`);

    // Fallback coordinates
    return { lat: 0, lng: 0 };
}

function isWithinIsraeliBorders(location) {
    // Get distance of geocoded city from Israel's center in KM
    var distance = geolocation.getDistance(config.israel.center, location);

    // Within allowed radius?
    return distance <= config.israel.radius;
}<|endoftext|>


<commit_before>/**
 Flexitable jQuery plugin
 Copyright (c) 2015 Adam Messinger, http://zenscope.com/
 Released under the MIT license, see LICENSE file for details.

 This plugin owes its starting point to the work of Marco Pegoraro (movableapp.com):
   https://github.com/marcopeg/MediaTable
 ...and also borrows some ideas from Tablesaw by Filament Group:
   https://github.com/filamentgroup/tablesaw
 **/

;(function($, undefined) {
  'use strict';

  $.fn.flexitable = function(user_config) {
    return this.each(function(i) {
      var $table = $(this);
      var config = $.extend({
        has_menu: true,
        button_title: 'Columns:',
        destroy: false
      }, (user_config || {}));
      var flexitable = columnChooser($table, config, i);

      if (config.destroy) {
        flexitable.destroy();
      } else {
        flexitable.init();
      }
    });
  };

  /* jQuery.deferredEach docs and info:
   * https://github.com/adammessinger/jQuery.deferredEach */
  (function($, undefined) {
    'use strict';

    $.deferredEach = function(collection, callback) {
      var i = 0;
      var length = collection.length;
      var is_array = _isArraylike(collection);
      var parent_deferred = new $.Deferred();
      var child_deferreds;
      var keys = [];
      var next, key;

      if (is_array) {
        child_deferreds = _makeChildDeferredsArray(length);

        next = function() {
          if (i < length && callback.call(collection[i], i, collection[i++]) !== false) {
            setTimeout(next, 1);
          }
          child_deferreds[i - 1].resolve();
          parent_deferred.notify(i / length);
        };
        next();
      } else {
        for (key in collection) {
          keys.push(key);
        }
        child_deferreds = _makeChildDeferredsArray(keys.length);

        next = function() {
          if (i < keys.length && callback.call(collection[keys[i]], keys[i], collection[keys[i++]]) !== false) {
            setTimeout(next, 1);
          }
          child_deferreds[i - 1].resolve();
          parent_deferred.notify(i / keys.length);
        };
        next();
      }

      $.when.apply(undefined, child_deferreds).then(function() {
        parent_deferred.notify(1);
        parent_deferred.resolve(collection);
      });
      return parent_deferred.promise();
    };

    function _makeChildDeferredsArray(length) {
      var i = 0;
      var array = [];

      for (; i < length; i++) {
        array.push(new $.Deferred());
      }
      return array;
    }

    function _isArraylike(obj) {
      var length = obj.length;
      var type = $.type(obj);

      if (type === "function" || $.isWindow(obj)) {
        return false;
      }
      if (obj.nodeType === 1 && length) {
        return true;
      }
      return type === "array" || length === 0 ||
             (typeof length === "number" && length > 0 && (length - 1) in obj);
    }
  })(jQuery);

  function columnChooser($table, config, i) {
    var persistent_css_class = 'persist';
    var essential_css_class = 'essential';
    var optional_css_class = 'optional';
    // view_model will contain all the data we need for future DOM manipulations.
    // Much faster than revisiting the DOM repeatedly.
    var view_model = {
      id: $table[0].id,
      // cfg: this table's Flexitable config
      cfg: config,
      $table: $table,
      $wrapper: $('
'),
      // $menu: will hold column toggle menu
      $menu: null,
      // cells_by_column: array of objects w/ each col's header txt & th,
      // contained cells, and visibility & persistence states
      cells_by_column: []
    };

    // public methods
    return {
      init: initFlexitable,
      destroy: destroyFlexitable
    };

    function initFlexitable() {
      var $headers;

      // Prevent re-initialization
      if (view_model.$table.data('Flexitable')) {
        return;
      }

      // Set table ID if not specified
      if (!view_model.id) {
        view_model.id = 'flexitable-' + i;
        view_model.$table[0].id = view_model.id;
      }

      $headers = view_model.$table.find('thead th');
      if ($headers.length) {
        $.deferredEach($headers, _initCellsByHeader)
          .done(function() {
            // 'flexitable-active' class enables media queries, once above init gives
            // proper classes to cells
            view_model.$table
              .addClass('flexitable-active')
              .before(view_model.$wrapper);

            // NOTE: using standard .appendChild() here because it saves 500-700ms in
            // IE 11 vs. jQ .appendTo()
            view_model.$wrapper[0].appendChild(view_model.$table[0]);

            // NOTE: MUST build menu after _initCellsByHeader, not before
            if (view_model.cfg.has_menu && view_model.cells_by_column) {
              _buildMenu(view_model);
            }

            view_model.$table.data('Flexitable', {
              $menu: view_model.$menu,
              $wrapper: view_model.$wrapper
            });

            view_model.$table.trigger('flexitable.initialized');
          });
      }
    }

    function destroyFlexitable() {
      var flexitable_data = view_model.$table.data('Flexitable');

      if (!flexitable_data) {
        return;
      }

      flexitable_data.$menu.remove();
      flexitable_data.$wrapper.after(view_model.$table).remove();
      // remove active class to nix Flexitable media queries
      view_model.$table.removeClass('flexitable-active');
      // remove stored plugin data on the table
      view_model.$table.removeData('Flexitable');
    }

    function _initCellsByHeader(i, header) {
      var $header = $(header);
      var cells_by_column = view_model.cells_by_column;
      var is_optional_col = $header.hasClass(optional_css_class);
      var is_essential_col = $header.hasClass(essential_css_class);
      var is_persistent_col = $header.hasClass(persistent_css_class);
      // NOTE: cell_num is used for nth-child selectors, which aren't 0-indexed
      var cell_num = i + 1;
      var $col_cells = view_model.$table.find('> thead th:nth-child(' + cell_num + '), > tbody td:nth-child(' + cell_num + ')');
      // cell loop vars:
      var i_cells, l_cells;

      // NOTE: using a loop here saved init time for huge tables vs. .toggleClass()
      for (i_cells = 0, l_cells = $col_cells.length; i_cells < l_cells; i_cells++) {
        $col_cells[i_cells].className += is_essential_col
          ? (' ' + essential_css_class)
          : '';
        $col_cells[i_cells].className += is_optional_col
          ? (' ' + optional_css_class)
          : '';
      }

      cells_by_column.push({
        // NOTE: we're using the th's visibility as a proxy for the column's
        is_visible: ($header.css('display') === 'table-cell'),
        $th: $header,
        heading_text: $header.text(),
        is_persistent_col: is_persistent_col,
        // NOTE: no need to store cells for persistent columns, so we don't to save memory
        $cells: is_persistent_col ? null : $col_cells
      });
    }

    function _buildMenu() {
      var cells_by_column = view_model.cells_by_column;
      var li_cache = [];
      var i, l, $this_checkbox, $this_label;

      // Build menu containers
      view_model.$menu = $('
');
      view_model.$menu.$button = $('<button type="button" />').text(view_model.cfg.button_title);
      view_model.$menu.$list = $('
');
      view_model.$menu
        .append(view_model.$menu.$button)
        .append(view_model.$menu.$list);

      // Add a class to the wrapper to inform about menu presence.
      view_model.$wrapper.addClass('flexitable-has-menu');

      // populate menu with checkboxes for each non-persistent column
      for (i = 0, l = cells_by_column.length; i < l; i++) {
        if (!cells_by_column[i].is_persistent_col) {
          $this_checkbox = $('<input />', {
            type: 'checkbox',
            name: 'toggle-cols',
            id: 'toggle-col-'+i,
            value: i
          });
          $this_checkbox.prop('checked', cells_by_column[i].is_visible);

          $this_label = $('', {
            for: 'toggle-col-'+i,
            text: cells_by_column[i].heading_text
          });

          li_cache.push($('
').append($this_checkbox).append($this_label))
        }
      }

      view_model.$menu.$list.append(li_cache);
      view_model.$menu.prependTo(view_model.$wrapper);
      _initMenuInteractions(view_model);
    }

    function _initMenuInteractions() {
      view_model.$menu
        .on('click', 'button', _toggleMenuVisibility)
        .on('change', 'input[name="toggle-cols"]', _toggleColumn)
        .on('updateCheck', 'input[name="toggle-cols"]', _updateMenuCheckbox);

      // Update checkbox status on viewport changes.
      $(window).on('orientationchange resize', _updateCheckboxesOnViewportChange);

      // Close menu when user clicks anywhere outside the menu.
      $(document).on('click', _closeMenuOnOutsideClick);
    }

    function _toggleMenuVisibility() {
      view_model.$menu.toggleClass('flexitable-menu-closed');
    }

    function _closeMenuOnOutsideClick(event) {
      if (!view_model.$menu.find(event.target).length) {
        view_model.$menu.addClass('flexitable-menu-closed');
      }
    }

    function _toggleColumn(event) {
      var checkbox = event.target;
      // NOTE: checkbox value is the same as column index from view_model.cells_by_column
      var i_col = parseInt(checkbox.value, 10);

      view_model.cells_by_column[i_col].$cells
        .toggleClass('flexitable-cell-shown', checkbox.checked)
        .toggleClass('flexitable-cell-hidden', !checkbox.checked);

      // update active state in view_model
      view_model.cells_by_column[i_col].is_visible = checkbox.checked;
    }

    function _updateMenuCheckbox(event) {
      var checkbox = event.target;
      // NOTE: checkbox value is the same as column index from view_model.cells_by_column
      var i_col = parseInt(checkbox.value, 10);

      checkbox.checked = view_model.cells_by_column[i_col].is_visible;
    }

    function _updateCheckboxesOnViewportChange() {
      // TODO: throttle this
      var i, l, cells_by_column = view_model.cells_by_column;

      // update active state of columns
      for (i = 0, l = cells_by_column.length; i < l; i++) {
        cells_by_column[i].is_visible = (cells_by_column[i].$th.css('display') === 'table-cell');
      }
      // update all checkboxes
      view_model.$menu.$list.find('input').trigger('updateCheck');
    }
  }
})(jQuery);<commit_msg>Unique IDs for checkboxes, even with multiple enhanced tables in play. Data attribute on checkboxes containing ID of the associated table for more easily associating the two w/ non-plugin script.<commit_after>/**
 Flexitable jQuery plugin
 Copyright (c) 2015 Adam Messinger, http://zenscope.com/
 Released under the MIT license, see LICENSE file for details.

 This plugin owes its starting point to the work of Marco Pegoraro (movableapp.com):
   https://github.com/marcopeg/MediaTable
 ...and also borrows some ideas from Tablesaw by Filament Group:
   https://github.com/filamentgroup/tablesaw
 **/

;(function($, undefined) {
  'use strict';

  $.fn.flexitable = function(user_config) {
    return this.each(function(i) {
      var $table = $(this);
      var config = $.extend({
        has_menu: true,
        button_title: 'Columns:',
        destroy: false
      }, (user_config || {}));
      var flexitable = columnChooser($table, config, i);

      if (config.destroy) {
        flexitable.destroy();
      } else {
        flexitable.init();
      }
    });
  };

  /* jQuery.deferredEach docs and info:
   * https://github.com/adammessinger/jQuery.deferredEach */
  (function($, undefined) {
    'use strict';

    $.deferredEach = function(collection, callback) {
      var i = 0;
      var length = collection.length;
      var is_array = _isArraylike(collection);
      var parent_deferred = new $.Deferred();
      var child_deferreds;
      var keys = [];
      var next, key;

      if (is_array) {
        child_deferreds = _makeChildDeferredsArray(length);

        next = function() {
          if (i < length && callback.call(collection[i], i, collection[i++]) !== false) {
            setTimeout(next, 1);
          }
          child_deferreds[i - 1].resolve();
          parent_deferred.notify(i / length);
        };
        next();
      } else {
        for (key in collection) {
          keys.push(key);
        }
        child_deferreds = _makeChildDeferredsArray(keys.length);

        next = function() {
          if (i < keys.length && callback.call(collection[keys[i]], keys[i], collection[keys[i++]]) !== false) {
            setTimeout(next, 1);
          }
          child_deferreds[i - 1].resolve();
          parent_deferred.notify(i / keys.length);
        };
        next();
      }

      $.when.apply(undefined, child_deferreds).then(function() {
        parent_deferred.notify(1);
        parent_deferred.resolve(collection);
      });
      return parent_deferred.promise();
    };

    function _makeChildDeferredsArray(length) {
      var i = 0;
      var array = [];

      for (; i < length; i++) {
        array.push(new $.Deferred());
      }
      return array;
    }

    function _isArraylike(obj) {
      var length = obj.length;
      var type = $.type(obj);

      if (type === "function" || $.isWindow(obj)) {
        return false;
      }
      if (obj.nodeType === 1 && length) {
        return true;
      }
      return type === "array" || length === 0 ||
             (typeof length === "number" && length > 0 && (length - 1) in obj);
    }
  })(jQuery);

  function columnChooser($table, config, i) {
    var persistent_css_class = 'persist';
    var essential_css_class = 'essential';
    var optional_css_class = 'optional';
    // view_model will contain all the data we need for future DOM manipulations.
    // Much faster than revisiting the DOM repeatedly.
    var view_model = {
      id: $table[0].id,
      // cfg: this table's Flexitable config
      cfg: config,
      $table: $table,
      $wrapper: $('
'),
      // $menu: will hold column toggle menu
      $menu: null,
      // cells_by_column: array of objects w/ each col's header txt & th,
      // contained cells, and visibility & persistence states
      cells_by_column: []
    };

    // public methods
    return {
      init: initFlexitable,
      destroy: destroyFlexitable
    };

    function initFlexitable() {
      var $headers;

      // Prevent re-initialization
      if (view_model.$table.data('Flexitable')) {
        return;
      }

      // Set table ID if not specified
      if (!view_model.id) {
        view_model.id = 'flexitable-' + i;
        view_model.$table[0].id = view_model.id;
      }

      $headers = view_model.$table.find('thead th');
      if ($headers.length) {
        $.deferredEach($headers, _initCellsByHeader)
          .done(function() {
            // 'flexitable-active' class enables media queries, once above init gives
            // proper classes to cells
            view_model.$table
              .addClass('flexitable-active')
              .before(view_model.$wrapper);

            // NOTE: using standard .appendChild() here because it saves 500-700ms in
            // IE 11 vs. jQ .appendTo()
            view_model.$wrapper[0].appendChild(view_model.$table[0]);

            // NOTE: MUST build menu after _initCellsByHeader, not before
            if (view_model.cfg.has_menu && view_model.cells_by_column) {
              _buildMenu(view_model);
            }

            view_model.$table.data('Flexitable', {
              $menu: view_model.$menu,
              $wrapper: view_model.$wrapper
            });

            view_model.$table.trigger('flexitable.initialized');
          });
      }
    }

    function destroyFlexitable() {
      var flexitable_data = view_model.$table.data('Flexitable');

      if (!flexitable_data) {
        return;
      }

      flexitable_data.$menu.remove();
      flexitable_data.$wrapper.after(view_model.$table).remove();
      // remove active class to nix Flexitable media queries
      view_model.$table.removeClass('flexitable-active');
      // remove stored plugin data on the table
      view_model.$table.removeData('Flexitable');
    }

    function _initCellsByHeader(i, header) {
      var $header = $(header);
      var cells_by_column = view_model.cells_by_column;
      var is_optional_col = $header.hasClass(optional_css_class);
      var is_essential_col = $header.hasClass(essential_css_class);
      var is_persistent_col = $header.hasClass(persistent_css_class);
      // NOTE: cell_num is used for nth-child selectors, which aren't 0-indexed
      var cell_num = i + 1;
      var $col_cells = view_model.$table.find('> thead th:nth-child(' + cell_num + '), > tbody td:nth-child(' + cell_num + ')');
      // cell loop vars:
      var i_cells, l_cells;

      // NOTE: using a loop here saved init time for huge tables vs. .toggleClass()
      for (i_cells = 0, l_cells = $col_cells.length; i_cells < l_cells; i_cells++) {
        $col_cells[i_cells].className += is_essential_col
          ? (' ' + essential_css_class)
          : '';
        $col_cells[i_cells].className += is_optional_col
          ? (' ' + optional_css_class)
          : '';
      }

      cells_by_column.push({
        // NOTE: we're using the th's visibility as a proxy for the column's
        is_visible: ($header.css('display') === 'table-cell'),
        $th: $header,
        heading_text: $header.text(),
        is_persistent_col: is_persistent_col,
        // NOTE: no need to store cells for persistent columns, so we don't to save memory
        $cells: is_persistent_col ? null : $col_cells
      });
    }

    function _buildMenu() {
      var cells_by_column = view_model.cells_by_column;
      var checkbox_id_pfx = (view_model.id + '_toggle-col-');
      var li_cache = [];
      var i, l, $this_checkbox, $this_label;

      // Build menu containers
      view_model.$menu = $('
');
      view_model.$menu.$button = $('<button type="button" />').text(view_model.cfg.button_title);
      view_model.$menu.$list = $('
');
      view_model.$menu
        .append(view_model.$menu.$button)
        .append(view_model.$menu.$list);

      // Add a class to the wrapper to inform about menu presence.
      view_model.$wrapper.addClass('flexitable-has-menu');

      // populate menu with checkboxes for each non-persistent column
      for (i = 0, l = cells_by_column.length; i < l; i++) {
        if (!cells_by_column[i].is_persistent_col) {
          $this_checkbox = $('<input />', {
            type: 'checkbox',
            name: 'toggle-cols',
            id: (checkbox_id_pfx + i),
            value: i,
            'data-flexitable-id': view_model.id
          });
          $this_checkbox.prop('checked', cells_by_column[i].is_visible);

          $this_label = $('', {
            for: (checkbox_id_pfx + i),
            text: cells_by_column[i].heading_text
          });

          li_cache.push($('
').append($this_checkbox).append($this_label))
        }
      }

      view_model.$menu.$list.append(li_cache);
      view_model.$menu.prependTo(view_model.$wrapper);
      _initMenuInteractions(view_model);
    }

    function _initMenuInteractions() {
      view_model.$menu
        .on('click', 'button', _toggleMenuVisibility)
        .on('change', 'input[name="toggle-cols"]', _toggleColumn)
        .on('updateCheck', 'input[name="toggle-cols"]', _updateMenuCheckbox);

      // Update checkbox status on viewport changes.
      $(window).on('orientationchange resize', _updateCheckboxesOnViewportChange);

      // Close menu when user clicks anywhere outside the menu.
      $(document).on('click', _closeMenuOnOutsideClick);
    }

    function _toggleMenuVisibility() {
      view_model.$menu.toggleClass('flexitable-menu-closed');
    }

    function _closeMenuOnOutsideClick(event) {
      if (!view_model.$menu.find(event.target).length) {
        view_model.$menu.addClass('flexitable-menu-closed');
      }
    }

    function _toggleColumn(event) {
      var checkbox = event.target;
      // NOTE: checkbox value is the same as column index from view_model.cells_by_column
      var i_col = parseInt(checkbox.value, 10);

      view_model.cells_by_column[i_col].$cells
        .toggleClass('flexitable-cell-shown', checkbox.checked)
        .toggleClass('flexitable-cell-hidden', !checkbox.checked);

      // update active state in view_model
      view_model.cells_by_column[i_col].is_visible = checkbox.checked;
    }

    function _updateMenuCheckbox(event) {
      var checkbox = event.target;
      // NOTE: checkbox value is the same as column index from view_model.cells_by_column
      var i_col = parseInt(checkbox.value, 10);

      checkbox.checked = view_model.cells_by_column[i_col].is_visible;
    }

    function _updateCheckboxesOnViewportChange() {
      // TODO: throttle this
      var i, l, cells_by_column = view_model.cells_by_column;

      // update active state of columns
      for (i = 0, l = cells_by_column.length; i < l; i++) {
        cells_by_column[i].is_visible = (cells_by_column[i].$th.css('display') === 'table-cell');
      }
      // update all checkboxes
      view_model.$menu.$list.find('input').trigger('updateCheck');
    }
  }
})(jQuery);<|endoftext|>


<commit_before>/**
 *  getScripts (jQuery shorthand extended)
 *  A lightweight asynchronous JavaScript loader.
 *
 *  Copyright 2015, Marc S. Brooks (https://mbrooks.info)
 *  Licensed under the MIT license:
 *  http://www.opensource.org/licenses/mit-license.php
 *
 *  Dependencies:
 *    jquery.js
 */

if (!window.jQuery || (window.jQuery && parseInt(window.jQuery.fn.jquery.replace('.', '')) < parseInt('1.8.3'.replace('.', '')))) {
  throw new Error('jQuery.getScripts requires jQuery 1.8.3 or greater.');
}

(function($) {

  /**
   * @namespace getScripts
   */
  var methods = {

    /**
     * Create new instance of getScripts
     *
     * @memberof getScripts
     * @method init
     *
     * @example
     * jQuery.getScripts(files, callback);
     *
     * @param {Array} files
     * @param {Function} callback
     */
    "init": function(files, callback) {

      // Support method chaining.
      return this.each(function() {
        if (!$.isArray(files) || files.length == 0) {
          $.error('Invalid array');
        }

        if (callback && !$.isFunction(callback)) {
          $.error('Invalid callback function');
        }

        var count = 0;

        // Execute as recursive callback.
        var _callback = function() {
          if (files.length == count) {
            if (callback) {
              callback();
            }

            return true;
          }

          var script = files[count];

          $.getScript(script)
            .done(_callback)
            .fail(function(jqxhr, settings, exception) {
              $.error("Script '" + script + "' failed with exception\n" + exception);
            });

          count++;
        };

        _callback();
      });
    }
  };

  $.fn.getScripts = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    }
    else
    if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    }
    else {
      $.error('Method ' +  method + ' does not exist in jQuery.getScripts');
    }
  };
})(jQuery);
<commit_msg>Updated asignment operator to ===<commit_after>/**
 *  getScripts (jQuery shorthand extended)
 *  A lightweight asynchronous JavaScript loader.
 *
 *  Copyright 2015, Marc S. Brooks (https://mbrooks.info)
 *  Licensed under the MIT license:
 *  http://www.opensource.org/licenses/mit-license.php
 *
 *  Dependencies:
 *    jquery.js
 */

if (!window.jQuery || (window.jQuery && parseInt(window.jQuery.fn.jquery.replace('.', '')) < parseInt('1.8.3'.replace('.', '')))) {
  throw new Error('jQuery.getScripts requires jQuery 1.8.3 or greater.');
}

(function($) {

  /**
   * @namespace getScripts
   */
  var methods = {

    /**
     * Create new instance of getScripts
     *
     * @memberof getScripts
     * @method init
     *
     * @example
     * jQuery.getScripts(files, callback);
     *
     * @param {Array} files
     * @param {Function} callback
     */
    "init": function(files, callback) {

      // Support method chaining.
      return this.each(function() {
        if (!$.isArray(files) || files.length === 0) {
          $.error('Invalid array');
        }

        if (callback && !$.isFunction(callback)) {
          $.error('Invalid callback function');
        }

        var count = 0;

        // Execute as recursive callback.
        var _callback = function() {
          if (files.length == count) {
            if (callback) {
              callback();
            }

            return true;
          }

          var script = files[count];

          $.getScript(script)
            .done(_callback)
            .fail(function(jqxhr, settings, exception) {
              $.error("Script '" + script + "' failed with exception\n" + exception);
            });

          count++;
        };

        _callback();
      });
    }
  };

  $.fn.getScripts = function(method) {
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    }
    else
    if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    }
    else {
      $.error('Method ' +  method + ' does not exist in jQuery.getScripts');
    }
  };
})(jQuery);
<|endoftext|>


<commit_before>import React, { PropTypes } from "react";
import { ClipPath } from "../victory-primitives/index";

export default class VictoryClipContainer extends React.Component {
  static displayName = "VictoryClipContainer";

  static propTypes = {
    style: PropTypes.object,
    padding: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.shape({
        top: PropTypes.number,
        bottom: PropTypes.number,
        left: PropTypes.number,
        right: PropTypes.number
      })
    ]),
    clipHeight: PropTypes.number,
    clipWidth: PropTypes.number,
    events: PropTypes.object,
    children: React.PropTypes.oneOfType([
      React.PropTypes.arrayOf(React.PropTypes.node),
      React.PropTypes.node
    ]),
    clipPathComponent: PropTypes.element,
    translateX: PropTypes.number,
    transform: PropTypes.string
  }

  static defaultProps = {
    clipPathComponent: <ClipPath/>
  }

  // Overridden in victory-core-native
  renderClippedGroup(props, clipId) {
    const { style, events, transform, children } = props;
    const clipComponent = this.renderClipComponent(props, clipId);
    return (
      <g
        style={style}
        {...events}
        transform={transform}
      >
        {clipComponent}
        <g clipPath={`url(#${clipId})`}>
          {children}
        </g>
      </g>
    );
  }

  // Overridden in victory-core-native
  renderGroup(props) {
    const { style, events, transform, children } = props;
    return (
      <g
        style={style}
        {...events}
        transform={transform}
      >
        {children}
      </g>
    );
  }

  // Overridden in victory-core-native
  renderClipComponent(props, clipId) {
    const { padding, translateX, clipHeight, clipWidth, clipPathComponent } = props;
    return React.cloneElement(
      clipPathComponent,
      { padding, clipId, translateX, clipWidth, clipHeight }
    );
  }

  render() {
    const { clipWidth } = this.props;
    if (clipWidth || clipWidth === 0) {
      const clipId = Math.round(Math.random() * 10000);
      return this.renderClippedGroup(this.props, clipId);
    }
    return this.renderGroup(this.props);
  }
}
<commit_msg>Cache clipId when instantiated<commit_after>import React, { PropTypes } from "react";
import { ClipPath } from "../victory-primitives/index";

export default class VictoryClipContainer extends React.Component {
  static displayName = "VictoryClipContainer";

  static propTypes = {
    style: PropTypes.object,
    padding: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.shape({
        top: PropTypes.number,
        bottom: PropTypes.number,
        left: PropTypes.number,
        right: PropTypes.number
      })
    ]),
    clipHeight: PropTypes.number,
    clipWidth: PropTypes.number,
    events: PropTypes.object,
    children: React.PropTypes.oneOfType([
      React.PropTypes.arrayOf(React.PropTypes.node),
      React.PropTypes.node
    ]),
    clipPathComponent: PropTypes.element,
    translateX: PropTypes.number,
    transform: PropTypes.string
  }

  static defaultProps = {
    clipPathComponent: <ClipPath/>
  }

  constructor(props) {
    super(props);
    this.clipId = Math.round(Math.random() * 10000);
  }

  // Overridden in victory-core-native
  renderClippedGroup(props, clipId) {
    const { style, events, transform, children } = props;
    const clipComponent = this.renderClipComponent(props, clipId);
    return (
      <g
        style={style}
        {...events}
        transform={transform}
      >
        {clipComponent}
        <g clipPath={`url(#${clipId})`}>
          {children}
        </g>
      </g>
    );
  }

  // Overridden in victory-core-native
  renderGroup(props) {
    const { style, events, transform, children } = props;
    return (
      <g
        style={style}
        {...events}
        transform={transform}
      >
        {children}
      </g>
    );
  }

  // Overridden in victory-core-native
  renderClipComponent(props, clipId) {
    const { padding, translateX, clipHeight, clipWidth, clipPathComponent } = props;
    return React.cloneElement(
      clipPathComponent,
      { padding, clipId, translateX, clipWidth, clipHeight }
    );
  }

  render() {
    const { clipWidth } = this.props;
    if (clipWidth || clipWidth === 0) {
      return this.renderClippedGroup(this.props, this.clipId);
    }
    return this.renderGroup(this.props);
  }
}
<|endoftext|>


<commit_before>var Application = Application || {};

Application.Constants = angular.module('application.core.constants', []);
Application.Services = angular.module('application.core.services', []);
Application.Controllers = angular.module('application.core.controllers', []);
Application.Filters = angular.module('application.core.filters', []);
Application.Directives = angular.module('application.core.directives', []);

Application.Provenance = {};
Application.Provenance.Constants = angular.module('application.provenance.constants', []);
Application.Provenance.Services = angular.module('application.provenance.services', []);
Application.Provenance.Controllers = angular.module('application.provenance.controllers', []);
Application.Provenance.Filters = angular.module('application.provenance.filters', []);
Application.Provenance.Directives = angular.module('application.provenance.directives', []);

var app = angular.module('materialscommons',
    [
        'ui',
        'ui.bootstrap',
        'ngCookies',
        '$strap.directives',
        'ui.router', 'ngResource',
        'ngQuickDate',
        'application.core.constants', 'application.core.services', 'application.core.controllers',
        'application.core.filters', 'application.core.directives',
        'application.provenance.constants', 'application.provenance.services', 'application.provenance.controllers',
        'application.provenance.filters', 'application.provenance.directives']);

app.config(function ($stateProvider) {
    Stomp.WebSocketClass = SockJS;
    mcglobals = {};
    doConfig();
    $stateProvider
        // Navbar
        .state('home', {
            url: '/home',
            templateUrl: 'application/core/home/home.html'
        })
        .state('toolbar', {
            url: '/toolbar',
            templateUrl: 'application/core/toolbar/toolbar.html'
        })
        .state('about', {
            url: '/about',
            templateUrl: 'application/core/about/about.html'
        })
        .state('contact', {
            url: '/contact',
            templateUrl: 'application/core/contact/contact.html'
        })
        .state('help', {
            url: '/help',
            templateUrl: 'application/core/help/help.html'
        })
        .state('login', {
            url: '/login',
            templateUrl: 'application/core/login/login.html'
        })
        .state('logout', {
            url: '/logout',
            controller: 'logout'
        })

        // Account
        .state('account', {
            url: '/account',
            templateUrl: 'application/core/account/account.html'
        })
        .state('account.groupcreate', {
            url: '/groupcreate',
            templateUrl: 'application/core/account/groupcreate/groupcreate.html'
        })
        .state('account.groupusers', {
            url: '/groupusers/:id',
            templateUrl: 'application/core/account/groupusers/groupusers.html'
        })
        // Toolbar drafts
        .state('toolbar.drafts', {
            url: '/drafts',
            templateUrl: 'application/core/toolbar/drafts/drafts.html'
        })
        // Toolbar Data Views
        .state('toolbar.mydatapage', {
            url: '/mydatapage',
            templateUrl: 'application/core/toolbar/mydatapage/mydatapage.html'
        })
        .state('toolbar.mydata', {
            url: '/mydata',
            templateUrl: 'application/core/toolbar/mydata/mydata.html'
        })
        .state('toolbar.thumbnails', {
            url: '/thumbnails',
            templateUrl: 'application/core/toolbar/thumbnails/thumbnails.html'
        })
        .state('toolbar.dataedit', {
            url: '/dataedit/:id',
            templateUrl: 'application/core/toolbar/dataedit/dataedit.html'
        })
        .state('toolbar.databytag', {
            url: '/databytag/:name',
            templateUrl: 'application/core/toolbar/databytag/databytag.html'
        })

        // Toolbar tag views
        .state('toolbar.tagspage', {
            url: '/tagspage',
            templateUrl: 'application/core/toolbar/tagspage/tagspage.html'
        })
        .state('toolbar.tags', {
            url: '/tags',
            templateUrl: 'application/core/toolbar/tags/tags.html'
        })
        .state('toolbar.globaltagcloud', {
            url: '/globaltagcloud',
            templateUrl: 'application/core/toolbar/globaltagcloud/globaltagcloud.html'
        })

        // Toolbar review views
        .state('toolbar.reviews', {
            url: '/reviews',
            templateUrl: 'application/core/toolbar/reviews/reviews.html'
        })

        // Toolbar machine views
        .state('toolbar.machines', {
            url: '/machines',
            templateUrl: 'application/core/toolbar/machines/machines.html'
        })

        // Toolbar materials views
        .state('toolbar.materials', {
            url: '/materials',
            templateUrl: 'application/core/toolbar/materials/materials.html'
        })

        // Toolbar overview
        .state('toolbar.overview', {
            url: '/overview',
            templateUrl: 'application/core/toolbar/overview/overview.html'
        })

        // Toolbar projectspage views
        .state('toolbar.projectspage', {
            url: '/projectspage/:id/:draft_id',
            templateUrl: 'application/core/toolbar/projectspage/projectspage.html',
            resolve: {
                ProvDrafts: "ProvDrafts"
            },
            onExit: function (ProvDrafts) {
                if (ProvDrafts.current) {
                    ProvDrafts.saveDraft();
                }
            }
        })
        .state('toolbar.projectspage.overview', {
            url: '/overview',
            templateUrl: 'application/core/toolbar/projectspage/overview/overview.html'
        })
        .state('toolbar.projectspage.provenance', {
            url: '/provenance',
            templateUrl: 'application/provenance/provenance.html'
        })
        .state('toolbar.projectspage.provenance.process', {
            url: '/process',
            templateUrl: 'application/provenance/process/process.html'

        })
        .state('toolbar.projectspage.provenance.iosteps', {
            url: '/iosteps:iosteps',
            templateUrl: 'application/provenance/iosteps/iosteps.html'
        })
        .state('toolbar.projectspage.provenance.iosteps.iostep', {
            url: '/iostep:iostep',
            templateUrl: 'application/provenance/iosteps/iostep/iostep.html'
        })
        .state('toolbar.projectspage.provenance.iosteps.files', {
            url: '/files:iostep',
            templateUrl: 'application/provenance/iosteps/files/files.html'
        })
        .state('toolbar.projectspage.provenance.finish', {
            url: '/finish',
            templateUrl: 'application/provenance/finish/finish.html'
        });
});

app.run(function ($rootScope, $state, $stateParams, $location, $cookieStore, User) {
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState) {
        if (!User.isAuthenticated()) {
            if (toState.templateUrl && toState.templateUrl.indexOf("partials/my-tools") !== -1) {
                $location.path("/login");
            }
        } else {
            $rootScope.email_address = User.u();
        }
    });
});
<commit_msg>Make sure the name has been set before saving the provenance.<commit_after>var Application = Application || {};

Application.Constants = angular.module('application.core.constants', []);
Application.Services = angular.module('application.core.services', []);
Application.Controllers = angular.module('application.core.controllers', []);
Application.Filters = angular.module('application.core.filters', []);
Application.Directives = angular.module('application.core.directives', []);

Application.Provenance = {};
Application.Provenance.Constants = angular.module('application.provenance.constants', []);
Application.Provenance.Services = angular.module('application.provenance.services', []);
Application.Provenance.Controllers = angular.module('application.provenance.controllers', []);
Application.Provenance.Filters = angular.module('application.provenance.filters', []);
Application.Provenance.Directives = angular.module('application.provenance.directives', []);

var app = angular.module('materialscommons',
    [
        'ui',
        'ui.bootstrap',
        'ngCookies',
        '$strap.directives',
        'ui.router', 'ngResource',
        'ngQuickDate',
        'application.core.constants', 'application.core.services', 'application.core.controllers',
        'application.core.filters', 'application.core.directives',
        'application.provenance.constants', 'application.provenance.services', 'application.provenance.controllers',
        'application.provenance.filters', 'application.provenance.directives']);

app.config(function ($stateProvider) {
    Stomp.WebSocketClass = SockJS;
    mcglobals = {};
    doConfig();
    $stateProvider
        // Navbar
        .state('home', {
            url: '/home',
            templateUrl: 'application/core/home/home.html'
        })
        .state('toolbar', {
            url: '/toolbar',
            templateUrl: 'application/core/toolbar/toolbar.html'
        })
        .state('about', {
            url: '/about',
            templateUrl: 'application/core/about/about.html'
        })
        .state('contact', {
            url: '/contact',
            templateUrl: 'application/core/contact/contact.html'
        })
        .state('help', {
            url: '/help',
            templateUrl: 'application/core/help/help.html'
        })
        .state('login', {
            url: '/login',
            templateUrl: 'application/core/login/login.html'
        })
        .state('logout', {
            url: '/logout',
            controller: 'logout'
        })

        // Account
        .state('account', {
            url: '/account',
            templateUrl: 'application/core/account/account.html'
        })
        .state('account.groupcreate', {
            url: '/groupcreate',
            templateUrl: 'application/core/account/groupcreate/groupcreate.html'
        })
        .state('account.groupusers', {
            url: '/groupusers/:id',
            templateUrl: 'application/core/account/groupusers/groupusers.html'
        })
        // Toolbar drafts
        .state('toolbar.drafts', {
            url: '/drafts',
            templateUrl: 'application/core/toolbar/drafts/drafts.html'
        })
        // Toolbar Data Views
        .state('toolbar.mydatapage', {
            url: '/mydatapage',
            templateUrl: 'application/core/toolbar/mydatapage/mydatapage.html'
        })
        .state('toolbar.mydata', {
            url: '/mydata',
            templateUrl: 'application/core/toolbar/mydata/mydata.html'
        })
        .state('toolbar.thumbnails', {
            url: '/thumbnails',
            templateUrl: 'application/core/toolbar/thumbnails/thumbnails.html'
        })
        .state('toolbar.dataedit', {
            url: '/dataedit/:id',
            templateUrl: 'application/core/toolbar/dataedit/dataedit.html'
        })
        .state('toolbar.databytag', {
            url: '/databytag/:name',
            templateUrl: 'application/core/toolbar/databytag/databytag.html'
        })

        // Toolbar tag views
        .state('toolbar.tagspage', {
            url: '/tagspage',
            templateUrl: 'application/core/toolbar/tagspage/tagspage.html'
        })
        .state('toolbar.tags', {
            url: '/tags',
            templateUrl: 'application/core/toolbar/tags/tags.html'
        })
        .state('toolbar.globaltagcloud', {
            url: '/globaltagcloud',
            templateUrl: 'application/core/toolbar/globaltagcloud/globaltagcloud.html'
        })

        // Toolbar review views
        .state('toolbar.reviews', {
            url: '/reviews',
            templateUrl: 'application/core/toolbar/reviews/reviews.html'
        })

        // Toolbar machine views
        .state('toolbar.machines', {
            url: '/machines',
            templateUrl: 'application/core/toolbar/machines/machines.html'
        })

        // Toolbar materials views
        .state('toolbar.materials', {
            url: '/materials',
            templateUrl: 'application/core/toolbar/materials/materials.html'
        })

        // Toolbar overview
        .state('toolbar.overview', {
            url: '/overview',
            templateUrl: 'application/core/toolbar/overview/overview.html'
        })

        // Toolbar projectspage views
        .state('toolbar.projectspage', {
            url: '/projectspage/:id/:draft_id',
            templateUrl: 'application/core/toolbar/projectspage/projectspage.html',
            resolve: {
                ProvDrafts: "ProvDrafts"
            },
            onExit: function (ProvDrafts) {
                if (ProvDrafts.current && ProvDrafts.current.attributes.process.name !== "") {
                    ProvDrafts.saveDraft();
                }
            }
        })
        .state('toolbar.projectspage.overview', {
            url: '/overview',
            templateUrl: 'application/core/toolbar/projectspage/overview/overview.html'
        })
        .state('toolbar.projectspage.provenance', {
            url: '/provenance',
            templateUrl: 'application/provenance/provenance.html'
        })
        .state('toolbar.projectspage.provenance.process', {
            url: '/process',
            templateUrl: 'application/provenance/process/process.html'

        })
        .state('toolbar.projectspage.provenance.iosteps', {
            url: '/iosteps:iosteps',
            templateUrl: 'application/provenance/iosteps/iosteps.html'
        })
        .state('toolbar.projectspage.provenance.iosteps.iostep', {
            url: '/iostep:iostep',
            templateUrl: 'application/provenance/iosteps/iostep/iostep.html'
        })
        .state('toolbar.projectspage.provenance.iosteps.files', {
            url: '/files:iostep',
            templateUrl: 'application/provenance/iosteps/files/files.html'
        })
        .state('toolbar.projectspage.provenance.finish', {
            url: '/finish',
            templateUrl: 'application/provenance/finish/finish.html'
        });
});

app.run(function ($rootScope, $state, $stateParams, $location, $cookieStore, User) {
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState) {
        if (!User.isAuthenticated()) {
            if (toState.templateUrl && toState.templateUrl.indexOf("partials/my-tools") !== -1) {
                $location.path("/login");
            }
        } else {
            $rootScope.email_address = User.u();
        }
    });
});
<|endoftext|>


<commit_before>var Schema = require('../BaseSchema')

var RegexpSchema = module.exports = Schema.patterns.RegexpSchema = Schema.extend({
  initialize: function(regexp) {
    this.regexp = regexp
  },
  errors: function(instance) {
    var message;
    if (!(Object(instance) instanceof String)) {
      message = instance + ' is not a String';
    } else if (!this.regexp || this.regexp.test(instance)) {
      message = instance + ' is not matched with RegExp -> ' + this.regexp;
    }

    if (message)
      return this.err(message, instance);
    return false;
  },
  validate: function(instance) {
    return Object(instance) instanceof String && (!this.regexp || this.regexp.test(instance))
  },

  toJSON: function() {
    var json = Schema.prototype.toJSON.call(this)

    json.type = 'string'

    if (this.regexp) {
      json.pattern = this.regexp.toString()
      json.pattern = json.pattern.substr(1, json.pattern.length - 2)
    }

    return json
  }
})

Schema.fromJSON.def(function(sch) {
  if (!sch || sch.type !== 'string') return

  if ('pattern' in sch) {
    return new RegexpSchema(RegExp('^' + sch.pattern + '$'))
  } else if ('minLength' in sch || 'maxLength' in sch) {
    return new RegexpSchema(RegExp('^.{' + [sch.minLength || 0, sch.maxLength].join(',') + '}$'))
  } else {
    return new RegexpSchema()
  }
})

Schema.fromJS.def(function(regexp) {
  if (regexp instanceof RegExp) return new RegexpSchema(regexp)
})<commit_msg>Feature Errors : Fixed logic in regexp<commit_after>var Schema = require('../BaseSchema')

var RegexpSchema = module.exports = Schema.patterns.RegexpSchema = Schema.extend({
  initialize: function(regexp) {
    this.regexp = regexp
  },
  errors: function(instance) {
    var message;
    if (!(Object(instance) instanceof String)) {
      message = instance + ' is not a String';
    } else if (this.regexp && !this.regexp.test(instance)) {
      message = instance + ' is not matched with RegExp -> ' + this.regexp;
    }

    if (message)
      return this.err(message, instance);
    return false;
  },
  validate: function(instance) {
    return Object(instance) instanceof String && (!this.regexp || this.regexp.test(instance))
  },

  toJSON: function() {
    var json = Schema.prototype.toJSON.call(this)

    json.type = 'string'

    if (this.regexp) {
      json.pattern = this.regexp.toString()
      json.pattern = json.pattern.substr(1, json.pattern.length - 2)
    }

    return json
  }
})

Schema.fromJSON.def(function(sch) {
  if (!sch || sch.type !== 'string') return

  if ('pattern' in sch) {
    return new RegexpSchema(RegExp('^' + sch.pattern + '$'))
  } else if ('minLength' in sch || 'maxLength' in sch) {
    return new RegexpSchema(RegExp('^.{' + [sch.minLength || 0, sch.maxLength].join(',') + '}$'))
  } else {
    return new RegexpSchema()
  }
})

Schema.fromJS.def(function(regexp) {
  if (regexp instanceof RegExp) return new RegexpSchema(regexp)
})<|endoftext|>