<commit_before>// Show very general purpose error
var something_went_wrong = function(content) {
    fix_button_texts()
    $('pre,.alert-error,.alert-warning,.help-inline').remove()
    var p = $('
').addClass('alert alert-error').html('Something went wrong! Click here to show technical details.').on('click', function() {
        $(this).next('pre').toggle()
    }).css('cursor', 'pointer')
    var pre = $('
').html(content).hide()
    $('body').prepend(pre)
    $('body').prepend(p)
}

// Handle response from exec of twfollow.py
var done_exec_main = function(content, rename) {
    console.log(content)
    try {
        response = JSON.parse(content)

        // Handle various known responses
        if (response['status'] == 'auth-redirect') {
            scraperwiki.tool.redirect(response['url'])
            return
        }

        if (response['status'] == 'ok-updating') {
            // set another (full) run going in the background to start getting older tweets
            scraperwiki.exec('tool/twfollow.py >/dev/null 2>&1 &',
              function() {
              },
              function(obj, err, exception) {
                  something_went_wrong(err + "! " + exception)
              }
            )
        }

        // Show whatever we would on loading page
        // i.e. read status from database that twfollow.py set
        show_hide_stuff(null, rename)
    } catch(e) {
        // Otherwise an unknown error - e.g. an unexpected stack trace
        something_went_wrong(content)
        return
    }
}

// Unlimited followers
var allow_unlimited_followers = function(cb) {
   scraperwiki.user.profile(function(details) {
        var accountLevel = details.effective.accountLevel
        var allow = true
        if (accountLevel.match(/free/)) {
            allow = false
        }
        cb(allow)
   })
}

// Trigger to get unlimited followers
var get_them_all = function() {
   $(this).addClass('loading').html('Getting...').attr('disabled', true)
   $('pre,.alert-error,.alert-warning,.help-inline').remove()

   scraperwiki.exec("echo 10000000 > max_to_get.txt; ONETIME=1 tool/twfollow.py",
    function(content) {
        done_exec_main(content, false)
    },
    function(obj, err, exception) {
        something_went_wrong(err + "! " + exception)
    }
   )
}

// Event function for when they click on the Go!, Refresh! or Reauthenticate buttons.
// Calls out to the Python script twfollow.py, which does the actual Twitter
// calling.
var scrape_action = function() {
    $('pre,.alert-error,.alert-warning,.help-inline').remove()
    $('.control-group').removeClass('error')

    var q = $('#q').val()
    q = q.replace(/^@/,'')
    if (q.match(/[^a-zA-Z0-9_]/)) {
        $(".control-group").addClass('error')
        $(".controls").append('Twitter user names only use the alphabet, numbers and _')
        return
    }

    $(this).addClass('loading').html('Loading…').attr('disabled', true)

    var rename = false
    if ($(this).attr('id') == 'submit') {
      rename = true
    }

    // show_hide_stuff will check this variable later and contact intercom.io
    window.trackSearch = true

    // Pass various OAuth bits of data to the Python script that is going to do the work
    scraperwiki.exec('echo ' + scraperwiki.shellEscape(q) + '>user.txt; ONETIME=1 tool/twfollow.py "' + callback_url + '" "' + oauth_verifier + '"',
        function(content) {
            done_exec_main(content, rename)
        },
        function(obj, err, exception) {
            something_went_wrong(err + "! " + exception)
        }
    )
}

// Show rate limit and so on
var diagnostics_action = function() {
    var $link = $(this)
    if ($('#diagnostics-area .alert').is(":visible")) {
        $('#diagnostics-area .alert').slideUp(400)
        return
    }
    $link.next().show()

    // Pass various OAuth bits of data to the Python script that is going to do the work
    scraperwiki.exec('tool/twfollow.py diagnostics',
        function (content) {
            $link.next().hide()
            var diagnostics
        try {
            diagnostics = JSON.parse(content)
        } catch(e) {
            console.log("caught!!")
            // Otherwise an unknown error - e.g. an unexpected stack trace
            something_went_wrong(content)
            return
        }
        console.log(diagnostics)
        var html = ''
        if ('status' in diagnostics) {
            html += 'Status ' + diagnostics.status + '. '
        }
        if ('user' in diagnostics) {
            html += 'Authenticated user is @' + diagnostics.user + '. '
            html += 'There are ' + diagnostics.followers_remaining + '/' + diagnostics.followers_limit + ' followers API calls left '
            html += 'resetting ' + moment.unix(diagnostics.users_reset).fromNow() + ", "
            html += '' + diagnostics.friends_remaining + '/' + diagnostics.friends_limit + ' following API calls left '
            html += 'resetting ' + moment.unix(diagnostics.users_reset).fromNow() + ", "
            html += '' + diagnostics.users_remaining + '/' + diagnostics.users_limit + ' user details API calls left '
            html += 'resetting ' + moment.unix(diagnostics.users_reset).fromNow() + ". "
        }
        if (!('crontab' in diagnostics)) {
            html += 'Not scheduled. '
        } else if (diagnostics.crontab.match(/no crontab/)) {
            html += 'Not scheduled. '
        } else {
            html += 'Scheduled to update at ' + parseInt(diagnostics.crontab) + ' minutes past the hour. '
        }
        $('#diagnostics-area .alert').html(html).slideDown(400)
    },
        function(obj, err, exception) {
            something_went_wrong(err + "! " + exception)
        }
    )
}

// Clear data and start again
var clear_action = function() {
    $(this).addClass('loading').html('Clearing…').attr('disabled', true)
    $('pre,.alert-error,.alert-warning,.help-inline').remove()

    scraperwiki.dataset.name("Get Twitter friends")

    scraperwiki.reporting.user({increments: {tf_resets: 1}})

    scraperwiki.exec("tool/twfollow.py clean-slate",
        function(content) {
            done_exec_main(content, false)
        },
        function(obj, err, exception) {
            something_went_wrong(err + "! " + exception)
        }
    )
}

// Buttons show "Loading..." and so on while working. This puts all their text back after.
var fix_button_texts = function() {
    $('#reauthenticate').removeClass('loading').html('Reauthenticate').attr('disabled', false)
    $('#submit').removeClass('loading').html('Go').attr('disabled', false)
    $('#clear-data').removeClass('loading').html('Monitor someone else*').attr('disabled', false)
}

var track_search_if_required = function() {
    if(window.trackSearch) {
        scraperwiki.reporting.user({increments: {tf_searches: 1}})
        window.trackSearch = undefined
    }
}

// Show the right form (get settings, or the refresh data one)
var show_hide_stuff = function(done, rename) {
    // Find out what user it is
    scraperwiki.exec('touch user.txt; cat user.txt', function(data) {
        data = $.trim(data)
        $('#q').val(data)
        $('.who').text(data)

        if (rename) {
            scraperwiki.dataset.name("Twitter friends of @" + data)
        }

    // Show expected delivery time
    scraperwiki.sql('select sum(batch_got) as got, sum(batch_expected) as expected from __status', function(results){
	var got = results[0]['got']
	var expected = results[0]['expected']
	$('.batch_got').text(got)
	$('.batch_expected').text(expected)

	var tweets_per_request = 5000
	var request_per_hour = 3
	var hours_left = Math.round((expected - got) / request_per_hour / tweets_per_request)
	var days_left = Math.round(hours_left / 24)
	if (hours_left <= 1) {
	    eta = "1 hour"
	} else if (hours_left < 13) {
	    eta = hours_left + " hours"
	} else if (days_left < 2) {
	    eta = "1 day"
	} else {
	    eta = days_left + " days"
	}
	$('#eta').text(eta)
        }
    )

        // Show right form
        scraperwiki.sql('select * from __status where id = "global"', function(results){
            results = results[0]

            // results['batch_expected'] += 1; // debugging, force a state

            console.log(results)

            $('.settings').hide()
            fix_button_texts()
            $('.done_when').text(moment(results['when']).format("Do MMM YYYY"))
	    // we run @hourly in cron, and until Twitter stops us, which happens with
	    // users/lookup rate limit (18000 in 15 min window, so three chunks of 5000)

            $('pre,.alert-error,.alert-warning,.help-inline').remove()
            $('.control-group').removeClass('error')

            if (results['current_status'] == 'auth-redirect') {
                $('#settings-auth').show()
                $('#settings-clear').show()
                // if during auth, click it
                if (oauth_verifier) {
                    $("#reauthenticate").trigger("click")
                    scraperwiki.dataset.name("Twitter friends of @" + data)
                }
            } else if (results['current_status'] == 'not-there') {
                $('#settings-get').show()
                var p = $('
').addClass('alert alert-error').html("User not found on Twitter! Check the spelling and that they have an account and try again.")
                $('body').prepend(p)
            } else if (results['current_status'] == 'rate-limit') {
                $('#settings-working').show()
                var p = $('
').addClass('alert alert-warning').html('Twitter has asked us to slow down! See the FAQ for details and suggestions.')
                $('body').prepend(p)
                $('#settings-clear').show()
            } else if (results['current_status'] == 'ok-updating') {
                $('#settings-working').show()
                $('#settings-clear').show()
                track_search_if_required()
            } else if (results['current_status'] == 'ok-done') {
                $('#settings-done').show()
                $('#settings-clear').show()
                track_search_if_required()
            } else if (results['current_status'] == 'ok-limit') {
                allow_unlimited_followers(function(allow) {
                  if (allow) {
                    $('#error-too-many').hide()
                    $('#allow-too-many').show()
                  } else {
                    $('#error-too-many').show()
                    $('#allow-too-many').hide()
                  }
                  $('#settings-limit').show()
                  $('#settings-clear').show()
                  track_search_if_required()
                })
            } else if (results['current_status'] == 'clean-slate') {
                $('#settings-get').show()
            } else {
                alert("Unknown internal state: " + results['current_status'])
            }
            if (done) {
                done()
            }
        }, function(results) {
            // this is bad as it will masks real errors - we have to show the form as
            // no SQLite database gives an error
            fix_button_texts()
            $('#settings-get').show()
            if (done) {
                done()
            }
        })
    }, function(obj, err, exception) {
       something_went_wrong(err + "! " + exception)
    })
}

// Get OAuth parameters that we need from the URL
var settings = scraperwiki.readSettings()
var callback_url
var oauth_verifier
scraperwiki.tool.getURL(function(our_url) {
    console.log(our_url)
    var url = $.url(our_url)
    oauth_verifier = url.param('oauth_verifier')
    // remove query parameters for the callback URL, so they don't stack up if we
    // go multiple times to Twitter
    callback_url = url.attr('base') + url.attr('path')
    // only when we have the callback URL, allow the submit button to be clicked
    $("#submit,#reauthenticate,#clear-data").removeAttr("disabled")
})

$(document).ready(function() {
    show_hide_stuff()

    $('#q').on('keypress', function(e){
      if(e.which == 13){
        $('#submit').trigger('click')
      }
    })

    $('#clear-data').on('click', clear_action)
    $('#submit,#reauthenticate').on('click', scrape_action)
    $('#diagnostics').on('click', diagnostics_action)
    $('#get-them-all').on('click', get_them_all)
})

<commit_msg>Update FAQ link<commit_after>// Show very general purpose error
var something_went_wrong = function(content) {
    fix_button_texts()
    $('pre,.alert-error,.alert-warning,.help-inline').remove()
    var p = $('
').addClass('alert alert-error').html('Something went wrong! Click here to show technical details.').on('click', function() {
        $(this).next('pre').toggle()
    }).css('cursor', 'pointer')
    var pre = $('
').html(content).hide()
    $('body').prepend(pre)
    $('body').prepend(p)
}

// Handle response from exec of twfollow.py
var done_exec_main = function(content, rename) {
    console.log(content)
    try {
        response = JSON.parse(content)

        // Handle various known responses
        if (response['status'] == 'auth-redirect') {
            scraperwiki.tool.redirect(response['url'])
            return
        }

        if (response['status'] == 'ok-updating') {
            // set another (full) run going in the background to start getting older tweets
            scraperwiki.exec('tool/twfollow.py >/dev/null 2>&1 &',
              function() {
              },
              function(obj, err, exception) {
                  something_went_wrong(err + "! " + exception)
              }
            )
        }

        // Show whatever we would on loading page
        // i.e. read status from database that twfollow.py set
        show_hide_stuff(null, rename)
    } catch(e) {
        // Otherwise an unknown error - e.g. an unexpected stack trace
        something_went_wrong(content)
        return
    }
}

// Unlimited followers
var allow_unlimited_followers = function(cb) {
   scraperwiki.user.profile(function(details) {
        var accountLevel = details.effective.accountLevel
        var allow = true
        if (accountLevel.match(/free/)) {
            allow = false
        }
        cb(allow)
   })
}

// Trigger to get unlimited followers
var get_them_all = function() {
   $(this).addClass('loading').html('Getting...').attr('disabled', true)
   $('pre,.alert-error,.alert-warning,.help-inline').remove()

   scraperwiki.exec("echo 10000000 > max_to_get.txt; ONETIME=1 tool/twfollow.py",
    function(content) {
        done_exec_main(content, false)
    },
    function(obj, err, exception) {
        something_went_wrong(err + "! " + exception)
    }
   )
}

// Event function for when they click on the Go!, Refresh! or Reauthenticate buttons.
// Calls out to the Python script twfollow.py, which does the actual Twitter
// calling.
var scrape_action = function() {
    $('pre,.alert-error,.alert-warning,.help-inline').remove()
    $('.control-group').removeClass('error')

    var q = $('#q').val()
    q = q.replace(/^@/,'')
    if (q.match(/[^a-zA-Z0-9_]/)) {
        $(".control-group").addClass('error')
        $(".controls").append('Twitter user names only use the alphabet, numbers and _')
        return
    }

    $(this).addClass('loading').html('Loading…').attr('disabled', true)

    var rename = false
    if ($(this).attr('id') == 'submit') {
      rename = true
    }

    // show_hide_stuff will check this variable later and contact intercom.io
    window.trackSearch = true

    // Pass various OAuth bits of data to the Python script that is going to do the work
    scraperwiki.exec('echo ' + scraperwiki.shellEscape(q) + '>user.txt; ONETIME=1 tool/twfollow.py "' + callback_url + '" "' + oauth_verifier + '"',
        function(content) {
            done_exec_main(content, rename)
        },
        function(obj, err, exception) {
            something_went_wrong(err + "! " + exception)
        }
    )
}

// Show rate limit and so on
var diagnostics_action = function() {
    var $link = $(this)
    if ($('#diagnostics-area .alert').is(":visible")) {
        $('#diagnostics-area .alert').slideUp(400)
        return
    }
    $link.next().show()

    // Pass various OAuth bits of data to the Python script that is going to do the work
    scraperwiki.exec('tool/twfollow.py diagnostics',
        function (content) {
            $link.next().hide()
            var diagnostics
        try {
            diagnostics = JSON.parse(content)
        } catch(e) {
            console.log("caught!!")
            // Otherwise an unknown error - e.g. an unexpected stack trace
            something_went_wrong(content)
            return
        }
        console.log(diagnostics)
        var html = ''
        if ('status' in diagnostics) {
            html += 'Status ' + diagnostics.status + '. '
        }
        if ('user' in diagnostics) {
            html += 'Authenticated user is @' + diagnostics.user + '. '
            html += 'There are ' + diagnostics.followers_remaining + '/' + diagnostics.followers_limit + ' followers API calls left '
            html += 'resetting ' + moment.unix(diagnostics.users_reset).fromNow() + ", "
            html += '' + diagnostics.friends_remaining + '/' + diagnostics.friends_limit + ' following API calls left '
            html += 'resetting ' + moment.unix(diagnostics.users_reset).fromNow() + ", "
            html += '' + diagnostics.users_remaining + '/' + diagnostics.users_limit + ' user details API calls left '
            html += 'resetting ' + moment.unix(diagnostics.users_reset).fromNow() + ". "
        }
        if (!('crontab' in diagnostics)) {
            html += 'Not scheduled. '
        } else if (diagnostics.crontab.match(/no crontab/)) {
            html += 'Not scheduled. '
        } else {
            html += 'Scheduled to update at ' + parseInt(diagnostics.crontab) + ' minutes past the hour. '
        }
        $('#diagnostics-area .alert').html(html).slideDown(400)
    },
        function(obj, err, exception) {
            something_went_wrong(err + "! " + exception)
        }
    )
}

// Clear data and start again
var clear_action = function() {
    $(this).addClass('loading').html('Clearing…').attr('disabled', true)
    $('pre,.alert-error,.alert-warning,.help-inline').remove()

    scraperwiki.dataset.name("Get Twitter friends")

    scraperwiki.reporting.user({increments: {tf_resets: 1}})

    scraperwiki.exec("tool/twfollow.py clean-slate",
        function(content) {
            done_exec_main(content, false)
        },
        function(obj, err, exception) {
            something_went_wrong(err + "! " + exception)
        }
    )
}

// Buttons show "Loading..." and so on while working. This puts all their text back after.
var fix_button_texts = function() {
    $('#reauthenticate').removeClass('loading').html('Reauthenticate').attr('disabled', false)
    $('#submit').removeClass('loading').html('Go').attr('disabled', false)
    $('#clear-data').removeClass('loading').html('Monitor someone else*').attr('disabled', false)
}

var track_search_if_required = function() {
    if(window.trackSearch) {
        scraperwiki.reporting.user({increments: {tf_searches: 1}})
        window.trackSearch = undefined
    }
}

// Show the right form (get settings, or the refresh data one)
var show_hide_stuff = function(done, rename) {
    // Find out what user it is
    scraperwiki.exec('touch user.txt; cat user.txt', function(data) {
        data = $.trim(data)
        $('#q').val(data)
        $('.who').text(data)

        if (rename) {
            scraperwiki.dataset.name("Twitter friends of @" + data)
        }

    // Show expected delivery time
    scraperwiki.sql('select sum(batch_got) as got, sum(batch_expected) as expected from __status', function(results){
	var got = results[0]['got']
	var expected = results[0]['expected']
	$('.batch_got').text(got)
	$('.batch_expected').text(expected)

	var tweets_per_request = 5000
	var request_per_hour = 3
	var hours_left = Math.round((expected - got) / request_per_hour / tweets_per_request)
	var days_left = Math.round(hours_left / 24)
	if (hours_left <= 1) {
	    eta = "1 hour"
	} else if (hours_left < 13) {
	    eta = hours_left + " hours"
	} else if (days_left < 2) {
	    eta = "1 day"
	} else {
	    eta = days_left + " days"
	}
	$('#eta').text(eta)
        }
    )

        // Show right form
        scraperwiki.sql('select * from __status where id = "global"', function(results){
            results = results[0]

            // results['batch_expected'] += 1; // debugging, force a state

            console.log(results)

            $('.settings').hide()
            fix_button_texts()
            $('.done_when').text(moment(results['when']).format("Do MMM YYYY"))
	    // we run @hourly in cron, and until Twitter stops us, which happens with
	    // users/lookup rate limit (18000 in 15 min window, so three chunks of 5000)

            $('pre,.alert-error,.alert-warning,.help-inline').remove()
            $('.control-group').removeClass('error')

            if (results['current_status'] == 'auth-redirect') {
                $('#settings-auth').show()
                $('#settings-clear').show()
                // if during auth, click it
                if (oauth_verifier) {
                    $("#reauthenticate").trigger("click")
                    scraperwiki.dataset.name("Twitter friends of @" + data)
                }
            } else if (results['current_status'] == 'not-there') {
                $('#settings-get').show()
                var p = $('
').addClass('alert alert-error').html("User not found on Twitter! Check the spelling and that they have an account and try again.")
                $('body').prepend(p)
            } else if (results['current_status'] == 'rate-limit') {
                $('#settings-working').show()
                var p = $('
').addClass('alert alert-warning').html('Twitter has asked us to slow down! See the FAQ for details and suggestions.')
                $('body').prepend(p)
                $('#settings-clear').show()
            } else if (results['current_status'] == 'ok-updating') {
                $('#settings-working').show()
                $('#settings-clear').show()
                track_search_if_required()
            } else if (results['current_status'] == 'ok-done') {
                $('#settings-done').show()
                $('#settings-clear').show()
                track_search_if_required()
            } else if (results['current_status'] == 'ok-limit') {
                allow_unlimited_followers(function(allow) {
                  if (allow) {
                    $('#error-too-many').hide()
                    $('#allow-too-many').show()
                  } else {
                    $('#error-too-many').show()
                    $('#allow-too-many').hide()
                  }
                  $('#settings-limit').show()
                  $('#settings-clear').show()
                  track_search_if_required()
                })
            } else if (results['current_status'] == 'clean-slate') {
                $('#settings-get').show()
            } else {
                alert("Unknown internal state: " + results['current_status'])
            }
            if (done) {
                done()
            }
        }, function(results) {
            // this is bad as it will masks real errors - we have to show the form as
            // no SQLite database gives an error
            fix_button_texts()
            $('#settings-get').show()
            if (done) {
                done()
            }
        })
    }, function(obj, err, exception) {
       something_went_wrong(err + "! " + exception)
    })
}

// Get OAuth parameters that we need from the URL
var settings = scraperwiki.readSettings()
var callback_url
var oauth_verifier
scraperwiki.tool.getURL(function(our_url) {
    console.log(our_url)
    var url = $.url(our_url)
    oauth_verifier = url.param('oauth_verifier')
    // remove query parameters for the callback URL, so they don't stack up if we
    // go multiple times to Twitter
    callback_url = url.attr('base') + url.attr('path')
    // only when we have the callback URL, allow the submit button to be clicked
    $("#submit,#reauthenticate,#clear-data").removeAttr("disabled")
})

$(document).ready(function() {
    show_hide_stuff()

    $('#q').on('keypress', function(e){
      if(e.which == 13){
        $('#submit').trigger('click')
      }
    })

    $('#clear-data').on('click', clear_action)
    $('#submit,#reauthenticate').on('click', scrape_action)
    $('#diagnostics').on('click', diagnostics_action)
    $('#get-them-all').on('click', get_them_all)
})

<|endoftext|>


<commit_before>// Info here: http://ad.aloodo.com/

function doAloodoPopup() {
	var url = 'http://www.aloodo.org/protection/';
	var message = 	'Third-party tracking detected. ' +
			'Missing or misconfigured tracking protection.';
	var txt = '' + message + '';

	if (typeof toastr=='undefined') {
		window.setTimeout(doAloodoPopup, 1000);
	} else {
		toastr.options = { 'timeOut': 30000 };
		toastr.error(txt);
	}
}

function toastrSetup() {
	if (typeof toastr !== 'undefined') {
		doAloodoPopup();
	}
	var sc = document.createElement('script');
	sc.setAttribute('src', 'http://ad.aloodo.com/toastr/toastr.js');
	document.body.appendChild(sc);
	sc.onload = doAloodoPopup();
	var cs = document.createElement('link');
	cs.setAttribute("rel", "stylesheet");
	cs.setAttribute("type", "text/css");
	cs.setAttribute("href", 'http://ad.aloodo.com/toastr/toastr.css');
	document.getElementsByTagName('head')[0].appendChild(cs);
}

function startAloodo(ev) {
	if (ev.data !== 'tracking detected') {
		return;
	}

	if (window.trackingAlternateLocation) {
		document.getElementsByTagName('body')[0].style.display='none';
		window.location.href = trackingAlternateLocation;
		return;
	}

	var safety = document.getElementById('tracking-safety');
	if (safety) {
		safety.style.display = 'none';
	}

	var done = false;
	var warning = document.getElementById('tracking-warning-block');
	if (warning) {
		warning.style.display = 'block';
		done = true;
	}
	var warning = document.getElementById('tracking-warning-table-cell');
	if (warning) {
		warning.style.display = 'table-cell';
		done = true;
	}
	var warning = document.getElementById('tracking-warning-inline');
	if (warning) {
		warning.style.display = 'inline';
		done = true;
	}
	if (done) { return; }

	if(typeof jQuery=='undefined') {
		var jq = document.createElement('script');
		jq.src = '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js';
		jq.onload = toastrSetup;
		document.body.appendChild(jq);
	} else {
		toastrSetup();
	}
}

function isMSIE() {
	return "ActiveXObject" in window
}

function setupAloodo() {
	// This puts the tracker in an iframe.
	var ifr = document.createElement('iframe');
	ifr.src = "//ad.aloodo.com/track/";
	ifr.style.visibility = 'hidden';
	document.body.appendChild(ifr);
}

window.addEventListener("message", startAloodo, false);
window.addEventListener("load", setupAloodo);

// Workaround for not being able to send cross-domain messages
// from iframe to its parent.  Assumes that MSIE is unprotected
// if this script runs at all.
if (isMSIE()) {
	window.postMessage('tracking detected', '*');
}
<commit_msg>Use HTTPS for popup in basic script<commit_after>// Info here: http://ad.aloodo.com/

function doAloodoPopup() {
	var url = 'https://www.aloodo.org/protection/';
	var message = 	'Third-party tracking detected. ' +
			'Missing or misconfigured tracking protection.';
	var txt = '' + message + '';

	if (typeof toastr=='undefined') {
		window.setTimeout(doAloodoPopup, 1000);
	} else {
		toastr.options = { 'timeOut': 30000 };
		toastr.error(txt);
	}
}

function toastrSetup() {
	if (typeof toastr !== 'undefined') {
		doAloodoPopup();
	}
	var sc = document.createElement('script');
	sc.setAttribute('src', 'https://ad.aloodo.com/toastr/toastr.js');
	document.body.appendChild(sc);
	sc.onload = doAloodoPopup();
	var cs = document.createElement('link');
	cs.setAttribute("rel", "stylesheet");
	cs.setAttribute("type", "text/css");
	cs.setAttribute("href", 'https://ad.aloodo.com/toastr/toastr.css');
	document.getElementsByTagName('head')[0].appendChild(cs);
}

function startAloodo(ev) {
	if (ev.data !== 'tracking detected') {
		return;
	}

	if (window.trackingAlternateLocation) {
		document.getElementsByTagName('body')[0].style.display='none';
		window.location.href = trackingAlternateLocation;
		return;
	}

	var safety = document.getElementById('tracking-safety');
	if (safety) {
		safety.style.display = 'none';
	}

	var done = false;
	var warning = document.getElementById('tracking-warning-block');
	if (warning) {
		warning.style.display = 'block';
		done = true;
	}
	var warning = document.getElementById('tracking-warning-table-cell');
	if (warning) {
		warning.style.display = 'table-cell';
		done = true;
	}
	var warning = document.getElementById('tracking-warning-inline');
	if (warning) {
		warning.style.display = 'inline';
		done = true;
	}
	if (done) { return; }

	if(typeof jQuery=='undefined') {
		var jq = document.createElement('script');
		jq.src = '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js';
		jq.onload = toastrSetup;
		document.body.appendChild(jq);
	} else {
		toastrSetup();
	}
}

function isMSIE() {
	return "ActiveXObject" in window
}

function setupAloodo() {
	// This puts the tracker in an iframe.
	var ifr = document.createElement('iframe');
	ifr.src = "//ad.aloodo.com/track/";
	ifr.style.visibility = 'hidden';
	document.body.appendChild(ifr);
}

window.addEventListener("message", startAloodo, false);
window.addEventListener("load", setupAloodo);

// Workaround for not being able to send cross-domain messages
// from iframe to its parent.  Assumes that MSIE is unprotected
// if this script runs at all.
if (isMSIE()) {
	window.postMessage('tracking detected', '*');
}
<|endoftext|>


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

const request = require('requestretry');
const fs = require('fs');
const through2 = require('through2');
const keysPath = __dirname + '/keys';
const LimitedParallelStream = require('./src/modules/limited_parallel_stream').LimitedParallelStream;
const byline = require('byline');
const program = require('commander');
const path = require('path');

program
	.version('0.0.1')
	.usage('[options] bucketName')
	.option('-H, --host [host]', 'specify the host (default: http://127.0.0.1)', 'http://127.0.0.1')
	.option('-p, --port [port]', 'specify the post (default: 8098)', 8098)
	.option('-c, --concurrency [concurrency]', 'specify the concurrency (default: 100)', 100)
	.option('-f, --file [file]', 'specify the folder of dump (default: __dirname + /dump)', __dirname + '/dump')
	.parse(process.argv);

if(!program.args.length) {
	console.error('\nBucket is required!');
	program.help();
}

const bucket = program.args[0];
const baseUrl = `${program.host}:${program.port}/riak/${bucket}/`;

/**
 * @TODO: Move this to dump.js
 */

console.info('Dump started ^_^');
request({url: `${baseUrl}?keys=stream`})
	.pipe(through2({ objectMode: true, allowHalfOpen: false, highWaterMark: 50, bufferSize: 30 }, function(chunk, enc, cb){
		let data;
		try{
			data = JSON.parse(chunk.toString());
		}
		catch(e) {
			console.error('Not valid JSON', chunk.toString());
			return cb();
		}

		if(data.keys && data.keys.length > 0) {
			this.push(data.keys.join('\n') + '\n');
		}

		cb()
	}))
	.pipe(fs.createWriteStream(keysPath))
	.on('finish', () =>{
		console.info('\tKeys saved on disk ✔');

		//Start saving all data
		let stream = fs.createReadStream(keysPath);
		stream = byline.createStream(stream);
		stream
			.pipe(new LimitedParallelStream(program.concurrency, function(key, enc, done){
				const url = `${baseUrl}${key}`;
				request({url: url}, (err, data) =>{
					if(!err && data.statusCode === 200) {
						this.push(`${key}\t${data.body}\t${data.headers['content-type']}\n`);
					} else {
						console.error(url, err.message);
					}
					done()
				});
			}))
			.pipe(fs.createWriteStream(path.resolve(program.file)))
			.on('finish', () =>{
				console.info('\tAll data saved on disk ✔')
			})
			.on('error', (err) =>{
				console.error(err)
			})

	})
	.on('error', (e) =>{
		console.error(e)
	});<commit_msg>Fix err<commit_after>#!/usr/bin/env node

const request = require('requestretry');
const fs = require('fs');
const through2 = require('through2');
const keysPath = __dirname + '/keys';
const LimitedParallelStream = require('./src/modules/limited_parallel_stream').LimitedParallelStream;
const byline = require('byline');
const program = require('commander');
const path = require('path');

program
	.version('0.0.1')
	.usage('[options] bucketName')
	.option('-H, --host [host]', 'specify the host (default: http://127.0.0.1)', 'http://127.0.0.1')
	.option('-p, --port [port]', 'specify the post (default: 8098)', 8098)
	.option('-c, --concurrency [concurrency]', 'specify the concurrency (default: 100)', 100)
	.option('-f, --file [file]', 'specify the folder of dump (default: __dirname + /dump)', __dirname + '/dump')
	.parse(process.argv);

if(!program.args.length) {
	console.error('\nBucket is required!');
	program.help();
}

const bucket = program.args[0];
const baseUrl = `${program.host}:${program.port}/riak/${bucket}/`;

/**
 * @TODO: Move this to dump.js
 */

console.info('Dump started ^_^');
request({url: `${baseUrl}?keys=stream`})
	.pipe(through2({ objectMode: true, allowHalfOpen: false, highWaterMark: 50, bufferSize: 30 }, function(chunk, enc, cb){
		let data;
		try{
			data = JSON.parse(chunk.toString());
		}
		catch(e) {
			console.error('Not valid JSON', chunk.toString());
			return cb();
		}

		if(data.keys && data.keys.length > 0) {
			this.push(data.keys.join('\n') + '\n');
		}

		cb()
	}))
	.pipe(fs.createWriteStream(keysPath))
	.on('finish', () =>{
		console.info('\tKeys saved on disk ✔');

		//Start saving all data
		let stream = fs.createReadStream(keysPath);
		stream = byline.createStream(stream);
		stream
			.pipe(new LimitedParallelStream(program.concurrency, function(key, enc, done){
				const url = `${baseUrl}${key}`;
				request({url: url}, (err, data) =>{
					if(!err && data.statusCode === 200) {
						this.push(`${key}\t${data.body}\t${data.headers['content-type']}\n`);
					} else {
						console.error(url, err, 'statusCode:', data.statusCode);
					}
					done()
				});
			}))
			.pipe(fs.createWriteStream(path.resolve(program.file)))
			.on('finish', () =>{
				console.info('\tAll data saved on disk ✔')
			})
			.on('error', (err) =>{
				console.error(err)
			})

	})
	.on('error', (e) =>{
		console.error(e)
	});<|endoftext|>


<commit_before>//Application Frame v0.1.0 - copyright by TitanNano / Jovan Ggerodetti - http://www.titannano.de

"use strict";

import { Make } from './util/make.js';
import { objectExtend } from './util/functions.js';
import Engine from './core/objects.js';

export var $$ = window; //(typeof global != 'undefined') ? window : global;

var userAgentParser= function(userAgentString){
	var items= [];
	var current= '';
	var enabled= true;
	var version= '';
	var engines= ['Gecko', 'AppleWebKit', 'Firefox', 'Safari', 'Chrome', 'OPR', 'Trident'];
	var found= [];
	var record= {};

	for(var i= 0; i < userAgentString.length; i++){
		if(userAgentString[i] == ' ' && enabled){
			items.push(current);
			current= '';
		}else if(userAgentString[i] == '('){
			enabled= false;
		}else if(userAgentString[i] == ')'){
			enabled= true;
		}else{
			current+= userAgentString[i];
		}
	}
	items.push(current);

	items.forEach(function(item){
		if(item.indexOf(';') > -1){
			record.platform= item;
		}else if(item.indexOf('/') > -1){
			item= item.split('/');
			if(item[0] == 'Version'){
				version= item[1];
			}else{
				item.push(engines.indexOf(item[0]));
				found.push(item);
			}
		}
	});

	if(found.length == 1){
		record.engine= found[0][0];
		record.engineVersion= found[0][1];
	}else if(found.length > 1){
		found.sort(function(a, b){
			if(a[2] < b[2])
				return 0;
			else
				return 1;
		});
		record.engine= found[found.length-1][0];
		record.engineVersion= found[found.length-1][1];
	}else{
		record.engine= 'unknown';
		record.engineVersion= '1';
	}

	record.arch= 'x32';

	record.platform.substring(1, record.platform.length-2).split('; ').forEach(function(item){
		if(item.indexOf('OS X') > -1){
			record.platform= item;
			record.arch= 'x64';
		}else if(item.indexOf('Windows') > -1){
			record.platform= item;
		}else if(item.indexOf('Linux') > -1){
			record.platform= item;
		}else if(item.indexOf('WOW64') > -1 || item.indexOf('Win64') > -1 || item.indexOf('x64') > -1){
			record.arch= 'x64';
		}else if(item.indexOf('/') > -1){
			if(engines.indexOf(item.split('/')[0]) > -1){
				record.engine= item.split('/')[0];
				record.engineVersion= item.split('/')[1];
			}
		}else if(item.indexOf(':') < 0){
            record.platform = item;
        }
	});

	if(version !== ''){
		record.engineVersion= version;
	}

	return record;
};

// get the current Platform
var platform= null;

// find out which engine is used
if ($$.navigator){
	Engine.info.type= 'Web';
	objectExtend.apply(Engine.info, [userAgentParser(navigator.userAgent)]);

//  check if touchscreen is supported
    $$.navigator.isTouch= 'ontouchstart' in $$;

// check if current platform is the Mozilla Add-on runtime
}else if($$.exports && $$.require && $$.module){
    var system= $$.require('sdk/system');
	objectExtend.apply(Engine.info, [{
		engine : system.name,
		engineVersion : system.version,
		platform : system.platform + ' ' + system.platformVersion,
		type : 'MozillaAddonSDK',
		arch : system.architecture
	}]);

// check if current platform is the Node.js runtime
}else if($$.process && $$.process.versions && $$.process.env && $$.process.pid){
    objectExtend.apply(Engine.info, [{
		engine : $$.process.name,
		engineVersion : $$.process.versions.node,
		platform : $$.process.platform,
		arch : $$.process.arch,
		type : 'Node'
	}]);
}

//  publish APIs
export var $= Engine.getLibraryItem;
export var $_= Engine.getScope;
<commit_msg>typo fix<commit_after>//Application Frame v0.1.0 - copyright by TitanNano / Jovan Ggerodetti - http://www.titannano.de

"use strict";

import { Make } from './util/make.js';
import { objectExtend } from './util/functions.js';
import Engine from './core/objects/Engine.js';

export var $$ = window; //(typeof global != 'undefined') ? window : global;

var userAgentParser= function(userAgentString){
	var items= [];
	var current= '';
	var enabled= true;
	var version= '';
	var engines= ['Gecko', 'AppleWebKit', 'Firefox', 'Safari', 'Chrome', 'OPR', 'Trident'];
	var found= [];
	var record= {};

	for(var i= 0; i < userAgentString.length; i++){
		if(userAgentString[i] == ' ' && enabled){
			items.push(current);
			current= '';
		}else if(userAgentString[i] == '('){
			enabled= false;
		}else if(userAgentString[i] == ')'){
			enabled= true;
		}else{
			current+= userAgentString[i];
		}
	}
	items.push(current);

	items.forEach(function(item){
		if(item.indexOf(';') > -1){
			record.platform= item;
		}else if(item.indexOf('/') > -1){
			item= item.split('/');
			if(item[0] == 'Version'){
				version= item[1];
			}else{
				item.push(engines.indexOf(item[0]));
				found.push(item);
			}
		}
	});

	if(found.length == 1){
		record.engine= found[0][0];
		record.engineVersion= found[0][1];
	}else if(found.length > 1){
		found.sort(function(a, b){
			if(a[2] < b[2])
				return 0;
			else
				return 1;
		});
		record.engine= found[found.length-1][0];
		record.engineVersion= found[found.length-1][1];
	}else{
		record.engine= 'unknown';
		record.engineVersion= '1';
	}

	record.arch= 'x32';

	record.platform.substring(1, record.platform.length-2).split('; ').forEach(function(item){
		if(item.indexOf('OS X') > -1){
			record.platform= item;
			record.arch= 'x64';
		}else if(item.indexOf('Windows') > -1){
			record.platform= item;
		}else if(item.indexOf('Linux') > -1){
			record.platform= item;
		}else if(item.indexOf('WOW64') > -1 || item.indexOf('Win64') > -1 || item.indexOf('x64') > -1){
			record.arch= 'x64';
		}else if(item.indexOf('/') > -1){
			if(engines.indexOf(item.split('/')[0]) > -1){
				record.engine= item.split('/')[0];
				record.engineVersion= item.split('/')[1];
			}
		}else if(item.indexOf(':') < 0){
            record.platform = item;
        }
	});

	if(version !== ''){
		record.engineVersion= version;
	}

	return record;
};

// get the current Platform
var platform= null;

// find out which engine is used
if ($$.navigator){
	Engine.info.type= 'Web';
	objectExtend.apply(Engine.info, [userAgentParser(navigator.userAgent)]);

//  check if touchscreen is supported
    $$.navigator.isTouch= 'ontouchstart' in $$;

// check if current platform is the Mozilla Add-on runtime
}else if($$.exports && $$.require && $$.module){
    var system= $$.require('sdk/system');
	objectExtend.apply(Engine.info, [{
		engine : system.name,
		engineVersion : system.version,
		platform : system.platform + ' ' + system.platformVersion,
		type : 'MozillaAddonSDK',
		arch : system.architecture
	}]);

// check if current platform is the Node.js runtime
}else if($$.process && $$.process.versions && $$.process.env && $$.process.pid){
    objectExtend.apply(Engine.info, [{
		engine : $$.process.name,
		engineVersion : $$.process.versions.node,
		platform : $$.process.platform,
		arch : $$.process.arch,
		type : 'Node'
	}]);
}

//  publish APIs
export var $= Engine.getLibraryItem;
export var $_= Engine.getScope;
<|endoftext|>


<commit_before>elation.require(['engine.things.generic', 'utils.template'], function() {
  elation.template.add('janusweb.edit.object',
      '<Object id=^{id}^ js_id=^{js_id}^ locked=^false^ pos=^{pos.x} {pos.y} {pos.z}^ vel=^{vel.x} {vel.y} {vel.z}^ accel=^{accel.x} {accel.y} {accel.z}^ xdir=^{xdir}^ ydir=^{ydir}^ zdir=^{zdir}^ scale=^{scale.x} {scale.y} {scale.z}^ col=^{col}^ lighting=^{lighting}^ visible=^{visible}^ />');

  elation.component.add('engine.things.janusbase', function() {
    this.defaultcolor = new THREE.Color(0xffffff);

    this.postinit = function() {
      elation.engine.things.janusbase.extendclass.postinit.call(this);
      this.frameupdates = [];
      this.defineProperties({
        room:     { type: 'object' },
        janus:    { type: 'object' },
        js_id:    { type: 'string' },
        color:    { type: 'color', default: this.defaultcolor, set: this.updateMaterial },
        fwd:      { type: 'vector3', default: new THREE.Vector3(0,0,1), set: this.pushFrameUpdate },
        xdir:     { type: 'vector3', default: new THREE.Vector3(1,0,0), set: this.pushFrameUpdate },
        ydir:     { type: 'vector3', default: new THREE.Vector3(0,1,0), set: this.pushFrameUpdate },
        zdir:     { type: 'vector3', default: new THREE.Vector3(0,0,1), set: this.pushFrameUpdate },
        lighting: { type: 'boolean', default: true },
        sync:     { type: 'boolean', default: false },
        rotate_axis: { type: 'string', default: '0 1 0' },
        rotate_deg_per_sec: { type: 'string' },
        onclick: { type: 'object' },
      });
      //if (this.col) this.color = this.col;
      this.jschildren = [];
      this.assets = {};
      elation.events.add(this.room, 'janusweb_script_frame_end', elation.bind(this, this.handleFrameUpdates));
      elation.events.add(this, 'mouseover,mouseout', elation.bind(this, this.updatePlayerCursor));

      if (this.onclick) {
        if (elation.utils.isString(this.onclick)) {
          elation.events.add(this, 'click', elation.bind(this, function() {
            eval(this.onclick);
          }));

        } else {
          elation.events.add(this, 'click', elation.bind(this, this.onclick));
        }
      }
    }
    this.createForces = function() {
      elation.events.add(this.objects.dynamics, 'physics_collide', elation.bind(this, this.handleCollision));

      var rotate_axis = this.properties.rotate_axis,
          rotate_speed = this.properties.rotate_deg_per_sec;
      if (rotate_axis && rotate_speed) {
        var speed = (rotate_speed * Math.PI/180);
        var axisparts = rotate_axis.split(' ');
        var axis = new THREE.Vector3().set(axisparts[0], axisparts[1], axisparts[2]);
        axis.multiplyScalar(speed);
        this.objects.dynamics.setAngularVelocity(axis);
      }

    }
    this.setProperties = function(props) {
      var n = this.janus.parser.parseNode(props);
      var rebuild = false;

      if (n.pos) this.properties.position.fromArray(n.pos);
      if (n.scale) this.properties.scale.fromArray(n.scale);
      if (n.orientation) this.properties.orientation.copy(n.orientation);

      if (n.id && n.id != this.properties.render.model) {
        this.properties.render.model = n.id;
        rebuild = true;
      }
      var curcol = this.properties.col || [1,1,1];
      if (n.col && (n.col[0] != curcol[0] || n.col[1] != curcol[1] || n.col[2] != curcol[2])) {
        this.properties.col = n.col;
        rebuild = true;
      }
      if (rebuild) {
        //this.set('visible', true, true);
      }
      if (n.accel) this.properties.acceleration.fromArray(n.accel.split(' ').map(parseFloat));
      if (n.vel) this.objects.dynamics.setVelocity(this.properties.velocity.fromArray(n.vel.split(' ').map(parseFloat)));
      this.refresh();
    }
    this.summarizeXML = function() {
      //'<Object id=^{id}^ js_id=^{js_id}^ locked=^false^ pos=^{pos.x} {pos.y} {pos.z}^ vel=^{vel.x} {vel.y} {vel.z}^ accel=^{accel.x} {accel.y} {accel.z}^ xdir=^{xdir}^ ydir=^{ydir}^ zdir=^{zdir}^ scale=^{scale.x} {scale.y} {scale.z}^ col=^{color}^ lighting=^{lighting}^ visible=^{visible}^ />');

      var matrix = new THREE.Matrix4().makeRotationFromQuaternion(this.properties.orientation);
      var xdir = new THREE.Vector3(),
          ydir = new THREE.Vector3(),
          zdir = new THREE.Vector3();
      matrix.extractBasis(xdir, ydir, zdir);

      var objdef = {
        id: this.properties.render.model,
        js_id: this.properties.js_id,
        pos: this.properties.position,
        vel: this.properties.velocity,
        accel: this.properties.acceleration,
        scale: this.properties.scale,
        xdir: xdir.toArray().join(' '),
        ydir: ydir.toArray().join(' '),
        zdir: zdir.toArray().join(' '),
        col: this.properties.color,
        lighting: this.properties.lighting,
        visible: this.properties.visible,
      };

      var xml = elation.template.get('janusweb.edit.object', objdef);
      return xml;
    }
    this.getProxyObject = function() {
      if (!this._proxyobject) {
        this._proxyobject = new elation.proxy(this, {
          js_id:    ['property', 'properties.js_id'],
          pos:      ['property', 'position'],
          vel:      ['property', 'velocity'],
          accel:    ['property', 'acceleration'],
          mass:     ['property', 'mass'],
          scale:    ['property', 'scale'],
          col:      ['property', 'color'],
          fwd:      ['property', 'zdir'],
          xdir:     ['property', 'xdir'],
          ydir:     ['property', 'ydir'],
          zdir:     ['property', 'zdir'],
          sync:     ['property', 'sync'],
          children: ['property', 'jschildren'],

          oncollision: ['callback', 'collision'],
          //onclick:     ['callback', 'click'],

          appendChild: ['function', 'appendChild']
        });
      }
      return this._proxyobject;
    }
    this.getAsset = function(type, id) {
      if (!this.assets[type]) {
        this.assets[type] = {};
      }
      var asset = this.assets[type][id] = this.room.getAsset(type, id);
      return asset;
    }
    this.getActiveAssets = function(assetlist) {
      if (assetlist) {
        for (var type in this.assets) {
          if (!assetlist[type]) assetlist[type] = {};
          for (var url in this.assets[type]) {
            assetlist[type][url] = this.assets[type][url];
          }
        }
      }
      return this.assets;
    }
    this.start = function() {
    }
    this.stop = function() {
    }
    this.pushFrameUpdate = function(key, value) {
//console.log('frame update!', key, value);
      this.frameupdates[key] = value;
    }
    this.handleFrameUpdates = function() {
      var updatenames = Object.keys(this.frameupdates);
      var xdir = this.properties.xdir,
          ydir = this.properties.ydir,
          zdir = this.properties.zdir,
          m = this.objects['3d'].matrix.elements;
      var diff = (
          xdir.x != m[0] || xdir.y != m[1] || xdir.z != m[2] ||
          ydir.x != m[4] || ydir.y != m[5] || ydir.z != m[6] ||
          zdir.x != m[8] || zdir.y != m[9] || zdir.z != m[10]
      );
      if (updatenames.length > 0 || diff) {
        var updates = this.frameupdates;
        if ('fwd' in updates) {
          this.properties.zdir.copy(this.fwd);
          updates.zdir = this.properties.zdir;
        }

        if ( ('xdir' in updates) &&
            !('ydir' in updates) &&
            !('zdir' in updates)) {
          zdir.crossVectors(xdir, ydir);
          this.updateVectors(true);
        }
        if (!('xdir' in updates) &&
            !('ydir' in updates) &&
             ('zdir' in updates)) {
          xdir.crossVectors(ydir, zdir);
          this.updateVectors(true);
        }
        if (!('xdir' in updates) &&
             ('ydir' in updates) &&
             ('zdir' in updates)) {
          xdir.crossVectors(zdir, ydir);
          this.updateVectors(true);
        }
        if ( ('xdir' in updates) &&
            !('ydir' in updates) &&
             ('zdir' in updates)) {
          ydir.crossVectors(xdir, zdir).multiplyScalar(-1);
          this.updateVectors(true);
        }
        if ( ('xdir' in updates) &&
             ('ydir' in updates) &&
            !('zdir' in updates)) {
          zdir.crossVectors(xdir, ydir);
          this.updateVectors(true);
        }

        if (!('xdir' in updates) &&
            !('ydir' in updates) &&
            !('zdir' in updates)) {
          // None specified, so update the vectors from the orientation quaternion
          this.updateVectors(false);
        }
        this.frameupdates = {};
      } else {
        this.updateVectors(false);
      }
    }
    this.updateVectors = function(updateOrientation) {
      if (updateOrientation) {
        //var quat = this.room.getOrientation(this.properties.xdir.toArray().join(' '), this.properties.ydir.toArray().join(' '), this.properties.zdir.toArray().join(' '));
        //this.xdir.normalize();
        //this.ydir.normalize();
        //this.zdir.normalize();
        var mat4 = new THREE.Matrix4();
        mat4.makeBasis(this.properties.xdir, this.properties.ydir, this.properties.zdir);

/*
        mat4.set(
          this.xdir.x, this.xdir.y, this.xdir.z, 0,
          this.ydir.x, this.ydir.y, this.ydir.z, 0,
          this.zdir.x, this.zdir.y, this.zdir.z, 0,
          0, 0, 0, 1
        );
*/

        var quat = new THREE.Quaternion();
        var pos = new THREE.Vector3();
        var scale = new THREE.Vector3();
        quat.setFromRotationMatrix(mat4);
        //mat4.decompose(pos, this.orientation, scale);
        //this.orientation.normalize();
//console.log(mat4.elements);
        this.properties.orientation.copy(quat);
//console.log(this.xdir.toArray(), this.ydir.toArray(), this.zdir.toArray(), this.orientation.toArray());
//console.log(this.properties.orientation, this.properties.orientation.toArray());
      } else if (this.objects['3d']) {
        //this.objects['3d'].matrix.extractBasis(this.properties.xdir, this.properties.ydir, this.properties.zdir);
      }
    }
    this.appendChild = function(obj) {
      var proxyobj = obj
      if (elation.utils.isString(obj)) {
        proxyobj = this.room.jsobjects[obj];
      }
      if (proxyobj) {
        //var realobj = this.room.getObjectFromProxy(proxyobj);
        var realobj = proxyobj._target;
        if (realobj) {
          this.add(realobj);
          this.updateScriptChildren();
        }
      }
    }
    this.removeChild = function(obj) {
      var proxyobj = obj
      if (elation.utils.isString(obj)) {
        proxyobj = this.room.jsobjects[obj];
      }
      if (proxyobj) {
        //var realobj = this.room.getObjectFromProxy(proxyobj);
        var realobj = proxyobj._target;
        if (realobj) {
          this.remove(realobj);
          this.updateScriptChildren();
        }
      }
    }
    this.updateScriptChildren = function() {
      this.jschildren = [];
      var keys = Object.keys(this.children);
      for (var i = 0; i < keys.length; i++) {
        this.jschildren.push(this.children[keys[i]].getProxyObject());
      }
    }
    this.handleCollision = function(ev) {
      var obj1 = ev.data.bodies[0],
          obj2 = ev.data.bodies[1];
      //var proxy1 = obj1.getProxy(),
      //    proxy2 = obj2.getProxy();
      var other = (obj1.object == this ? obj2.object : obj1.object);
      if (other) {
        if (other.getProxyObject) {
          var proxy = other.getProxyObject();
          //console.log('I collided', proxy, this);
          elation.events.fire({type: 'collision', element: this, data: proxy});
        } else {
console.error('dunno what this is', other);
        }
      }
    }
    this.setOpacity = function(opacity) {
      this.objects['3d'].traverse(function(n) {
        if (n.material) {
          n.material.opacity = opacity;
        }
      });
    }
    this.updatePlayerCursor = function(ev) {
      if (ev.type == 'mouseover' && this.onclick) {
        this.engine.client.player.cursor_style = 'pointer';
      } else if (this.engine.systems.controls.pointerLockActive) {
        this.engine.client.player.cursor_style = 'crosshair';
      } else {
        this.engine.client.player.cursor_style = 'default';
      }
    }
  }, elation.engine.things.generic);
});
<commit_msg>Improved cursor logic for VR<commit_after>elation.require(['engine.things.generic', 'utils.template'], function() {
  elation.template.add('janusweb.edit.object',
      '<Object id=^{id}^ js_id=^{js_id}^ locked=^false^ pos=^{pos.x} {pos.y} {pos.z}^ vel=^{vel.x} {vel.y} {vel.z}^ accel=^{accel.x} {accel.y} {accel.z}^ xdir=^{xdir}^ ydir=^{ydir}^ zdir=^{zdir}^ scale=^{scale.x} {scale.y} {scale.z}^ col=^{col}^ lighting=^{lighting}^ visible=^{visible}^ />');

  elation.component.add('engine.things.janusbase', function() {
    this.defaultcolor = new THREE.Color(0xffffff);

    this.postinit = function() {
      elation.engine.things.janusbase.extendclass.postinit.call(this);
      this.frameupdates = [];
      this.defineProperties({
        room:     { type: 'object' },
        janus:    { type: 'object' },
        js_id:    { type: 'string' },
        color:    { type: 'color', default: this.defaultcolor, set: this.updateMaterial },
        fwd:      { type: 'vector3', default: new THREE.Vector3(0,0,1), set: this.pushFrameUpdate },
        xdir:     { type: 'vector3', default: new THREE.Vector3(1,0,0), set: this.pushFrameUpdate },
        ydir:     { type: 'vector3', default: new THREE.Vector3(0,1,0), set: this.pushFrameUpdate },
        zdir:     { type: 'vector3', default: new THREE.Vector3(0,0,1), set: this.pushFrameUpdate },
        lighting: { type: 'boolean', default: true },
        sync:     { type: 'boolean', default: false },
        rotate_axis: { type: 'string', default: '0 1 0' },
        rotate_deg_per_sec: { type: 'string' },
        onclick: { type: 'object' },
      });
      //if (this.col) this.color = this.col;
      this.jschildren = [];
      this.assets = {};
      elation.events.add(this.room, 'janusweb_script_frame_end', elation.bind(this, this.handleFrameUpdates));
      elation.events.add(this, 'mouseover,mouseout', elation.bind(this, this.updatePlayerCursor));

      if (this.onclick) {
        if (elation.utils.isString(this.onclick)) {
          elation.events.add(this, 'click', elation.bind(this, function() {
            eval(this.onclick);
          }));

        } else {
          elation.events.add(this, 'click', elation.bind(this, this.onclick));
        }
      }
    }
    this.createForces = function() {
      elation.events.add(this.objects.dynamics, 'physics_collide', elation.bind(this, this.handleCollision));

      var rotate_axis = this.properties.rotate_axis,
          rotate_speed = this.properties.rotate_deg_per_sec;
      if (rotate_axis && rotate_speed) {
        var speed = (rotate_speed * Math.PI/180);
        var axisparts = rotate_axis.split(' ');
        var axis = new THREE.Vector3().set(axisparts[0], axisparts[1], axisparts[2]);
        axis.multiplyScalar(speed);
        this.objects.dynamics.setAngularVelocity(axis);
      }

    }
    this.setProperties = function(props) {
      var n = this.janus.parser.parseNode(props);
      var rebuild = false;

      if (n.pos) this.properties.position.fromArray(n.pos);
      if (n.scale) this.properties.scale.fromArray(n.scale);
      if (n.orientation) this.properties.orientation.copy(n.orientation);

      if (n.id && n.id != this.properties.render.model) {
        this.properties.render.model = n.id;
        rebuild = true;
      }
      var curcol = this.properties.col || [1,1,1];
      if (n.col && (n.col[0] != curcol[0] || n.col[1] != curcol[1] || n.col[2] != curcol[2])) {
        this.properties.col = n.col;
        rebuild = true;
      }
      if (rebuild) {
        //this.set('visible', true, true);
      }
      if (n.accel) this.properties.acceleration.fromArray(n.accel.split(' ').map(parseFloat));
      if (n.vel) this.objects.dynamics.setVelocity(this.properties.velocity.fromArray(n.vel.split(' ').map(parseFloat)));
      this.refresh();
    }
    this.summarizeXML = function() {
      //'<Object id=^{id}^ js_id=^{js_id}^ locked=^false^ pos=^{pos.x} {pos.y} {pos.z}^ vel=^{vel.x} {vel.y} {vel.z}^ accel=^{accel.x} {accel.y} {accel.z}^ xdir=^{xdir}^ ydir=^{ydir}^ zdir=^{zdir}^ scale=^{scale.x} {scale.y} {scale.z}^ col=^{color}^ lighting=^{lighting}^ visible=^{visible}^ />');

      var matrix = new THREE.Matrix4().makeRotationFromQuaternion(this.properties.orientation);
      var xdir = new THREE.Vector3(),
          ydir = new THREE.Vector3(),
          zdir = new THREE.Vector3();
      matrix.extractBasis(xdir, ydir, zdir);

      var objdef = {
        id: this.properties.render.model,
        js_id: this.properties.js_id,
        pos: this.properties.position,
        vel: this.properties.velocity,
        accel: this.properties.acceleration,
        scale: this.properties.scale,
        xdir: xdir.toArray().join(' '),
        ydir: ydir.toArray().join(' '),
        zdir: zdir.toArray().join(' '),
        col: this.properties.color,
        lighting: this.properties.lighting,
        visible: this.properties.visible,
      };

      var xml = elation.template.get('janusweb.edit.object', objdef);
      return xml;
    }
    this.getProxyObject = function() {
      if (!this._proxyobject) {
        this._proxyobject = new elation.proxy(this, {
          js_id:    ['property', 'properties.js_id'],
          pos:      ['property', 'position'],
          vel:      ['property', 'velocity'],
          accel:    ['property', 'acceleration'],
          mass:     ['property', 'mass'],
          scale:    ['property', 'scale'],
          col:      ['property', 'color'],
          fwd:      ['property', 'zdir'],
          xdir:     ['property', 'xdir'],
          ydir:     ['property', 'ydir'],
          zdir:     ['property', 'zdir'],
          sync:     ['property', 'sync'],
          children: ['property', 'jschildren'],

          oncollision: ['callback', 'collision'],
          //onclick:     ['callback', 'click'],

          appendChild: ['function', 'appendChild']
        });
      }
      return this._proxyobject;
    }
    this.getAsset = function(type, id) {
      if (!this.assets[type]) {
        this.assets[type] = {};
      }
      var asset = this.assets[type][id] = this.room.getAsset(type, id);
      return asset;
    }
    this.getActiveAssets = function(assetlist) {
      if (assetlist) {
        for (var type in this.assets) {
          if (!assetlist[type]) assetlist[type] = {};
          for (var url in this.assets[type]) {
            assetlist[type][url] = this.assets[type][url];
          }
        }
      }
      return this.assets;
    }
    this.start = function() {
    }
    this.stop = function() {
    }
    this.pushFrameUpdate = function(key, value) {
//console.log('frame update!', key, value);
      this.frameupdates[key] = value;
    }
    this.handleFrameUpdates = function() {
      var updatenames = Object.keys(this.frameupdates);
      var xdir = this.properties.xdir,
          ydir = this.properties.ydir,
          zdir = this.properties.zdir,
          m = this.objects['3d'].matrix.elements;
      var diff = (
          xdir.x != m[0] || xdir.y != m[1] || xdir.z != m[2] ||
          ydir.x != m[4] || ydir.y != m[5] || ydir.z != m[6] ||
          zdir.x != m[8] || zdir.y != m[9] || zdir.z != m[10]
      );
      if (updatenames.length > 0 || diff) {
        var updates = this.frameupdates;
        if ('fwd' in updates) {
          this.properties.zdir.copy(this.fwd);
          updates.zdir = this.properties.zdir;
        }

        if ( ('xdir' in updates) &&
            !('ydir' in updates) &&
            !('zdir' in updates)) {
          zdir.crossVectors(xdir, ydir);
          this.updateVectors(true);
        }
        if (!('xdir' in updates) &&
            !('ydir' in updates) &&
             ('zdir' in updates)) {
          xdir.crossVectors(ydir, zdir);
          this.updateVectors(true);
        }
        if (!('xdir' in updates) &&
             ('ydir' in updates) &&
             ('zdir' in updates)) {
          xdir.crossVectors(zdir, ydir);
          this.updateVectors(true);
        }
        if ( ('xdir' in updates) &&
            !('ydir' in updates) &&
             ('zdir' in updates)) {
          ydir.crossVectors(xdir, zdir).multiplyScalar(-1);
          this.updateVectors(true);
        }
        if ( ('xdir' in updates) &&
             ('ydir' in updates) &&
            !('zdir' in updates)) {
          zdir.crossVectors(xdir, ydir);
          this.updateVectors(true);
        }

        if (!('xdir' in updates) &&
            !('ydir' in updates) &&
            !('zdir' in updates)) {
          // None specified, so update the vectors from the orientation quaternion
          this.updateVectors(false);
        }
        this.frameupdates = {};
      } else {
        this.updateVectors(false);
      }
    }
    this.updateVectors = function(updateOrientation) {
      if (updateOrientation) {
        //var quat = this.room.getOrientation(this.properties.xdir.toArray().join(' '), this.properties.ydir.toArray().join(' '), this.properties.zdir.toArray().join(' '));
        //this.xdir.normalize();
        //this.ydir.normalize();
        //this.zdir.normalize();
        var mat4 = new THREE.Matrix4();
        mat4.makeBasis(this.properties.xdir, this.properties.ydir, this.properties.zdir);

/*
        mat4.set(
          this.xdir.x, this.xdir.y, this.xdir.z, 0,
          this.ydir.x, this.ydir.y, this.ydir.z, 0,
          this.zdir.x, this.zdir.y, this.zdir.z, 0,
          0, 0, 0, 1
        );
*/

        var quat = new THREE.Quaternion();
        var pos = new THREE.Vector3();
        var scale = new THREE.Vector3();
        quat.setFromRotationMatrix(mat4);
        //mat4.decompose(pos, this.orientation, scale);
        //this.orientation.normalize();
//console.log(mat4.elements);
        this.properties.orientation.copy(quat);
//console.log(this.xdir.toArray(), this.ydir.toArray(), this.zdir.toArray(), this.orientation.toArray());
//console.log(this.properties.orientation, this.properties.orientation.toArray());
      } else if (this.objects['3d']) {
        //this.objects['3d'].matrix.extractBasis(this.properties.xdir, this.properties.ydir, this.properties.zdir);
      }
    }
    this.appendChild = function(obj) {
      var proxyobj = obj
      if (elation.utils.isString(obj)) {
        proxyobj = this.room.jsobjects[obj];
      }
      if (proxyobj) {
        //var realobj = this.room.getObjectFromProxy(proxyobj);
        var realobj = proxyobj._target;
        if (realobj) {
          this.add(realobj);
          this.updateScriptChildren();
        }
      }
    }
    this.removeChild = function(obj) {
      var proxyobj = obj
      if (elation.utils.isString(obj)) {
        proxyobj = this.room.jsobjects[obj];
      }
      if (proxyobj) {
        //var realobj = this.room.getObjectFromProxy(proxyobj);
        var realobj = proxyobj._target;
        if (realobj) {
          this.remove(realobj);
          this.updateScriptChildren();
        }
      }
    }
    this.updateScriptChildren = function() {
      this.jschildren = [];
      var keys = Object.keys(this.children);
      for (var i = 0; i < keys.length; i++) {
        this.jschildren.push(this.children[keys[i]].getProxyObject());
      }
    }
    this.handleCollision = function(ev) {
      var obj1 = ev.data.bodies[0],
          obj2 = ev.data.bodies[1];
      //var proxy1 = obj1.getProxy(),
      //    proxy2 = obj2.getProxy();
      var other = (obj1.object == this ? obj2.object : obj1.object);
      if (other) {
        if (other.getProxyObject) {
          var proxy = other.getProxyObject();
          //console.log('I collided', proxy, this);
          elation.events.fire({type: 'collision', element: this, data: proxy});
        } else {
console.error('dunno what this is', other);
        }
      }
    }
    this.setOpacity = function(opacity) {
      this.objects['3d'].traverse(function(n) {
        if (n.material) {
          n.material.opacity = opacity;
        }
      });
    }
    this.updatePlayerCursor = function(ev) {
      var vrdisplay = this.engine.systems.render.views.main.vrdisplay;
      if (ev.type == 'mouseover' && (this.onclick || elation.events.hasEventListener(this, 'click'))) {
        this.engine.client.player.cursor_style = 'pointer';
      } else if (this.engine.systems.controls.pointerLockActive || (vrdisplay && vrdisplay.isPresenting)) {
        this.engine.client.player.cursor_style = 'crosshair';
      } else {
        this.engine.client.player.cursor_style = 'default';
      }
    }
  }, elation.engine.things.generic);
});
<|endoftext|>


<commit_before>'use strict';

angular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions'])

  .provider('$affix', function() {

    var defaults = this.defaults = {
      offsetTop: 'auto'
    };

    this.$get = function($window, dimensions) {

      var bodyEl = angular.element($window.document.body);

      function AffixFactory(element, config) {

        var $affix = {};

        // Common vars
        var options = angular.extend({}, defaults, config);
        var targetEl = options.target;

        // Initial private vars
        var reset = 'affix affix-top affix-bottom',
            initialAffixTop = 0,
            initialOffsetTop = 0,
            affixed = null,
            unpin = null;

        var parent = element.parent();
        // Options: custom parent
        if (options.offsetParent) {
          if (options.offsetParent.match(/^\d+$/)) {
            for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {
              parent = parent.parent();
            }
          }
          else {
            parent = angular.element(options.offsetParent);
          }
        }

        // Options: offsets
        var offsetTop = 0;
        if(options.offsetTop) {
          if(options.offsetTop === 'auto') {
            options.offsetTop = '+0';
          }
          if(options.offsetTop.match(/^[-+]\d+$/)) {
            initialAffixTop -= options.offsetTop * 1;
            if(options.offsetParent) {
              offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);
            }
            else {
              offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);
            }
          }
          else {
            offsetTop = options.offsetTop * 1;
          }
        }

        var offsetBottom = 0;
        if(options.offsetBottom) {
          if(options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) {
            // add 1 pixel due to rounding problems...
            offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;
          }
          else {
            offsetBottom = options.offsetBottom * 1;
          }
        }

        $affix.init = function() {

          initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;

          // Bind events
          targetEl.on('scroll', $affix.checkPosition);
          targetEl.on('click', $affix.checkPositionWithEventLoop);
          // Both of these checkPosition() calls are necessary for the case where
          // the user hits refresh after scrolling to the bottom of the page.
          $affix.checkPosition();
          $affix.checkPositionWithEventLoop();

        };

        $affix.destroy = function() {

          // Unbind events
          targetEl.off('scroll', $affix.checkPosition);
          targetEl.off('click', $affix.checkPositionWithEventLoop);

        };

        $affix.checkPositionWithEventLoop = function() {

          setTimeout($affix.checkPosition, 1);

        };

        $affix.checkPosition = function() {
          // if (!this.$element.is(':visible')) return

          var scrollTop = getScrollTop();
          var position = dimensions.offset(element[0]);
          var elementHeight = dimensions.height(element[0]);

          // Get required affix class according to position
          var affix = getRequiredAffixClass(unpin, position, elementHeight);

          // Did affix status changed this last check?
          if(affixed === affix) return;
          affixed = affix;

          // Add proper affix class
          element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));

          if(affix === 'top') {
            unpin = null;
            element.css('position', (options.offsetParent) ? '' : 'relative');
            element.css('top', '');
          } else if(affix === 'bottom') {
            if (options.offsetUnpin) {
              unpin = -(options.offsetUnpin * 1);
            }
            else {
              // Calculate unpin threshold when affixed to bottom.
              // Hopefully the browser scrolls pixel by pixel.
              unpin = position.top - scrollTop;
            }
            element.css('position', (options.offsetParent) ? '' : 'relative');
            element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));
          } else { // affix === 'middle'
            unpin = null;
            element.css('position', 'fixed');
            element.css('top', initialAffixTop + 'px');
          }

        };

        // Private methods

        function getRequiredAffixClass(unpin, position, elementHeight) {

          var scrollTop = getScrollTop();
          var scrollHeight = getScrollHeight();

          if(scrollTop <= offsetTop) {
            return 'top';
          } else if(unpin !== null && (scrollTop + unpin <= position.top)) {
            return 'middle';
          } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {
            return 'bottom';
          } else {
            return 'middle';
          }

        }

        function getScrollTop() {
          return targetEl[0] === $window ? $window.pageYOffset : targetEl[0] === $window;
        }

        function getScrollHeight() {
          return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;
        }

        $affix.init();
        return $affix;

      }

      return AffixFactory;

    };

  })

  .directive('bsAffix', function($affix, $window) {

    return {
      restrict: 'EAC',
      require: '^?bsAffixTarget',
      link: function postLink(scope, element, attr, affixTarget) {

        var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};
        angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {
          if(angular.isDefined(attr[key])) options[key] = attr[key];
        });

        var affix = $affix(element, options);
        scope.$on('$destroy', function() {
          options = null;
          affix = null;
        });

      }
    };

  })

  .directive('bsAffixTarget', function() {
    return {
      controller: function($element) {
        this.$element = $element;
      }
    };
  });
<commit_msg>fix(affix): properly handle window resize (fixes #552)<commit_after>'use strict';

angular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions'])

  .provider('$affix', function() {

    var defaults = this.defaults = {
      offsetTop: 'auto'
    };

    this.$get = function($window, debounce, dimensions) {

      var bodyEl = angular.element($window.document.body);
      var windowEl = angular.element($window);

      function AffixFactory(element, config) {

        var $affix = {};

        // Common vars
        var options = angular.extend({}, defaults, config);
        var targetEl = options.target;

        // Initial private vars
        var reset = 'affix affix-top affix-bottom',
            initialAffixTop = 0,
            initialOffsetTop = 0,
            offsetTop = 0,
            offsetBottom = 0,
            affixed = null,
            unpin = null;

        var parent = element.parent();
        // Options: custom parent
        if (options.offsetParent) {
          if (options.offsetParent.match(/^\d+$/)) {
            for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {
              parent = parent.parent();
            }
          }
          else {
            parent = angular.element(options.offsetParent);
          }
        }

        $affix.init = function() {

          $affix.$parseOffsets();
          initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;

          // Bind events
          targetEl.on('scroll', $affix.checkPosition);
          targetEl.on('click', $affix.checkPositionWithEventLoop);
          windowEl.on('resize', $affix.$debouncedOnResize);

          // Both of these checkPosition() calls are necessary for the case where
          // the user hits refresh after scrolling to the bottom of the page.
          $affix.checkPosition();
          $affix.checkPositionWithEventLoop();

        };

        $affix.destroy = function() {

          // Unbind events
          targetEl.off('scroll', $affix.checkPosition);
          targetEl.off('click', $affix.checkPositionWithEventLoop);
          windowEl.off('resize', $affix.$debouncedOnResize);

        };

        $affix.checkPositionWithEventLoop = function() {

          setTimeout($affix.checkPosition, 1);

        };

        $affix.checkPosition = function() {
          // if (!this.$element.is(':visible')) return

          var scrollTop = getScrollTop();
          var position = dimensions.offset(element[0]);
          var elementHeight = dimensions.height(element[0]);

          // Get required affix class according to position
          var affix = getRequiredAffixClass(unpin, position, elementHeight);

          // Did affix status changed this last check?
          if(affixed === affix) return;
          affixed = affix;

          // Add proper affix class
          element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));

          if(affix === 'top') {
            unpin = null;
            element.css('position', (options.offsetParent) ? '' : 'relative');
            element.css('top', '');
          } else if(affix === 'bottom') {
            if (options.offsetUnpin) {
              unpin = -(options.offsetUnpin * 1);
            }
            else {
              // Calculate unpin threshold when affixed to bottom.
              // Hopefully the browser scrolls pixel by pixel.
              unpin = position.top - scrollTop;
            }
            element.css('position', (options.offsetParent) ? '' : 'relative');
            element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));
          } else { // affix === 'middle'
            unpin = null;
            element.css('position', 'fixed');
            element.css('top', initialAffixTop + 'px');
          }

        };

        $affix.$onResize = function() {
          $affix.$parseOffsets();
          $affix.checkPosition();
        };
        $affix.$debouncedOnResize = debounce($affix.$onResize, 50);

        $affix.$parseOffsets = function() {

          // Reset position to calculate correct offsetTop
          element.css('position', (options.offsetParent) ? '' : 'relative');

          if(options.offsetTop) {
            if(options.offsetTop === 'auto') {
              options.offsetTop = '+0';
            }
            if(options.offsetTop.match(/^[-+]\d+$/)) {
              initialAffixTop = - options.offsetTop * 1;
              if(options.offsetParent) {
                offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);
              }
              else {
                offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);
              }
            }
            else {
              offsetTop = options.offsetTop * 1;
            }
          }

          if(options.offsetBottom) {
            if(options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) {
              // add 1 pixel due to rounding problems...
              offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;
            }
            else {
              offsetBottom = options.offsetBottom * 1;
            }
          }

        };

        // Private methods

        function getRequiredAffixClass(unpin, position, elementHeight) {

          var scrollTop = getScrollTop();
          var scrollHeight = getScrollHeight();

          if(scrollTop <= offsetTop) {
            return 'top';
          } else if(unpin !== null && (scrollTop + unpin <= position.top)) {
            return 'middle';
          } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {
            return 'bottom';
          } else {
            return 'middle';
          }

        }

        function getScrollTop() {
          return targetEl[0] === $window ? $window.pageYOffset : targetEl[0] === $window;
        }

        function getScrollHeight() {
          return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;
        }

        $affix.init();
        return $affix;

      }

      return AffixFactory;

    };

  })

  .directive('bsAffix', function($affix, $window) {

    return {
      restrict: 'EAC',
      require: '^?bsAffixTarget',
      link: function postLink(scope, element, attr, affixTarget) {

        var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};
        angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {
          if(angular.isDefined(attr[key])) options[key] = attr[key];
        });

        var affix = $affix(element, options);
        scope.$on('$destroy', function() {
          options = null;
          affix = null;
        });

      }
    };

  })

  .directive('bsAffixTarget', function() {
    return {
      controller: function($element) {
        this.$element = $element;
      }
    };
  });
<|endoftext|>


<commit_before>/** @flow */
import * as fs from 'fs';
import {Engine} from './engine';
import {Response} from './response';
import {Request} from './request';
import {PathLayer} from './pathlayer';

/** Application class, the barebone of enchanter */
class Application {

    settings: Map<string, any>;
    pages: PathLayer[];
    engines: any;
    engine: Engine;

    constructor() {
        this.settings = new Map();
        this.pages = [];
    }

    init() {
        if (!this.engine) {
            var options:any = {
                defaultEngineName: this._get('view engine'),
                defaultEngine: this._get('view module'),
                root: this._get('views'),
                engines: []
            };
            this.engine = new Engine(options);
        }
    }

    /**
     * Assign `setting` to `val`, or return `setting`'s value.
     *
     *    app.set('foo', 'bar');
     *    app.get('foo');
     *    // => "bar"
     *
     * Mounted servers inherit their parent server's settings.
     *
     * @param {String} setting
     * @param {*} [val]
     * @return {Server} for chaining
     * @public
     */
     set(setting: string, value: ?Object) {
        if (arguments.length === 1) {
            // app.get(setting)
            return this.settings.get(setting);
        }
        // set value
        this.settings.set(setting, value);

        return this;
    }

    /**
     * return `setting`'s value.
     *
     *    app.get('foo');
     *    // => "bar"
     *
     * @param {String} setting
     * @param {*} [val]
     * @return {Server} for chaining
     * @public
     */
     _get(setting: string) {
        return this.set(setting);
     }

    /**
     * Adding a page to the application
     *
     *    app.page('/', (context) => {
     *    });
     *
     * Mounted servers inherit their parent server's settings.
     *
     * @param {String} path
     * @param {*} [fn] function to bind
     * @return {Server} for chaining
     * @public
     */
     page(path: string, fn: Function) {
        this.pages.push(new PathLayer(path, {}, fn));
        return this;
     }

     /**
     * Adding a page to the application
     *
     *    app.all('/', (context) => {
     *    });
     *
     * Mounted servers inherit their parent server's settings.
     *
     * @param {String} path
     * @param {*} [fn] function to bind
     * @return {Server} for chaining
     * @public
     */
     all = (path: string, fn: Function) => this.page(path, fn);
     get = (path: string, fn: Function) => this.page(path, fn);
     post = (path: string, fn: Function) => this.page(path, fn);
     put = (path: string, fn: Function) => this.page(path, fn);
     del = (path: string, fn: Function) => this.page(path, fn);

    /**
     * Generate all the pages that are registered in this application
     *
     */
    generateAll() {
        console.log("generate files");

        // iterate over all the pages and execute them
        for (let layer: PathLayer of this.pages) {
             this.generate(layer.route);
        };
    }

    /**
     * generate a specific page, with its according route name
     *
     * @param {String} page, the route name that is been registered in the map
     * @public
     */
    generate(page: string) {
        console.log(`start generate ${page}`);
        // first initialize objects
        this.init();

        // iterate over all the pages that are registered
        // views directory with the templates
        var views = this._get('views');
        if (!views) views = __dirname + "/views";
        // output directory
        var output = this._get('output');
        if (!output) output = __dirname + "/out";

        let pathLayer = this.matchOnPage(page);
        // do something with obj
        if (pathLayer != null) {
            var response = new Response(this.engine, `${output.toString()}${page}`);
            var request = new Request(page, pathLayer.params, pathLayer, this);
            pathLayer.handle.call(this, request, response);
            console.log(`generate files ${page}`);
        }
    }

    /**
     * Adding a shortcut to the generate function, it generates a specific page.
     *
     * @param {String} page, the route name that is been registered in the map
     * @public
     */
    gen = (page: string) => this.generate(page);

    matchOnPage(page: string) {
        for (let layer: PathLayer of this.pages) {
            if (layer.match(page)) {
                return layer;
            }
        }
        return null;
    }
}

module.exports = function(express: any) {
    if ((process.argv[2] === '--dynamic' || process.argv[2] === '-d') && express !== undefined) {
        return express();
    } else {
        return new Application();
    }
};<commit_msg>adding event emitter to the application class<commit_after>/** @flow */
import * as fs from 'fs';
import {Engine} from './engine';
import {Response} from './response';
import {Request} from './request';
import {PathLayer} from './pathlayer';
import {EventEmitter} from 'events';

/** Application class, the barebone of enchanter */
class Application extends EventEmitter {

    settings: Map<string, any>;
    pages: PathLayer[];
    engines: any;
    engine: Engine;

    constructor() {
        this.settings = new Map();
        this.pages = [];
    }

    init() {
        if (!this.engine) {
            var options:any = {
                defaultEngineName: this._get('view engine'),
                defaultEngine: this._get('view module'),
                root: this._get('views'),
                engines: []
            };
            this.engine = new Engine(options);
        }
    }

    /**
     * Assign `setting` to `val`, or return `setting`'s value.
     *
     *    app.set('foo', 'bar');
     *    app.get('foo');
     *    // => "bar"
     *
     * Mounted servers inherit their parent server's settings.
     *
     * @param {String} setting
     * @param {*} [val]
     * @return {Server} for chaining
     * @public
     */
     set(setting: string, value: ?Object) {
        if (arguments.length === 1) {
            // app.get(setting)
            return this.settings.get(setting);
        }
        // set value
        this.settings.set(setting, value);

        return this;
    }

    /**
     * return `setting`'s value.
     *
     *    app.get('foo');
     *    // => "bar"
     *
     * @param {String} setting
     * @param {*} [val]
     * @return {Server} for chaining
     * @public
     */
     _get(setting: string) {
        return this.set(setting);
     }

    /**
     * Adding a page to the application
     *
     *    app.page('/', (context) => {
     *    });
     *
     * Mounted servers inherit their parent server's settings.
     *
     * @param {String} path
     * @param {*} [fn] function to bind
     * @return {Server} for chaining
     * @public
     */
     page(path: string, fn: Function) {
        this.pages.push(new PathLayer(path, {}, fn));
        return this;
     }

     /**
     * Adding a page to the application
     *
     *    app.all('/', (context) => {
     *    });
     *
     * Mounted servers inherit their parent server's settings.
     *
     * @param {String} path
     * @param {*} [fn] function to bind
     * @return {Server} for chaining
     * @public
     */
     all = (path: string, fn: Function) => this.page(path, fn);
     get = (path: string, fn: Function) => this.page(path, fn);
     post = (path: string, fn: Function) => this.page(path, fn);
     put = (path: string, fn: Function) => this.page(path, fn);
     del = (path: string, fn: Function) => this.page(path, fn);

    /**
     * Generate all the pages that are registered in this application
     *
     */
    generateAll() {
        console.log("generate files");

        // iterate over all the pages and execute them
        for (let layer: PathLayer of this.pages) {
             this.generate(layer.route);
        };
        this.emit('all');
    }

    /**
     * generate a specific page, with its according route name
     *
     * @param {String} page, the route name that is been registered in the map
     * @public
     */
    generate(page: string) {
        console.log(`start generate ${page}`);
        // first initialize objects
        this.init();

        // iterate over all the pages that are registered
        // views directory with the templates
        var views = this._get('views');
        if (!views) views = __dirname + "/views";
        // output directory
        var output = this._get('output');
        if (!output) output = __dirname + "/out";

        let pathLayer = this.matchOnPage(page);
        // do something with obj
        if (pathLayer != null) {
            var response = new Response(this.engine, `${output.toString()}${page}`);
            var request = new Request(page, pathLayer.params, pathLayer, this);
            pathLayer.handle.call(this, request, response);
            console.log(`generate files ${page}`);
        }
        this.emit('end');
    }

    /**
     * Adding a shortcut to the generate function, it generates a specific page.
     *
     * @param {String} page, the route name that is been registered in the map
     * @public
     */
    gen = (page: string) => this.generate(page);

    matchOnPage(page: string) {
        for (let layer: PathLayer of this.pages) {
            if (layer.match(page)) {
                return layer;
            }
        }
        return null;
    }
}

module.exports = function(express: any) {
    if ((process.argv[2] === '--dynamic' || process.argv[2] === '-d') && express !== undefined) {
        return express();
    } else {
        return new Application();
    }
};<|endoftext|>


<commit_before>var pageIndex = 0;

$( document ).ready(function() {
  console.log("ready");
  loadPageIntoElement("Copenhagen", addPage());
  loadPageIntoElement("Amadeus", addPage());
});

function addPage() {
	var pageId = "page" + pageIndex++;
	console.log("Creating element " + pageId);

	var tempContainer = document.createElement("div");
	tempContainer.innerHtml =
'
' +
'
'+
'
'+
'

'+
'
'+
'

'+
'
'+
'
';

	$(".wikibrowser-host").append(tempContainer.innerHtml);
	return pageId;
}

function loadPageIntoElement(page, element) {
	$.ajax({
	    url : "http://en.wikipedia.org/w/api.php?action=parse&format=json&callback=?&continue=&page=" + page,
	    data: {
	    	format: 'json'
	    },
	    dataType: 'jsonp',
	    success : function(result){
	        console.log("success");
	    }
	})
	.done(function(data) {
		console.log("injecting into " + element);
		console.log(data);
		$( "#" + element + " > .pre-content > h1" ).append( data.parse.displaytitle );
		$( "#" + element + " > .content" ).append( data.parse.text['*'] );
		$( "#" + element + " > .content a").each(fixHyperlink);
		$( "#" + element ).perfectScrollbar({
			wheelSpeed: 3
		});
	});
}

function fixHyperlink(index, element)
{
	var jElement = $(element);
	var address = jElement.attr('href');
	if (address.substring(0, 6) === '/wiki/')
	{
		jElement.attr('href', "http://en.wikipedia.org" + address);
		console.log("Fixed " + address);
		jElement.on('click', function() {
			console.log("Loading " + address.substring(6));
			loadPageIntoElement(address.substring(6), addPage());
			return false; // prevent going to href (wikipedia)
		})
	}
	else
	{
		jElement.attr('target', "_blank");
		console.log("Fixed external " + address);
	}
}<commit_msg>quick fix for anchors<commit_after>var pageIndex = 0;

$( document ).ready(function() {
  console.log("ready");
  loadPageIntoElement("Copenhagen", addPage());
  loadPageIntoElement("Amadeus", addPage());
});

function addPage() {
	var pageId = "page" + pageIndex++;
	console.log("Creating element " + pageId);

	var tempContainer = document.createElement("div");
	tempContainer.innerHtml =
'
' +
'
'+
'
'+
'

'+
'
'+
'

'+
'
'+
'
';

	$(".wikibrowser-host").append(tempContainer.innerHtml);
	return pageId;
}

function loadPageIntoElement(page, element) {
	$.ajax({
	    url : "http://en.wikipedia.org/w/api.php?action=parse&format=json&callback=?&continue=&page=" + page,
	    data: {
	    	format: 'json'
	    },
	    dataType: 'jsonp',
	    success : function(result){
	        console.log("success");
	    }
	})
	.done(function(data) {
		console.log("injecting into " + element);
		console.log(data);
		$( "#" + element + " > .pre-content > h1" ).append( data.parse.displaytitle );
		$( "#" + element + " > .content" ).append( data.parse.text['*'] );
		$( "#" + element + " > .content a").each(fixHyperlink);
		$( "#" + element ).perfectScrollbar({
			wheelSpeed: 3
		});
	});
}

function fixHyperlink(index, element)
{
	var jElement = $(element);
	var address = jElement.attr('href');
	if (address.substring(0, 6) === '/wiki/')
	{
		jElement.attr('href', "http://en.wikipedia.org" + address);
		console.log("Fixed " + address);
		jElement.on('click', function() {
			console.log("Loading " + address.substring(6));
			loadPageIntoElement(address.substring(6), addPage());
			return false; // prevent going to href (wikipedia)
		})
	}
	if (address.substring(0, 1) !== '#')
	{
		jElement.attr('target', "_blank");
		console.log("Fixed external " + address);
	}
}<|endoftext|>


<commit_before>var Session = require('../lib/session');
var SessionStore = require('../server/session_store');

function toAsync(transform) {
    return function(session, done) {
        done(null, transform(session));
    };
}

function savedTo(store, transform) {
    if (typeof store === 'string') store = new SessionStore(store);
    return function(session, done) {
        transform(session, function(err, session) {
            if (err) return done(err);
            store.save(session, done);
        });
    };
}

var async = require('async');
var path = require('path');
var config = require('../server/config');

var argv = require('minimist')(process.argv.slice(2), {
    alias: {
        i: 'input',
        o: 'output'
    },
    default: {
        input: path.join(config.var, 'sessions')
    }
});
var input = new SessionStore(argv.input);
var output = argv.output ? argv.output : input;
var transforms = argv._.map(function(transform) {
    return require(path.join(process.cwd(), transform));
});

var steps = transforms.map(function(trans) {
    var transform = trans;
    if (!trans.async) transform = toAsync(transform);
    return function(session, done) {
        transform(session, function(err, r) {
            if (r) session = r;
            done(err, session);
        });
    };
});

var transform = savedTo(output, function transform(session, done) {
    session = new Session(session.getData());
    async.series(steps.map(function(step) {
        return step.bind(this, session);
    }), done);
});

input.keys(function(err, keys) {
    if (err) return allDone(err);
    async.each(keys, function(key, keyDone) {
        input.load(key, function(err, session) {
            if (err) return keyDone(err);
            transform(session, keyDone);
        });
    }, allDone);
});

function allDone(err) {
    if (err) return console.error(err);
}
<commit_msg>scripts/transform: factor out maybeReturns<commit_after>var Session = require('../lib/session');
var SessionStore = require('../server/session_store');

function toAsync(transform) {
    return function(session, done) {
        done(null, transform(session));
    };
}

function maybeReturns(transform) {
    return function(session, done) {
        transform(session, function(err, r) {
            if (r) session = r;
            done(err, session);
        });
    };
}

function savedTo(store, transform) {
    if (typeof store === 'string') store = new SessionStore(store);
    return function(session, done) {
        transform(session, function(err, session) {
            if (err) return done(err);
            store.save(session, done);
        });
    };
}

var async = require('async');
var path = require('path');
var config = require('../server/config');

var argv = require('minimist')(process.argv.slice(2), {
    alias: {
        i: 'input',
        o: 'output'
    },
    default: {
        input: path.join(config.var, 'sessions')
    }
});
var input = new SessionStore(argv.input);
var output = argv.output ? argv.output : input;
var transforms = argv._.map(function(transform) {
    return require(path.join(process.cwd(), transform));
});

var steps = transforms.map(function(trans) {
    var transform = trans;
    if (!trans.async) transform = toAsync(transform);
    if (!trans.alwaysReturns) transform = maybeReturns(transform);
    return transform;
});

var transform = savedTo(output, function transform(session, done) {
    session = new Session(session.getData());
    async.series(steps.map(function(step) {
        return step.bind(this, session);
    }), done);
});

input.keys(function(err, keys) {
    if (err) return allDone(err);
    async.each(keys, function(key, keyDone) {
        input.load(key, function(err, session) {
            if (err) return keyDone(err);
            transform(session, keyDone);
        });
    }, allDone);
});

function allDone(err) {
    if (err) return console.error(err);
}
<|endoftext|>