<commit_before>function Robot(x, y, dir = 0)
{
	this.x = x;		//x coordinate
	this.y = y;		//y coordinate
	this.dir = dir;	//orientation in radians

	this.senseCircle = 10 + 5;
}

Robot.size = 10;
Robot.sensorRadius = 100;

let cos = Math.cos;
let sin = Math.sin;

Robot.prototype.draw = function(ctx)
{
	ctx.strokestyle = 'black';
	ctx.beginPath();

	//The robot's main circle
	ctx.arc(this.x, this.y, Robot.size, 0, Math.PI * 2, true);
	ctx.moveTo(this.x, this.y);

	//draw a line to show Robot's orientation
	ctx.moveTo(this.x, this.y);
	ctx.lineTo(this.x + cos(this.dir) * Robot.size, this.y + sin(this.dir) * Robot.size)
	ctx.moveTo(this.x, this.y);

	ctx.stroke();

	ctx.beginPath();
	//draw Robot's sensing circle
	ctx.arc(this.x, this.y, this.senseCircle, 0, Math.PI*2, false);
	ctx.stroke();

	ctx.beginPath();

	this.senseCircle = (this.senseCircle + 2) % Robot.sensorRadius;
}<commit_msg>add color to sensing circle<commit_after>function Robot(x, y, dir = 0)
{
	this.x = x;		//x coordinate
	this.y = y;		//y coordinate
	this.dir = dir;	//orientation in radians

	this.senseCircle = 10 + 5;
}

Robot.size = 10;
Robot.sensorRadius = 100;

let cos = Math.cos;
let sin = Math.sin;

Robot.prototype.draw = function(ctx)
{
	ctx.strokeStyle = 'black';
	ctx.beginPath();

	//The robot's main circle
	ctx.arc(this.x, this.y, Robot.size, 0, Math.PI * 2, true);
	ctx.moveTo(this.x, this.y);

	//draw a line to show Robot's orientation
	ctx.moveTo(this.x, this.y);
	ctx.lineTo(this.x + cos(this.dir) * Robot.size, this.y + sin(this.dir) * Robot.size)
	ctx.moveTo(this.x, this.y);

	ctx.stroke();

	ctx.strokeStyle = 'blue';
	ctx.beginPath();
	//draw Robot's sensing circle
	ctx.arc(this.x, this.y, this.senseCircle, 0, Math.PI*2, false);
	ctx.stroke();

	this.senseCircle = (this.senseCircle + 2) % Robot.sensorRadius;
}<|endoftext|>


<commit_before>/**
 * Upgrade Module to manage store upgrades
 */
'use strict';

define(['util/btc', 'bitcoinjs-lib'], function(BtcUtils, Bitcoin) {
// DarkWallet namespace for the local storage.
var DW_NS = 'dw:identity:';

function Upgrade4To5(store, identity, password) {
    if (identity.store.get('old-mpk')) {
        console.log("Double reseed?");
        return false;
    }
    // 1. adapt private keys
    var privData = identity.store.getPrivateData(password);
    var oldPrivKey = privData.privKey;
    var oldPrivKeys = privData.privKeys;
    var oldScanKeys = identity.store.get('scankeys');
    var oldIdKeys = identity.store.get('idkeys');
    var oldMpk = identity.store.get('mpk');

    identity.store.set('old-mpk', oldMpk);
    identity.store.set('old-idkeys', oldIdKeys);
    identity.store.set('old-scankeys', oldScanKeys);

    // generate completely overwrites the private data, calls store.save()
    identity.generate(privData.seed, password, identity.wallet.network);

    // get private data again to add the old key
    privData = identity.store.getPrivateData(password);
    privData.oldPrivKey = oldPrivKey;
    privData.privKeys = oldPrivKeys;

    // save the updated private data
    identity.store.setPrivateData(privData, password);

    // update identity
    identity.wallet.mpk = identity.store.get('mpk');
    identity.wallet.oldMpk = identity.store.get('old-mpk');
    identity.wallet.scanKeys = identity.store.get('scankeys');
    identity.wallet.idKeys = identity.store.get('idkeys');
    identity.wallet.oldScanKeys = identity.store.get('old-scankeys');

    // 2.b Add mpk to previous pockets
    var mpks = identity.store.get('mpks');
    var rootKey = Bitcoin.HDNode.fromBase58(privData.privKey);
    identity.wallet.pockets.hdPockets.forEach(function(pocketStore, i) {
        if (pocketStore) {
            if (!mpks[i]) {
                mpks[i] = rootKey.deriveHardened(i).toBase58(false);
            }
            pocketStore.mpk = mpks[i];
        }
    });

    // set version so we can start creating new addresses
    identity.reseed = false;
    identity.store.set('reseed', false);
    identity.store.set('version', 5);

    // Safety cleanup of malformed
    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        // Cleanup if malformed
        if (!walletAddress || !walletAddress.index){
            console.log("delete bad address", index);
            delete identity.wallet.pubKeys[index];
        }
    });

    // 3. upgrade the pocket addresses (index with length 1)
    // ... user should not have funds in any pocket address since they will be deleted
    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        index = walletAddress.index;
        if (index.length === 1 && walletAddress.type === undefined) {
            var pocket = identity.wallet.pockets.getAddressPocket(walletAddress);
            if (pocket && pocket.store.mpk) {
                // first remove the old address
                pocket.removeAddress(walletAddress);
                // and now create a new one
                // only for main branch and if the pocket exists
                if (index[0]%2 === 0) {
                    pocket.createAddress([index[0]/2]);
                }
            }
            else {
                if (pocket && !pocket.store.mpk) {
                    // autocreated pocket for not deleted addresses
                    // we dont call pocket.destroy because we dont want
                    // to trigger pocket cleanup.
                    delete identity.wallet.pockets.pockets.hd[pocket.getPocketId()];
                }
                // if the pocket doesn't exist just delete the address
                identity.wallet.deleteAddress(index);
            }
        }
        // also set all stealth as oldstealth
        if (walletAddress.type === 'stealth') {
            walletAddress.type = 'oldstealth';
        }
    });

    // 4. clean up old unused addresses
    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        index = walletAddress.index;
        if (index.length > 1 && walletAddress.type === undefined) {
            if (walletAddress.nOutputs === 0 && ['unused', 'pocket', 'change'].indexOf(walletAddress.label) > -1) {
                var pocket = identity.wallet.pockets.getAddressPocket(walletAddress);
                // remove it
                try {
                    pocket.removeAddress(walletAddress);
                } catch (e) {
                    console.log("error removing address", walletAddress);
                }
            }
        }
    });

    // 5. should create some new addresses?

    // 6. perform other long running cleanings

    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        // Reindex // delete badly indexed
        if (walletAddress.type === 'readonly' && walletAddress.index[0] === index) {
            delete identity.wallet.pubKeys[index];
            if (!identity.wallet.pubKeys[walletAddress.index]) {
                // if it doesnt exist, relink it
                identity.wallet.pubKeys[walletAddress.index.slice(0)] = walletAddress;
            }
        }
    });

    return true;
}

/**
 * Upgrade version 3 to version 4
 */

function Upgrade3To4(store) {
    // We change txdb to contain an array so we can store several fields.
    if (store.transactions && Object.keys(store.transactions).length && !Array.isArray(store.transactions[Object.keys(store.transactions)[0]])) {
        Object.keys(store.transactions).forEach(function(txHash) {
            if (!Array.isArray(store.transactions[txHash])) {
                store.transactions[txHash] = [store.transactions[txHash]];
            }
        });
    }
    return true;
}

/**
 * Upgrade version 2 to version 3
 */

function Upgrade2To3(store) {
    // Reset the stealth counter so stealth will be downloaded from the start
    store.lastStealth = 0;
    return true;
}

/**
 * Upgrade version 1 to version 2
 */

function Upgrade1To2(store) {
    if (!store.mpk) {
        console.log("Wallet without mpk!", store.mpk);
    }

    // Upgrade Public Keys
    var pubKeys = store.pubkeys;

    var toRemove = [];
    Object.keys(pubKeys).forEach(function(index) {
        var walletAddress = pubKeys[index];
        // Check for malformed address
        if (walletAddress == null || walletAddress.index == null) {
            toRemove.push(index)
            return;
        }
        // Start mpk for pocket addresses
        if (walletAddress.index.length == 1) {
            walletAddress.mpk = BtcUtils.deriveMpk(store.mpk, walletAddress.index[0]);
        }
    });
    // Cleanup malformed addresses
    toRemove.forEach(function(index) {
        console.log("[model] Deleting", pubKeys[index]);
        delete pubKeys[index];
    });

    // Upgrade Public Keys
    var contacts = store.contacts;

    if (!Array.isArray(contacts)) {
        store.contacts = [];
        contacts = store.contacts;
    }
    // Cleanup empty keys
    contacts.forEach(function(contact) {
        if (!contact) {
            console.log("[upgrade] Delete contact", contact);
            contacts.splice(contacts.indexOf(contact), 1);
            return;
        }
    });
    // Upgrade pocket store to new format
    if (typeof store.pockets[0] == 'string') {
        for(var i=0; i< store.pockets.length; i++) {
            store.pockets[i] = {'name': store.pockets[i]};
        };
    }
    // If no scankeys need to regenerate
    if (!store.scankeys || (store.scankeys.length == 0)) {
        // Can't finish the upgrade, need user to regenerate keys
        console.log('[upgrade] You need to reseed the wallet to generate stealth scanning keys!');
        store.reseed = true;
        return false;
    }
    return true;
}

/**
 * Upgrade a given store
 * @return true of false if the store was changed and should be saved
 */
function Upgrade(store, identity, password) {
    if (store.version == 5) {
        return false;
    }

    console.log("[upgrade] Upgrading to version 5")

    // 0 to 1
    if (!store.version) {
        store.version = 1;
    }
    // 1 to 2
    if ((store.version == 1) && Upgrade1To2(store)) {
        store.version = 2;
        console.log("[upgrade] Upgraded to version 2")
    }
    // 2 to 3
    if ((store.version == 2) && Upgrade2To3(store)) {
        store.version = 3;
        console.log("[upgrade] Upgraded to version 3")
    }
    // 3 to 4
    if ((store.version == 3) && Upgrade3To4(store)) {
        store.version = 4;
        console.log("[upgrade] Upgraded to version 4")
    }
    if (store.version == 4) {
        if (identity) {
            // Upgrade of 4 to 5 needs reseeding with live identity and password
            if (Upgrade4To5(store, identity, password)) {
                store.version = 5
                console.log("[upgrade] Upgraded to version 5")
            }
        } else {
            store.reseed = true;
        }
    }
    return true;
}

return Upgrade;
});
<commit_msg>Safer way to get pocketId.<commit_after>/**
 * Upgrade Module to manage store upgrades
 */
'use strict';

define(['util/btc', 'bitcoinjs-lib'], function(BtcUtils, Bitcoin) {
// DarkWallet namespace for the local storage.
var DW_NS = 'dw:identity:';

function Upgrade4To5(store, identity, password) {
    if (identity.store.get('old-mpk')) {
        console.log("Double reseed?");
        return false;
    }
    // 1. adapt private keys
    var privData = identity.store.getPrivateData(password);
    var oldPrivKey = privData.privKey;
    var oldPrivKeys = privData.privKeys;
    var oldScanKeys = identity.store.get('scankeys');
    var oldIdKeys = identity.store.get('idkeys');
    var oldMpk = identity.store.get('mpk');

    identity.store.set('old-mpk', oldMpk);
    identity.store.set('old-idkeys', oldIdKeys);
    identity.store.set('old-scankeys', oldScanKeys);

    // generate completely overwrites the private data, calls store.save()
    identity.generate(privData.seed, password, identity.wallet.network);

    // get private data again to add the old key
    privData = identity.store.getPrivateData(password);
    privData.oldPrivKey = oldPrivKey;
    privData.privKeys = oldPrivKeys;

    // save the updated private data
    identity.store.setPrivateData(privData, password);

    // update identity
    identity.wallet.mpk = identity.store.get('mpk');
    identity.wallet.oldMpk = identity.store.get('old-mpk');
    identity.wallet.scanKeys = identity.store.get('scankeys');
    identity.wallet.idKeys = identity.store.get('idkeys');
    identity.wallet.oldScanKeys = identity.store.get('old-scankeys');

    // 2.b Add mpk to previous pockets
    var mpks = identity.store.get('mpks');
    var rootKey = Bitcoin.HDNode.fromBase58(privData.privKey);
    identity.wallet.pockets.hdPockets.forEach(function(pocketStore, i) {
        if (pocketStore) {
            if (!mpks[i]) {
                mpks[i] = rootKey.deriveHardened(i).toBase58(false);
            }
            pocketStore.mpk = mpks[i];
        }
    });

    // set version so we can start creating new addresses
    identity.reseed = false;
    identity.store.set('reseed', false);
    identity.store.set('version', 5);

    // Safety cleanup of malformed
    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        // Cleanup if malformed
        if (!walletAddress || !walletAddress.index){
            console.log("delete bad address", index);
            delete identity.wallet.pubKeys[index];
        }
    });

    // 3. upgrade the pocket addresses (index with length 1)
    // ... user should not have funds in any pocket address since they will be deleted
    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        index = walletAddress.index;
        if (index.length === 1 && walletAddress.type === undefined) {
            var pocket = identity.wallet.pockets.getAddressPocket(walletAddress);
            if (pocket && pocket.store.mpk) {
                // first remove the old address
                pocket.removeAddress(walletAddress);
                // and now create a new one
                // only for main branch and if the pocket exists
                if (index[0]%2 === 0) {
                    pocket.createAddress([index[0]/2]);
                }
            }
            else {
                if (pocket && !pocket.store.mpk) {
                    // autocreated pocket for not deleted addresses
                    // dont use pocket.getPocketId because it depends on pocket.store
                    var pocketId = identity.wallet.pockets.getAddressPocketId(walletAddress);
                    // we dont call pocket.destroy because we dont want
                    // to trigger pocket cleanup.
                    delete identity.wallet.pockets.pockets.hd[pocketId];
                }
                // if the pocket doesn't exist just delete the address
                identity.wallet.deleteAddress(index);
            }
        }
        // also set all stealth as oldstealth
        if (walletAddress.type === 'stealth') {
            walletAddress.type = 'oldstealth';
        }
    });

    // 4. clean up old unused addresses
    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        index = walletAddress.index;
        if (index.length > 1 && walletAddress.type === undefined) {
            if (walletAddress.nOutputs === 0 && ['unused', 'pocket', 'change'].indexOf(walletAddress.label) > -1) {
                var pocket = identity.wallet.pockets.getAddressPocket(walletAddress);
                // remove it
                try {
                    pocket.removeAddress(walletAddress);
                } catch (e) {
                    console.log("error removing address", walletAddress);
                }
            }
        }
    });

    // 5. should create some new addresses?

    // 6. perform other long running cleanings

    Object.keys(identity.wallet.pubKeys).forEach(function(index) {
        var walletAddress = identity.wallet.pubKeys[index];
        // Reindex // delete badly indexed
        if (walletAddress.type === 'readonly' && walletAddress.index[0] === index) {
            delete identity.wallet.pubKeys[index];
            if (!identity.wallet.pubKeys[walletAddress.index]) {
                // if it doesnt exist, relink it
                identity.wallet.pubKeys[walletAddress.index.slice(0)] = walletAddress;
            }
        }
    });

    return true;
}

/**
 * Upgrade version 3 to version 4
 */

function Upgrade3To4(store) {
    // We change txdb to contain an array so we can store several fields.
    if (store.transactions && Object.keys(store.transactions).length && !Array.isArray(store.transactions[Object.keys(store.transactions)[0]])) {
        Object.keys(store.transactions).forEach(function(txHash) {
            if (!Array.isArray(store.transactions[txHash])) {
                store.transactions[txHash] = [store.transactions[txHash]];
            }
        });
    }
    return true;
}

/**
 * Upgrade version 2 to version 3
 */

function Upgrade2To3(store) {
    // Reset the stealth counter so stealth will be downloaded from the start
    store.lastStealth = 0;
    return true;
}

/**
 * Upgrade version 1 to version 2
 */

function Upgrade1To2(store) {
    if (!store.mpk) {
        console.log("Wallet without mpk!", store.mpk);
    }

    // Upgrade Public Keys
    var pubKeys = store.pubkeys;

    var toRemove = [];
    Object.keys(pubKeys).forEach(function(index) {
        var walletAddress = pubKeys[index];
        // Check for malformed address
        if (walletAddress == null || walletAddress.index == null) {
            toRemove.push(index)
            return;
        }
        // Start mpk for pocket addresses
        if (walletAddress.index.length == 1) {
            walletAddress.mpk = BtcUtils.deriveMpk(store.mpk, walletAddress.index[0]);
        }
    });
    // Cleanup malformed addresses
    toRemove.forEach(function(index) {
        console.log("[model] Deleting", pubKeys[index]);
        delete pubKeys[index];
    });

    // Upgrade Public Keys
    var contacts = store.contacts;

    if (!Array.isArray(contacts)) {
        store.contacts = [];
        contacts = store.contacts;
    }
    // Cleanup empty keys
    contacts.forEach(function(contact) {
        if (!contact) {
            console.log("[upgrade] Delete contact", contact);
            contacts.splice(contacts.indexOf(contact), 1);
            return;
        }
    });
    // Upgrade pocket store to new format
    if (typeof store.pockets[0] == 'string') {
        for(var i=0; i< store.pockets.length; i++) {
            store.pockets[i] = {'name': store.pockets[i]};
        };
    }
    // If no scankeys need to regenerate
    if (!store.scankeys || (store.scankeys.length == 0)) {
        // Can't finish the upgrade, need user to regenerate keys
        console.log('[upgrade] You need to reseed the wallet to generate stealth scanning keys!');
        store.reseed = true;
        return false;
    }
    return true;
}

/**
 * Upgrade a given store
 * @return true of false if the store was changed and should be saved
 */
function Upgrade(store, identity, password) {
    if (store.version == 5) {
        return false;
    }

    console.log("[upgrade] Upgrading to version 5")

    // 0 to 1
    if (!store.version) {
        store.version = 1;
    }
    // 1 to 2
    if ((store.version == 1) && Upgrade1To2(store)) {
        store.version = 2;
        console.log("[upgrade] Upgraded to version 2")
    }
    // 2 to 3
    if ((store.version == 2) && Upgrade2To3(store)) {
        store.version = 3;
        console.log("[upgrade] Upgraded to version 3")
    }
    // 3 to 4
    if ((store.version == 3) && Upgrade3To4(store)) {
        store.version = 4;
        console.log("[upgrade] Upgraded to version 4")
    }
    if (store.version == 4) {
        if (identity) {
            // Upgrade of 4 to 5 needs reseeding with live identity and password
            if (Upgrade4To5(store, identity, password)) {
                store.version = 5
                console.log("[upgrade] Upgraded to version 5")
            }
        } else {
            store.reseed = true;
        }
    }
    return true;
}

return Upgrade;
});
<|endoftext|>


<commit_before>//Origin https://gist.github.com/leecrossley/4078996
var shake = (function () {
    var shake = {},
    watchId = null,
    options = { frequency: 300 },
        previousAcceleration = { x: null, y: null, z: null },
        shakeCallBack = null;

    // Start watching the accelerometer for a shake gesture
    shake.startWatch = function (onShake) {
        alert('method called');
        if (onShake) {
            alert('shaking!');
            shakeCallBack = onShake;
        }
        watchId = navigator.accelerometer.watchAcceleration(getAccelerationSnapshot, handleError, options);
    };

    // Stop watching the accelerometer for a shake gesture
    shake.stopWatch = function () {
        if (watchId !== null) {
            navigator.accelerometer.clearWatch(watchId);
            watchId = null;
        }
    };

    // Gets the current acceleration snapshot from the last accelerometer watch
    function getAccelerationSnapshot() {
        navigator.accelerometer.getCurrentAcceleration(assessCurrentAcceleration, handleError);
    }

    // Assess the current acceleration parameters to determine a shake
    function assessCurrentAcceleration(acceleration) {
        var accelerationChange = {};
        if (previousAcceleration.x !== null) {
            accelerationChange.x = Math.abs(previousAcceleration.x, acceleration.x);
            accelerationChange.y = Math.abs(previousAcceleration.y, acceleration.y);
            accelerationChange.z = Math.abs(previousAcceleration.z, acceleration.z);
        }
        if (accelerationChange.x + accelerationChange.y + accelerationChange.z > 30) {
            // Shake detected
            if (typeof (shakeCallBack) === "function") {
                shakeCallBack();
            }
            shake.stopWatch();
            setTimeout(shake.startWatch, 1000, shakeCallBack);
            previousAcceleration = {
                x: null,
                y: null,
                z: null
            };
        } else {
            previousAcceleration = {
                x: acceleration.x,
                y: acceleration.y,
                z: acceleration.z
            };
        }
    }

    // Handle errors here
    function handleError() {
    }

    return shake;
})();
<commit_msg>Update shake.js<commit_after>//Origin https://gist.github.com/leecrossley/4078996
var shake = (function () {
    var shake = {},
    watchId = null,
    options = { frequency: 300 },
        previousAcceleration = { x: null, y: null, z: null },
        shakeCallBack = null;

    // Start watching the accelerometer for a shake gesture
    shake.startWatch = function (onShake) {
        alert('method called');
        if (onShake) {
            alert('shaking!');
            shakeCallBack = onShake;
        }
        watchId = navigator.accelerometer.watchAcceleration(getAccelerationSnapshot, handleError, options);
    };

    // Stop watching the accelerometer for a shake gesture
    shake.stopWatch = function () {
        if (watchId !== null) {
            navigator.accelerometer.clearWatch(watchId);
            watchId = null;
        }
    };

    // Gets the current acceleration snapshot from the last accelerometer watch
    function getAccelerationSnapshot() {
        navigator.accelerometer.getCurrentAcceleration(assessCurrentAcceleration, handleError);
    }

    // Assess the current acceleration parameters to determine a shake
    function assessCurrentAcceleration(acceleration) {
        var accelerationChange = {};
        if (previousAcceleration.x !== null) {
            accelerationChange.x = Math.abs(previousAcceleration.x, acceleration.x);
            accelerationChange.y = Math.abs(previousAcceleration.y, acceleration.y);
            accelerationChange.z = Math.abs(previousAcceleration.z, acceleration.z);
        }
        if (accelerationChange.x + accelerationChange.y + accelerationChange.z > 30) {
            // Shake detected
            if (typeof (shakeCallBack) === "function") {
                shakeCallBack();
            }
            //shake.stopWatch();
            setTimeout(shake.startWatch, 1000, shakeCallBack);
            previousAcceleration = {
                x: null,
                y: null,
                z: null
            };
        } else {
            previousAcceleration = {
                x: acceleration.x,
                y: acceleration.y,
                z: acceleration.z
            };
        }
    }

    // Handle errors here
    function handleError() {
    }

    return shake;
})();
<|endoftext|>


<commit_before>import React from 'react';
import lbry from '../lbry.js';
import lighthouse from '../lighthouse.js';
import {Link, ToolTipLink, DownloadLink, WatchLink} from '../component/link.js';
import {Thumbnail, CreditAmount, TruncatedText} from '../component/common.js';

var fetchResultsStyle = {
    color: '#888',
    textAlign: 'center',
    fontSize: '1.2em'
  };

var SearchActive = React.createClass({
  render: function() {
    return (

        <BusyMessage message="Looking up the Dewey Decimals" />

    );
  }
});

var searchNoResultsStyle = {
  textAlign: 'center'
}, searchNoResultsMessageStyle = {
  fontStyle: 'italic',
  marginRight: '5px'
};

var SearchNoResults = React.createClass({
  render: function() {
    return (

        No one has checked anything in for {this.props.query} yet.
        <Link label="Be the first" href="?publish" />

    );
  }
});

var SearchResults = React.createClass({
  render: function() {
    var rows = [];
    this.props.results.forEach(function(result) {
      console.log(result);
      var mediaType = lbry.getMediaType(result.value.content_type);
      rows.push(
        <SearchResultRow key={result.name} name={result.name} title={result.value.title} imgUrl={result.value.thumbnail}
                         description={result.value.description} nsfw={result.value.nsfw} mediaType={mediaType} />
      );
    });
    return (

{rows}

    );
  }
});

var
  searchRowStyle = {
    height: (24 * 7) + 'px',
    overflowY: 'hidden'
  },
  searchRowCompactStyle = {
    height: '180px',
  },
  searchRowImgStyle = {
    maxWidth: '100%',
    maxHeight: (24 * 7) + 'px',
    display: 'block',
    marginLeft: 'auto',
    marginRight: 'auto'
  },
  searchRowTitleStyle = {
    fontWeight: 'bold'
  },
  searchRowTitleCompactStyle = {
    fontSize: '1.25em',
    lineHeight: '1.15',
  },
  searchRowCostStyle = {
    float: 'right',
  },
  searchRowDescriptionStyle = {
    color : '#444',
    marginTop: '12px',
    fontSize: '0.9em'
  };

var SearchResultRow = React.createClass({
  getInitialState: function() {
    return {
      downloading: false,
      isHovered: false,
      cost: null,
      costIncludesData: null,
    }
  },
  handleMouseOver: function() {
    this.setState({
      isHovered: true,
    });
  },
  handleMouseOut: function() {
    this.setState({
      isHovered: false,
    });
  },
  componentWillMount: function() {
    if ('cost' in this.props) {
      this.setState({
        cost: this.props.cost,
        costIncludesData: this.props.costIncludesData,
      });
    } else {
      lbry.getCostInfoForName(this.props.name, ({cost, includesData}) => {
        this.setState({
          cost: cost,
          costIncludesData: includesData,
        });
      });
    }
  },
  render: function() {
    var obscureNsfw = !lbry.getClientSetting('showNsfw') && this.props.nsfw;
    if (!this.props.compact) {
      var style = searchRowStyle;
      var titleStyle = searchRowTitleStyle;
    } else {
      var style = Object.assign({}, searchRowStyle, searchRowCompactStyle);
      var titleStyle = Object.assign({}, searchRowTitleStyle, searchRowTitleCompactStyle);
    }

    return (

            <Thumbnail src={this.props.imgUrl} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} />

            {this.state.cost !== null
              ?
                  <CreditAmount amount={this.state.cost} isEstimate={!this.state.costIncludesData}/>

              : null}

lbry://{this.props.name}

                <TruncatedText lines={3}>
                  {this.props.title}
                </TruncatedText>

              {this.props.mediaType == 'video' ? <WatchLink streamName={this.props.name} button="primary" /> : null}
              <DownloadLink streamName={this.props.name} button="text" />

              <TruncatedText lines={3}>
                {this.props.description}
              </TruncatedText>

        {
          !obscureNsfw || !this.state.isHovered ? null :

                This content is Not Safe For Work.
                To view adult content, please change your <Link href="?settings" label="Settings" />.

        }

    );
  }
});

var featuredContentItemContainerStyle = {
  position: 'relative',
};

var FeaturedContentItem = React.createClass({
  resolveSearch: false,

  propTypes: {
    name: React.PropTypes.string,
  },

  getInitialState: function() {
    return {
      metadata: null,
      title: null,
      cost: null,
      overlayShowing: false,
    };
  },

  componentWillUnmount: function() {
    this.resolveSearch = false;
  },

  componentDidMount: function() {
    this._isMounted = true;

    lbry.resolveName(this.props.name, (metadata) => {
      if (!this._isMounted) {
        return;
      }

      this.setState({
        metadata: metadata,
        title: metadata && metadata.title ? metadata.title : ('lbry://' + this.props.name),
      });
    });
  },

  render: function() {
    if (this.state.metadata === null) {
      // Still waiting for metadata, skip render
      return null;
    }

    return (

      <SearchResultRow name={this.props.name} title={this.state.title} imgUrl={this.state.metadata.thumbnail}
                 description={this.state.metadata.description} mediaType={lbry.getMediaType(this.state.metadata.content_type)}
                 nsfw={this.state.metadata.nsfw} compact />

);
  }
});

var featuredContentLegendStyle = {
  fontSize: '12px',
  color: '#aaa',
  verticalAlign: '15%',
};

var FeaturedContent = React.createClass({
  render: function() {
    return (

Featured Content

          <FeaturedContentItem name="bellflower" />
          <FeaturedContentItem name="itsadisaster" />
          <FeaturedContentItem name="dopeman" />
          <FeaturedContentItem name="smlawncare" />
          <FeaturedContentItem name="cinemasix" />

Community Content <ToolTipLink style={featuredContentLegendStyle} label="What's this?"
            tooltip='Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!' />

          <FeaturedContentItem name="one" />
          <FeaturedContentItem name="two" />
          <FeaturedContentItem name="three" />
          <FeaturedContentItem name="four" />
          <FeaturedContentItem name="five" />

    );
  }
});

var DiscoverPage = React.createClass({
  userTypingTimer: null,

  componentDidUpdate: function() {
    if (this.props.query != this.state.query)
    {
      this.handleSearchChanged();
    }
  },

  handleSearchChanged: function() {
    this.setState({
      searching: true,
      query: this.props.query,
    });

    lighthouse.search(this.props.query, this.searchCallback);
  },

  componentDidMount: function() {
    document.title = "Discover";
    if (this.props.query) {
      // Rendering with a query already typed
      this.handleSearchChanged();
    }
  },

  getInitialState: function() {
    return {
      results: [],
      query: this.props.query,
      searching: this.props.query && this.props.query.length > 0
    };
  },

  searchCallback: function(results) {
    if (this.state.searching) //could have canceled while results were pending, in which case nothing to do
    {
      this.setState({
        results: results,
        searching: false //multiple searches can be out, we're only done if we receive one we actually care about
      });
    }
  },

  render: function() {
    return (

        { this.state.searching ? <SearchActive /> : null }
        { !this.state.searching && this.props.query && this.state.results.length ? <SearchResults results={this.state.results} /> : null }
        { !this.state.searching && this.props.query && !this.state.results.length ? <SearchNoResults query={this.props.query} /> : null }
        { !this.props.query && !this.state.searching ? <FeaturedContent /> : null }

    );
  }
});

export default DiscoverPage;
<commit_msg>Add import for BusyMessage to discover.js<commit_after>import React from 'react';
import lbry from '../lbry.js';
import lighthouse from '../lighthouse.js';
import {Link, ToolTipLink, DownloadLink, WatchLink} from '../component/link.js';
import {Thumbnail, CreditAmount, TruncatedText, BusyMessage} from '../component/common.js';

var fetchResultsStyle = {
    color: '#888',
    textAlign: 'center',
    fontSize: '1.2em'
  };

var SearchActive = React.createClass({
  render: function() {
    return (

        <BusyMessage message="Looking up the Dewey Decimals" />

    );
  }
});

var searchNoResultsStyle = {
  textAlign: 'center'
}, searchNoResultsMessageStyle = {
  fontStyle: 'italic',
  marginRight: '5px'
};

var SearchNoResults = React.createClass({
  render: function() {
    return (

        No one has checked anything in for {this.props.query} yet.
        <Link label="Be the first" href="?publish" />

    );
  }
});

var SearchResults = React.createClass({
  render: function() {
    var rows = [];
    this.props.results.forEach(function(result) {
      console.log(result);
      var mediaType = lbry.getMediaType(result.value.content_type);
      rows.push(
        <SearchResultRow key={result.name} name={result.name} title={result.value.title} imgUrl={result.value.thumbnail}
                         description={result.value.description} nsfw={result.value.nsfw} mediaType={mediaType} />
      );
    });
    return (

{rows}

    );
  }
});

var
  searchRowStyle = {
    height: (24 * 7) + 'px',
    overflowY: 'hidden'
  },
  searchRowCompactStyle = {
    height: '180px',
  },
  searchRowImgStyle = {
    maxWidth: '100%',
    maxHeight: (24 * 7) + 'px',
    display: 'block',
    marginLeft: 'auto',
    marginRight: 'auto'
  },
  searchRowTitleStyle = {
    fontWeight: 'bold'
  },
  searchRowTitleCompactStyle = {
    fontSize: '1.25em',
    lineHeight: '1.15',
  },
  searchRowCostStyle = {
    float: 'right',
  },
  searchRowDescriptionStyle = {
    color : '#444',
    marginTop: '12px',
    fontSize: '0.9em'
  };

var SearchResultRow = React.createClass({
  getInitialState: function() {
    return {
      downloading: false,
      isHovered: false,
      cost: null,
      costIncludesData: null,
    }
  },
  handleMouseOver: function() {
    this.setState({
      isHovered: true,
    });
  },
  handleMouseOut: function() {
    this.setState({
      isHovered: false,
    });
  },
  componentWillMount: function() {
    if ('cost' in this.props) {
      this.setState({
        cost: this.props.cost,
        costIncludesData: this.props.costIncludesData,
      });
    } else {
      lbry.getCostInfoForName(this.props.name, ({cost, includesData}) => {
        this.setState({
          cost: cost,
          costIncludesData: includesData,
        });
      });
    }
  },
  render: function() {
    var obscureNsfw = !lbry.getClientSetting('showNsfw') && this.props.nsfw;
    if (!this.props.compact) {
      var style = searchRowStyle;
      var titleStyle = searchRowTitleStyle;
    } else {
      var style = Object.assign({}, searchRowStyle, searchRowCompactStyle);
      var titleStyle = Object.assign({}, searchRowTitleStyle, searchRowTitleCompactStyle);
    }

    return (

            <Thumbnail src={this.props.imgUrl} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} />

            {this.state.cost !== null
              ?
                  <CreditAmount amount={this.state.cost} isEstimate={!this.state.costIncludesData}/>

              : null}

lbry://{this.props.name}

                <TruncatedText lines={3}>
                  {this.props.title}
                </TruncatedText>

              {this.props.mediaType == 'video' ? <WatchLink streamName={this.props.name} button="primary" /> : null}
              <DownloadLink streamName={this.props.name} button="text" />

              <TruncatedText lines={3}>
                {this.props.description}
              </TruncatedText>

        {
          !obscureNsfw || !this.state.isHovered ? null :

                This content is Not Safe For Work.
                To view adult content, please change your <Link href="?settings" label="Settings" />.

        }

    );
  }
});

var featuredContentItemContainerStyle = {
  position: 'relative',
};

var FeaturedContentItem = React.createClass({
  resolveSearch: false,

  propTypes: {
    name: React.PropTypes.string,
  },

  getInitialState: function() {
    return {
      metadata: null,
      title: null,
      cost: null,
      overlayShowing: false,
    };
  },

  componentWillUnmount: function() {
    this.resolveSearch = false;
  },

  componentDidMount: function() {
    this._isMounted = true;

    lbry.resolveName(this.props.name, (metadata) => {
      if (!this._isMounted) {
        return;
      }

      this.setState({
        metadata: metadata,
        title: metadata && metadata.title ? metadata.title : ('lbry://' + this.props.name),
      });
    });
  },

  render: function() {
    if (this.state.metadata === null) {
      // Still waiting for metadata, skip render
      return null;
    }

    return (

      <SearchResultRow name={this.props.name} title={this.state.title} imgUrl={this.state.metadata.thumbnail}
                 description={this.state.metadata.description} mediaType={lbry.getMediaType(this.state.metadata.content_type)}
                 nsfw={this.state.metadata.nsfw} compact />

);
  }
});

var featuredContentLegendStyle = {
  fontSize: '12px',
  color: '#aaa',
  verticalAlign: '15%',
};

var FeaturedContent = React.createClass({
  render: function() {
    return (

Featured Content

          <FeaturedContentItem name="bellflower" />
          <FeaturedContentItem name="itsadisaster" />
          <FeaturedContentItem name="dopeman" />
          <FeaturedContentItem name="smlawncare" />
          <FeaturedContentItem name="cinemasix" />

Community Content <ToolTipLink style={featuredContentLegendStyle} label="What's this?"
            tooltip='Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!' />

          <FeaturedContentItem name="one" />
          <FeaturedContentItem name="two" />
          <FeaturedContentItem name="three" />
          <FeaturedContentItem name="four" />
          <FeaturedContentItem name="five" />

    );
  }
});

var DiscoverPage = React.createClass({
  userTypingTimer: null,

  componentDidUpdate: function() {
    if (this.props.query != this.state.query)
    {
      this.handleSearchChanged();
    }
  },

  handleSearchChanged: function() {
    this.setState({
      searching: true,
      query: this.props.query,
    });

    lighthouse.search(this.props.query, this.searchCallback);
  },

  componentDidMount: function() {
    document.title = "Discover";
    if (this.props.query) {
      // Rendering with a query already typed
      this.handleSearchChanged();
    }
  },

  getInitialState: function() {
    return {
      results: [],
      query: this.props.query,
      searching: this.props.query && this.props.query.length > 0
    };
  },

  searchCallback: function(results) {
    if (this.state.searching) //could have canceled while results were pending, in which case nothing to do
    {
      this.setState({
        results: results,
        searching: false //multiple searches can be out, we're only done if we receive one we actually care about
      });
    }
  },

  render: function() {
    return (

        { this.state.searching ? <SearchActive /> : null }
        { !this.state.searching && this.props.query && this.state.results.length ? <SearchResults results={this.state.results} /> : null }
        { !this.state.searching && this.props.query && !this.state.results.length ? <SearchNoResults query={this.props.query} /> : null }
        { !this.props.query && !this.state.searching ? <FeaturedContent /> : null }

    );
  }
});

export default DiscoverPage;
<|endoftext|>


<commit_before>var WINDOW_WIDTH = windowWidth();
var WINDOW_HEIGHT = windowHeight();

var Y_AXIS = new THREE.Vector3(0, 1, 0);

var views = [
  {
    left: 0.5,
    bottom: 0,
    width: 0.5,
    height: 1.0,
    position: new THREE.Vector3(3, 10, -1),
    target: function() {
      return this.position.clone().setY(0);
    }
  },
  {
    left: 0,
    bottom: 0,
    width: 0.5,
    height: 1.0,
    position: new THREE.Vector3(10, 5, -10),
    target: function() {
      return scene.position.clone().setY(scene.position.y - 2);
    }
  },
];

var scene = new THREE.Scene();
views.forEach(function(view) {
  var width = WINDOW_WIDTH * view.width;
  var height = WINDOW_HEIGHT * view.height;
  var camera = new THREE.OrthographicCamera(-width/2, width/2, height/2, -height/2, 0, 1000);
  camera.zoom = 50;
  camera.position.set(view.position.x, view.position.y, view.position.z);

  view.camera = camera;
});

var light = new THREE.PointLight(0xffffff, 0.5, 1000);
light.position.set(100, 500, -100);
scene.add(light);

var light2 = new THREE.PointLight(0xffffff, 0.5, 1000);
light2.position.set(-100, 500, 100);
scene.add(light2);

var axisHelper = new THREE.AxisHelper(52);
axisHelper.position.z = 0.02;
scene.add(axisHelper);

var gridHelper = new THREE.GridHelper(20 * 3, 3);
scene.add(gridHelper);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
renderer.setClearColor(0xEEEEFF, 1);
document.getElementById("main-container").appendChild(renderer.domElement);

setup();

function render() {
  renderer.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);

  views.forEach(function(view) {
    var camera = view.camera;

    var width = Math.floor(WINDOW_WIDTH * view.width);
    var height = Math.floor(WINDOW_HEIGHT * view.height);

    var left = Math.floor(WINDOW_WIDTH  * view.left);
    var bottom = Math.floor(WINDOW_HEIGHT * view.bottom);

    renderer.setViewport(left, bottom, width, height);
    renderer.setScissor(left, bottom, width, height);
    renderer.enableScissorTest(true);

    camera.left = -width/2;
    camera.right = width/2;
    camera.top = height/2;
    camera.bottom = -height/2;
    camera.lookAt(view.target());

    camera.updateProjectionMatrix();

    renderer.render(scene, camera);
  });
}

function loop() {
  requestAnimationFrame(loop);
  render();
}
loop();

function windowWidth() {
  return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
}

function windowHeight() {
  return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
}

function onWindowResize(event) {
  var WINDOW_WIDTH = windowWidth();
  var WINDOW_WIDTH = windowHeight();
}
window.addEventListener('resize', onWindowResize, false);

function setup() {
  models.tiles().then(function(tiles) {
    var tilesParent = document.getElementById("tiles-container").getElementsByClassName("tiles")[0];
    tiles.forEach(function(tileData) {
      var tile = document.createElement('li');
      tile.dataset.name = tileData.name;
      tile.dataset.model = tileData.model;
      tile.addEventListener('click', function(evt) {
        var children = tilesParent.getElementsByClassName("selected");
        for (var i = 0; i < children.length; i++) {
          var child = children.item(i);
          child.classList.remove("selected");

        }

        tile.classList.add("selected");
        select(tile);
      });

      var thumb = document.createElement('img');
      thumb.src = tileData.image;

      tile.appendChild(thumb);
      tilesParent.appendChild(tile);
    }.bind(this));
  }.bind(this));
}

var selected = {};
function select(tileElement) {
  if (selected.object) {
    scene.remove(selected.object);
    selected = {};
  }

  return models.load(tileElement.dataset.model).then(function(object) {
    selected = {};
    selected.object = object;
    window.info = tileInfo(object.clone());

    setupDebugObjects(object, selected);

    setTimeout(function() {
      setupDebugPaths(object, selected, info);
    }, 100);

    scene.add(object);
  });
}

function setupDebugObjects(object, selected) {
    var verticesGeometry = new THREE.Geometry();
    var facesGeometry = new THREE.Geometry();
    traverseGeometries(object, function(o) {
      o.geometry.vertices.forEach(function(v) {
        verticesGeometry.vertices.push(v);
      });

      applicableFaces(o.geometry.faces).forEach(function(f) {
        facesGeometry.vertices.push(o.geometry.vertices[f.a].clone());
        var a = facesGeometry.vertices.length - 1;
        facesGeometry.vertices.push(o.geometry.vertices[f.b].clone());
        var b = facesGeometry.vertices.length - 1;
        facesGeometry.vertices.push(o.geometry.vertices[f.c].clone());
        var c = facesGeometry.vertices.length - 1;

        var newFace = new THREE.Face3(a, b, c, f.normal.clone(), f.color.clone(), f.materialIndex);
        facesGeometry.faces.push(newFace);
      });
    });
    var verticesMaterial = new THREE.PointsMaterial({color: 0xFFFF00, size: 0.3});
    var facesMaterial = new THREE.MeshBasicMaterial({color: 0xFF0000});

    var debugVertices = new THREE.Points(verticesGeometry, verticesMaterial);
    object.add(debugVertices);

    var debugFaces = new THREE.Mesh(facesGeometry, facesMaterial);
    var normals = new THREE.FaceNormalsHelper(debugFaces, 2, 0x0000FF, 2);
    debugFaces.add(normals);
    var edges = new THREE.WireframeHelper(debugFaces, 0xFFFF00);
    edges.position.y += 0.1;
    debugFaces.add(edges);

    object.add(debugFaces);

    selected.debugVertices = debugVertices;
    selected.debugFaces = debugFaces;
}

function setupDebugPaths(object, selected, info) {
  var color = 0x00FF00;
  var textMaterial = new THREE.MeshBasicMaterial({color: 0x000000});

  var graph = new THREE.Group();
  graph.position.y += 0.1;

  var debugLabels = new THREE.Group();
  debugLabels.visible = false;
  graph.add(debugLabels);

  var nodesGeometry = new THREE.Geometry();
  Object.keys(info.nodes).forEach(function(nid) {
    var node = info.nodes[nid];
    nodesGeometry.vertices.push(node.position);

    var text = new THREE.TextGeometry(nid.toString(), {size: 0.2, height: 0.05});
    var textObj = new THREE.Mesh(text, textMaterial);
    textObj.rotation.set(Math.PI/2, Math.PI, -Math.PI/2)
    textObj.position.set(node.position.x + 0.1, node.position.y + 0.1, node.position.z + 0.1);
    debugLabels.add(textObj);
  });

  var nodesMaterial = new THREE.PointsMaterial({color: color, size: 0.3});

  var nodes = new THREE.Points(nodesGeometry, nodesMaterial);
  graph.add(nodes);

  var pathEdgeMaterial = new THREE.LineBasicMaterial({color: color});

  var seen = new Set();
  Object.keys(info.nodes).forEach(function(nid) {
    if (seen.has(nid)) {
      return;
    }

    var node = info.nodes[nid];
    var pathEdgeGeometries = graphPathEdges(info.nodes, node, seen);
    pathEdgeGeometries.forEach(function(geo) {
      graph.add(new THREE.Line(geo, pathEdgeMaterial));
    });
  });

  object.add(graph);
  selected.debugPaths = graph;

  selected.debugLabels = debugLabels;
}

function graphPathEdges(nodes, start, seen) {
  var geometry = new THREE.Geometry();
  var geometries = [geometry];

  var current = start;
  while (current) {
    geometry.vertices.push(current.position.clone());
    seen.add(current.id);

    var next = 0;
    while (next < current.adjacents.length && seen.has(current.adjacents[next])) {
      next += 1;
    }

    current.adjacents.slice(next + 1).forEach(function(aid) {
      if (seen.has(aid)) {
        return;
      }
      var node = nodes[aid];
      var nodeGeometries = graphPathEdges(nodes, node, seen);
      nodeGeometries[0].vertices.unshift(current.position.clone());
      geometries.push.apply(geometries, nodeGeometries);
    });

    current = nodes[current.adjacents[next]];
  }

  return geometries;
}

document.getElementById("debug-faces").addEventListener("click", function() {
  if (selected.debugFaces) {
    selected.debugFaces.visible = !selected.debugFaces.visible;
  }
});

document.getElementById("debug-vertices").addEventListener("click", function() {
  if (selected.debugVertices) {
    selected.debugVertices.visible = !selected.debugVertices.visible;
  }
});

document.getElementById("debug-paths").addEventListener("click", function() {
  if (selected.debugPaths) {
    selected.debugPaths.visible = !selected.debugPaths.visible;
  }
});

document.getElementById("debug-labels").addEventListener("click", function() {
  if (selected.debugLabels) {
    selected.debugLabels.visible = !selected.debugLabels.visible;
  }
});

function applicableFaces(faces) {
  return faces.filter(function(face) {
    // Returns if the face is in any way upright
    return Math.abs(Y_AXIS.angleTo(face.normal)) < Math.PI/2;
  });
}

function traverse(object, callback) {
  callback(object);

  object.children.forEach(function(child) {
    traverse(child, callback);
  });
}

function traverseGeometries(object, callback) {
  return traverse(object, function(found) {
    if (found.geometry) {
      callback(found);
    }
  });
}

function tileInfo(target) {
  var info = {nodes: {}};
  Node.reset_ids();

  var boundingBox = new THREE.Box3().setFromObject(target);

  traverseGeometries(target, function(o) {
    // edge hash : related node
    var seenEdges = {};
    applicableFaces(o.geometry.faces).forEach(function(f) {
      var v1 = o.geometry.vertices[f.a];
      var v2 = o.geometry.vertices[f.b];
      var v3 = o.geometry.vertices[f.c];
      var midpoint = v1.clone().add(v2).add(v3).divideScalar(3);

      var node = new Node(midpoint, o.material);
      info.nodes[node.id] = node;

      var faceVerts = [v1, v2, v3];
      // This is a little wasteful because each hashedEdge is actually
      // inserted twice
      faceVerts.forEach(function(va) {
        faceVerts.forEach(function(vb) {
          if (va.equals(vb)) {
            return;
          }
          var hashedEdge = hashEdge(va, vb);
          if (!seenEdges[hashedEdge] && isOuterEdge(boundingBox, va, vb)) {
            // create new outer node at the midpoint of this edge
            var edgeMid = va.clone().add(vb).divideScalar(2);
            var edgeNode = new Node(edgeMid, o.material);
            info.nodes[edgeNode.id] = edgeNode;

            node.addAdjacent(edgeNode);
            edgeNode.addAdjacent(node);
          }

          if (seenEdges[hashedEdge] && seenEdges[hashedEdge] !== node) {
            node.addAdjacent(seenEdges[hashedEdge]);
            seenEdges[hashedEdge].addAdjacent(node);
          }
          seenEdges[hashedEdge] = node;
        });
      });
    });
  });
  return info;
}

function hashEdge(a, b) {
  return [[a.x, b.x], [a.y, b.y], [a.z, b.z]].map(hashPair).join(":");
}

function hashPair(p) {
  var a = p[0];
  var b = p[1];
  return ((a < b) ? [a, b] : [b, a]).join(",");
}

function isOuterEdge(box, a, b) {
  return (a.x === box.min.x && b.x === box.min.x)
    || (a.x === box.max.x && b.x === box.max.x)
    || (a.z === box.min.z && b.z === box.min.z)
    || (a.z === box.max.z && b.z === box.max.z);
}

var idx = 1;
function Node(position, material) {
  this.id = idx++;
  this.position = position;
  this.material = material;
  this.adjacents = [];
}

Node.reset_ids = function() {
  idx = 1;
};

Node.prototype.addAdjacent = function(node) {
  this.adjacents.push(node.id);
};

<commit_msg>Added face information to the nodes<commit_after>var WINDOW_WIDTH = windowWidth();
var WINDOW_HEIGHT = windowHeight();

var Y_AXIS = new THREE.Vector3(0, 1, 0);

var views = [
  {
    left: 0.5,
    bottom: 0,
    width: 0.5,
    height: 1.0,
    position: new THREE.Vector3(3, 10, -1),
    target: function() {
      return this.position.clone().setY(0);
    }
  },
  {
    left: 0,
    bottom: 0,
    width: 0.5,
    height: 1.0,
    position: new THREE.Vector3(10, 5, -10),
    target: function() {
      return scene.position.clone().setY(scene.position.y - 2);
    }
  },
];

var scene = new THREE.Scene();
views.forEach(function(view) {
  var width = WINDOW_WIDTH * view.width;
  var height = WINDOW_HEIGHT * view.height;
  var camera = new THREE.OrthographicCamera(-width/2, width/2, height/2, -height/2, 0, 1000);
  camera.zoom = 50;
  camera.position.set(view.position.x, view.position.y, view.position.z);

  view.camera = camera;
});

var light = new THREE.PointLight(0xffffff, 0.5, 1000);
light.position.set(100, 500, -100);
scene.add(light);

var light2 = new THREE.PointLight(0xffffff, 0.5, 1000);
light2.position.set(-100, 500, 100);
scene.add(light2);

var axisHelper = new THREE.AxisHelper(52);
axisHelper.position.z = 0.02;
scene.add(axisHelper);

var gridHelper = new THREE.GridHelper(20 * 3, 3);
scene.add(gridHelper);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
renderer.setClearColor(0xEEEEFF, 1);
document.getElementById("main-container").appendChild(renderer.domElement);

setup();

function render() {
  renderer.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);

  views.forEach(function(view) {
    var camera = view.camera;

    var width = Math.floor(WINDOW_WIDTH * view.width);
    var height = Math.floor(WINDOW_HEIGHT * view.height);

    var left = Math.floor(WINDOW_WIDTH  * view.left);
    var bottom = Math.floor(WINDOW_HEIGHT * view.bottom);

    renderer.setViewport(left, bottom, width, height);
    renderer.setScissor(left, bottom, width, height);
    renderer.enableScissorTest(true);

    camera.left = -width/2;
    camera.right = width/2;
    camera.top = height/2;
    camera.bottom = -height/2;
    camera.lookAt(view.target());

    camera.updateProjectionMatrix();

    renderer.render(scene, camera);
  });
}

function loop() {
  requestAnimationFrame(loop);
  render();
}
loop();

function windowWidth() {
  return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
}

function windowHeight() {
  return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
}

function onWindowResize(event) {
  var WINDOW_WIDTH = windowWidth();
  var WINDOW_WIDTH = windowHeight();
}
window.addEventListener('resize', onWindowResize, false);

function setup() {
  models.tiles().then(function(tiles) {
    var tilesParent = document.getElementById("tiles-container").getElementsByClassName("tiles")[0];
    tiles.forEach(function(tileData) {
      var tile = document.createElement('li');
      tile.dataset.name = tileData.name;
      tile.dataset.model = tileData.model;
      tile.addEventListener('click', function(evt) {
        var children = tilesParent.getElementsByClassName("selected");
        for (var i = 0; i < children.length; i++) {
          var child = children.item(i);
          child.classList.remove("selected");

        }

        tile.classList.add("selected");
        select(tile);
      });

      var thumb = document.createElement('img');
      thumb.src = tileData.image;

      tile.appendChild(thumb);
      tilesParent.appendChild(tile);
    }.bind(this));
  }.bind(this));
}

var selected = {};
function select(tileElement) {
  if (selected.object) {
    scene.remove(selected.object);
    selected = {};
  }

  return models.load(tileElement.dataset.model).then(function(object) {
    selected = {};
    selected.object = object;
    window.info = tileInfo(object.clone());

    setupDebugObjects(object, selected);

    setTimeout(function() {
      setupDebugPaths(object, selected, info);
    }, 100);

    scene.add(object);
  });
}

function setupDebugObjects(object, selected) {
    var verticesGeometry = new THREE.Geometry();
    var facesGeometry = new THREE.Geometry();
    traverseGeometries(object, function(o) {
      o.geometry.vertices.forEach(function(v) {
        verticesGeometry.vertices.push(v);
      });

      applicableFaces(o.geometry.faces).forEach(function(f) {
        facesGeometry.vertices.push(o.geometry.vertices[f.a].clone());
        var a = facesGeometry.vertices.length - 1;
        facesGeometry.vertices.push(o.geometry.vertices[f.b].clone());
        var b = facesGeometry.vertices.length - 1;
        facesGeometry.vertices.push(o.geometry.vertices[f.c].clone());
        var c = facesGeometry.vertices.length - 1;

        var newFace = new THREE.Face3(a, b, c, f.normal.clone(), f.color.clone(), f.materialIndex);
        facesGeometry.faces.push(newFace);
      });
    });
    var verticesMaterial = new THREE.PointsMaterial({color: 0xFFFF00, size: 0.3});
    var facesMaterial = new THREE.MeshBasicMaterial({color: 0xFF0000});

    var debugVertices = new THREE.Points(verticesGeometry, verticesMaterial);
    object.add(debugVertices);

    var debugFaces = new THREE.Mesh(facesGeometry, facesMaterial);
    var normals = new THREE.FaceNormalsHelper(debugFaces, 2, 0x0000FF, 2);
    debugFaces.add(normals);
    var edges = new THREE.WireframeHelper(debugFaces, 0xFFFF00);
    edges.position.y += 0.1;
    debugFaces.add(edges);

    object.add(debugFaces);

    selected.debugVertices = debugVertices;
    selected.debugFaces = debugFaces;
}

function setupDebugPaths(object, selected, info) {
  var color = 0x00FF00;
  var textMaterial = new THREE.MeshBasicMaterial({color: 0x000000});

  var graph = new THREE.Group();
  graph.position.y += 0.1;

  var debugLabels = new THREE.Group();
  debugLabels.visible = false;
  graph.add(debugLabels);

  var nodesGeometry = new THREE.Geometry();
  Object.keys(info.nodes).forEach(function(nid) {
    var node = info.nodes[nid];
    nodesGeometry.vertices.push(node.position);

    var text = new THREE.TextGeometry(nid.toString(), {size: 0.2, height: 0.05});
    var textObj = new THREE.Mesh(text, textMaterial);
    textObj.rotation.set(Math.PI/2, Math.PI, -Math.PI/2)
    textObj.position.set(node.position.x + 0.1, node.position.y + 0.1, node.position.z + 0.1);
    debugLabels.add(textObj);
  });

  var nodesMaterial = new THREE.PointsMaterial({color: color, size: 0.3});

  var nodes = new THREE.Points(nodesGeometry, nodesMaterial);
  graph.add(nodes);

  var pathEdgeMaterial = new THREE.LineBasicMaterial({color: color});

  var seen = new Set();
  Object.keys(info.nodes).forEach(function(nid) {
    if (seen.has(nid)) {
      return;
    }

    var node = info.nodes[nid];
    var pathEdgeGeometries = graphPathEdges(info.nodes, node, seen);
    pathEdgeGeometries.forEach(function(geo) {
      graph.add(new THREE.Line(geo, pathEdgeMaterial));
    });
  });

  object.add(graph);
  selected.debugPaths = graph;

  selected.debugLabels = debugLabels;
}

function graphPathEdges(nodes, start, seen) {
  var geometry = new THREE.Geometry();
  var geometries = [geometry];

  var current = start;
  while (current) {
    geometry.vertices.push(current.position.clone());
    seen.add(current.id);

    var next = 0;
    while (next < current.adjacents.length && seen.has(current.adjacents[next])) {
      next += 1;
    }

    current.adjacents.slice(next + 1).forEach(function(aid) {
      if (seen.has(aid)) {
        return;
      }
      var node = nodes[aid];
      var nodeGeometries = graphPathEdges(nodes, node, seen);
      nodeGeometries[0].vertices.unshift(current.position.clone());
      geometries.push.apply(geometries, nodeGeometries);
    });

    current = nodes[current.adjacents[next]];
  }

  return geometries;
}

document.getElementById("debug-faces").addEventListener("click", function() {
  if (selected.debugFaces) {
    selected.debugFaces.visible = !selected.debugFaces.visible;
  }
});

document.getElementById("debug-vertices").addEventListener("click", function() {
  if (selected.debugVertices) {
    selected.debugVertices.visible = !selected.debugVertices.visible;
  }
});

document.getElementById("debug-paths").addEventListener("click", function() {
  if (selected.debugPaths) {
    selected.debugPaths.visible = !selected.debugPaths.visible;
  }
});

document.getElementById("debug-labels").addEventListener("click", function() {
  if (selected.debugLabels) {
    selected.debugLabels.visible = !selected.debugLabels.visible;
  }
});

function applicableFaces(faces) {
  return faces.filter(function(face) {
    // Returns if the face is in any way upright
    return Math.abs(Y_AXIS.angleTo(face.normal)) < Math.PI/2;
  });
}

function traverse(object, callback) {
  callback(object);

  object.children.forEach(function(child) {
    traverse(child, callback);
  });
}

function traverseGeometries(object, callback) {
  return traverse(object, function(found) {
    if (found.geometry) {
      callback(found);
    }
  });
}

function tileInfo(target) {
  var info = {nodes: {}};
  Node.reset_ids();

  var boundingBox = new THREE.Box3().setFromObject(target);

  traverseGeometries(target, function(o) {
    // edge hash : related node
    var seenEdges = {};
    applicableFaces(o.geometry.faces).forEach(function(f) {
      var v1 = o.geometry.vertices[f.a];
      var v2 = o.geometry.vertices[f.b];
      var v3 = o.geometry.vertices[f.c];
      var midpoint = v1.clone().add(v2).add(v3).divideScalar(3);

      var node = new Node(midpoint, o.material, f.clone());
      info.nodes[node.id] = node;

      var faceVerts = [v1, v2, v3];
      // This is a little wasteful because each hashedEdge is actually
      // inserted twice
      faceVerts.forEach(function(va) {
        faceVerts.forEach(function(vb) {
          if (va.equals(vb)) {
            return;
          }
          var hashedEdge = hashEdge(va, vb);
          if (!seenEdges[hashedEdge] && isOuterEdge(boundingBox, va, vb)) {
            // create new outer node at the midpoint of this edge
            var edgeMid = va.clone().add(vb).divideScalar(2);
            var edgeNode = new Node(edgeMid, o.material);
            info.nodes[edgeNode.id] = edgeNode;

            node.addAdjacent(edgeNode);
            edgeNode.addAdjacent(node);
          }

          if (seenEdges[hashedEdge] && seenEdges[hashedEdge] !== node) {
            node.addAdjacent(seenEdges[hashedEdge]);
            seenEdges[hashedEdge].addAdjacent(node);
          }
          seenEdges[hashedEdge] = node;
        });
      });
    });
  });
  return info;
}

function hashEdge(a, b) {
  return [[a.x, b.x], [a.y, b.y], [a.z, b.z]].map(hashPair).join(":");
}

function hashPair(p) {
  var a = p[0];
  var b = p[1];
  return ((a < b) ? [a, b] : [b, a]).join(",");
}

function isOuterEdge(box, a, b) {
  return (a.x === box.min.x && b.x === box.min.x)
    || (a.x === box.max.x && b.x === box.max.x)
    || (a.z === box.min.z && b.z === box.min.z)
    || (a.z === box.max.z && b.z === box.max.z);
}

var idx = 1;
function Node(position, material, face) {
  this.id = idx++;
  this.position = position;
  this.material = material;
  this.face = face;
  this.adjacents = [];
}

Node.reset_ids = function() {
  idx = 1;
};

Node.prototype.addAdjacent = function(node) {
  this.adjacents.push(node.id);
};

<|endoftext|>


<commit_before>/**
* used to display homepage, show and ask pages list of story links
*/
HN.displayStories = function(){
	$.ajax({
		url: HN.storiesUrl,
		type: 'GET',
		dataType: 'json'
	})
	.done(function(storyIds) {
		getStoryInfo(storyIds);

	})
	.fail(function() {
		console.log("Error retrieving story ids");
	});

	function getStoryInfo(storyIds){
		var $top_list = $('#top_list');
		for(var i=0;i<HN.storiesPerPage;i++){
			var storyInfoUrl = HN.util.getItemInfoUrlFromId(storyIds[i]);
			if(storyInfoUrl){
				$.ajax({
					url: storyInfoUrl,
					type: 'GET',
					dataType: 'json'
				})
				.done(function(storyInfo) {
					if(!storyInfo){
						console.log('Story info is: ' + storyInfo + ' for story id: ' + storyIds[i]);
						return;
					}
					var story = new HN.Story(storyInfo);
					if(HN.shouldDisplayStory(story)){
						$top_list.append(getStoryHTML(story));
					}
				})
				.fail(function() {
					console.log("failed to get info about story: " + story.id);
				});
			}
		}
	}

	function getStoryHTML(story){
		var html = "

" + HN.util.getStoryTitleHTML(story);
		var num_comments = story.numComments();
		if(num_comments > 0){
			var comments_text = ' comment';
			if(num_comments > 1){
				comments_text = ' comments';
			}
			html = html + "
" + num_comments  + comments_text + "
";
		}
		html = html + "

";
		return html;
	}
};
<commit_msg>replace jquery with vanilla js for inserting story html in dom<commit_after>/**
* used to display homepage, show and ask pages list of story links
*/
HN.displayStories = function(){
	$.ajax({
		url: HN.storiesUrl,
		type: 'GET',
		dataType: 'json'
	})
	.done(function(storyIds) {
		getStoryInfo(storyIds);

	})
	.fail(function() {
		console.log("Error retrieving story ids");
	});

	function getStoryInfo(storyIds){
		var top_list = document.getElementById('top_list');
		for(var i=0;i<HN.storiesPerPage;i++){
			var storyInfoUrl = HN.util.getItemInfoUrlFromId(storyIds[i]);
			if(storyInfoUrl){
				$.ajax({
					url: storyInfoUrl,
					type: 'GET',
					dataType: 'json'
				})
				.done(function(storyInfo) {
					if(!storyInfo){
						console.log('Story info is: ' + storyInfo + ' for story id: ' + storyIds[i]);
						return;
					}
					var story = new HN.Story(storyInfo);
					if(HN.shouldDisplayStory(story)){
						top_list.insertAdjacentHTML('beforeend', getStoryHTML(story));
					}
				})
				.fail(function() {
					console.log("failed to get info about story: " + story.id);
				});
			}
		}
	}

	function getStoryHTML(story){
		var html = "

" + HN.util.getStoryTitleHTML(story);
		var num_comments = story.numComments();
		if(num_comments > 0){
			var comments_text = ' comment';
			if(num_comments > 1){
				comments_text = ' comments';
			}
			html = html + "
" + num_comments  + comments_text + "
";
		}
		html = html + "

";
		return html;
	}
};
<|endoftext|>


<commit_before>var render_to_theme = 'theme_js';

function render_theme()
{
    document.getElementById(render_to_theme).innerHTML = '';
    display_grid(render_to_theme);

    potential_theme_entries_lists = '
';

    potential_theme_entries_lists += get_heading_in_list_item('STARRED CLUES');
    potential_theme_entries_lists += get_starred_clues(PUZAPP.puzdata);

    min_theme_len = 9;
    potential_theme_entries_lists += get_heading_in_list_item('LONG ENTRIES');
    potential_theme_entries_lists += get_long_entries_and_their_common_substrings(PUZAPP.puzdata, min_theme_len);

    potential_theme_entries_lists += '
';

    document.getElementById(render_to_theme).innerHTML += potential_theme_entries_lists;
}

// TODO: fancy this up?
function get_heading_in_list_item(title)
{
    return '
' + title + '
';
}

function get_starred_clues(puzdata) {
    retval = '';

    var starred_across = getCluesPreOrPostfixedWith(puzdata.across_clues, '*', puzdata.across_entries, 'A');
    var starred_down = getCluesPreOrPostfixedWith(puzdata.down_clues, '*', puzdata.down_entries, 'D');
    var starred_clues = starred_across.concat(starred_down);

    if (starred_clues.length == 0) {
        retval += '<none>\n';
    } else {
        retval += '
\n';
        for (var i = 0; i < starred_clues.length; ++i) {
            retval += '
' + starred_clues[i] + "
\n";
        }
        retval += '
\n';
    }

    return retval;
}

function getCluesPreOrPostfixedWith(clues, token, entries, type) {
    var retval = [];

    for (var i in clues) {
        if (clues[i].startsWith(token) || clues[i].endsWith(token)) {
            // console.log(i + type + " " + clues[i]);
            retval.push(i + type + ' [' + clues[i] + '] ' + entries[i]);
        }
    }

    return retval;
}

function get_long_entries_and_their_common_substrings(puzdata, min_theme_len)
{
    retval = '';

    //document.getElementById(render_to_theme).style.fontFamily = "monospace";

    retval += '
';

    // TODO: stop (essentially) duplicating code (i.e., the next 15 lines--for across, then for down)
    retval += '
(across entries of length > ' + min_theme_len  + ')
';
    var potential_across_theme_entries = getStringsOfAtLeastMinLength(puzdata.across_entries, min_theme_len);
//    retval += '**' + potential_across_theme_entries + ': ' + potential_across_theme_entries.length + '**'
    if (potential_across_theme_entries.length == 0) {
        retval += '<none>' + '
\n';
    } else {
        retval += '
';
        longest_common_substrings_across = longestCommonSubstringsFromMultipleStrings.apply(null, potential_across_theme_entries);
        for (i_substr = 0; i_substr < longest_common_substrings_across.length; ++i_substr) {
            var longest_common_substring_across = longest_common_substrings_across[i_substr];
            retval += '
\nlongest common substring: ' + (longest_common_substring_across.length > 0 ? longest_common_substring_across : '<none>') + '
\n';
            retval += '
'
            for (var i = 0; i < potential_across_theme_entries.length; ++i) {
                retval += '
' + markSubstring(potential_across_theme_entries[i], longest_common_substring_across) + '
\n';
            }
            retval += '
'
        }
        retval += '
';
    }

    retval += '
(down entries of length > ' + min_theme_len  + ')
\n\n';
    var potential_down_theme_entries = getStringsOfAtLeastMinLength(puzdata.down_entries, min_theme_len);
    if (potential_down_theme_entries.length == 0) {
        retval += '<none>' + '
\n';
    } else {
        retval += '
';
        longest_common_substrings_down = longestCommonSubstringsFromMultipleStrings.apply(null, potential_down_theme_entries);
        for (i_substr = 0; i_substr < longest_common_substrings_down.length; ++i_substr) {
            var longest_common_substring_down = longest_common_substrings_down[i_substr];
            retval += '
\nlongest common substring: ' + (longest_common_substring_down.length > 0 ? longest_common_substring_down : '<none>') + '
\n';
            retval += '
'
            for (var i = 0; i < potential_down_theme_entries.length; ++i) {
                retval += '
' + markSubstring(potential_down_theme_entries[i], longest_common_substring_down) + '
\n';
            }
            retval += '
'
        }
        retval += '
';
    }

    retval += '
';

    return retval;
}

// returns a version of {string} with {substring} marked (by  tag)
// TODO: only highlights first instance of substring (per string)--do something else?
function markSubstring(string, substring)
{
    var retval = "";

    var substring_start_index = string.indexOf(substring);
    retval += string.substring(0, substring_start_index);
    retval += '' + substring + '';
    retval += string.substring(substring_start_index + substring.length, string.length);

    return retval;
}

// returns all strings from {strings} of length at least {min_len}
function getStringsOfAtLeastMinLength(strings, min_len)
{
    var retval = [];

    for (var i in strings) {
        var entry = strings[i];
        if (entry.length >= min_len) {
            retval.push(entry);
        }
    }

    return retval;
}

// returns the longest substrings common to {arguments}
function longestCommonSubstringsFromMultipleStrings()
{
    if (arguments.length === 0) {
        return ""; // TODO: do something else (e.g., throw an exception)?
    }

    var substringToSourcesMap = {};
    for (var iArg = 0; iArg < arguments.length; ++iArg) {
        var s = arguments[iArg];
        for (var i = 0; i < s.length; ++i) {
            for (var j = i; j <= s.length; ++j) {
                var substring = s.slice(i, j);
                addKeyValuePairToMultimap(substringToSourcesMap, substring, s);
            }
        }
    }

    var retval = [];
    var maxCommonSubstringLen = -1;
    for (var substring in substringToSourcesMap) {
//        if (!substringToSourcesMap.hasOwnProperty(substring)) { // TODO: is this needed? is this also needed for other for-in constructs?
//            continue;
//        }

        if (substring.length < maxCommonSubstringLen) {
            continue;
        }
        if (substringToSourcesMap[substring].length == arguments.length) {
            if (substring.length > maxCommonSubstringLen) {
                maxCommonSubstringLen = substring.length;
                retval = [];
            }

            retval.push(substring); // when here, substring.length >= (immediately previous value of) maxCommonSubstringLen
        }
    }

    return retval;
}

// bare-bones multimap implementation
function addKeyValuePairToMultimap(multimap, key, value) {
    if (!(key in multimap)) {
        multimap[key] = [];
    }

    if (multimap[key].indexOf(value) == -1) { // TODO: better way to do this?
        multimap[key].push(value);
    }
}
<commit_msg>refactor duplicate code; add some TODOs; misc cleanup<commit_after>var render_to_theme = 'theme_js';

function render_theme()
{
    document.getElementById(render_to_theme).innerHTML = '';
    display_grid(render_to_theme);

    // TODO?: is there a "better" way to do that--instead of just building strings with HTML, is there something offered by Javascript that is somehow better?
    potential_theme_entries_lists = '
';

    potential_theme_entries_lists += get_heading_in_list_item('STARRED CLUES');
    potential_theme_entries_lists += get_starred_clues(PUZAPP.puzdata);

    min_theme_len = 9; // TODO?: allow user to pick?
    potential_theme_entries_lists += get_heading_in_list_item('LONG ENTRIES');
    potential_theme_entries_lists += get_long_entries_and_their_common_substrings(PUZAPP.puzdata, min_theme_len);

    potential_theme_entries_lists += '
';

    document.getElementById(render_to_theme).innerHTML += potential_theme_entries_lists;
}

// TODO: fancy this up?
function get_heading_in_list_item(title)
{
    return '
' + title + '
';
}

function get_starred_clues(puzdata) {
    var retval = '';

    var starred_across = getCluesPreOrPostfixedWith(puzdata.across_clues, '*', puzdata.across_entries, 'A');
    var starred_down = getCluesPreOrPostfixedWith(puzdata.down_clues, '*', puzdata.down_entries, 'D');
    var starred_clues = starred_across.concat(starred_down);

    if (starred_clues.length == 0) {
        retval += '<none>\n';
    } else {
        retval += '
\n';
        for (var i = 0; i < starred_clues.length; ++i) {
            retval += '
' + starred_clues[i] + "
\n";
        }
        retval += '
\n';
    }

    return retval;
}

function getCluesPreOrPostfixedWith(clues, token, entries, type) {
    var retval = [];

    for (var i in clues) {
        if (clues[i].startsWith(token) || clues[i].endsWith(token)) {
            // console.log(i + type + " " + clues[i]);
            retval.push(i + type + ' [' + clues[i] + '] ' + entries[i]);
        }
    }

    return retval;
}

function get_long_entries_and_their_common_substrings(puzdata, min_theme_len)
{
    var retval = '';

    //document.getElementById(render_to_theme).style.fontFamily = "monospace";

    retval += '
';

    // TODO: stop (essentially) duplicating code (i.e., the next 15 lines--for across, then for down)
    retval += '
(across entries of length > ' + min_theme_len  + ')
';
    retval += get_one_directions_long_entries_and_their_common_substrings(puzdata.across_entries, min_theme_len);

    retval += '
(down entries of length > ' + min_theme_len  + ')
\n\n';
    retval += get_one_directions_long_entries_and_their_common_substrings(puzdata.down_entries, min_theme_len);

    retval += '
';

    return retval;
}

function get_one_directions_long_entries_and_their_common_substrings(entries, min_theme_len) {
    var retval = '';

    var potential_theme_entries = getStringsOfAtLeastMinLength(entries, min_theme_len);
    if (potential_theme_entries.length == 0) {
        retval += '<none>' + '
\n';
    } else {
        retval += '
';
        longest_common_substrings = longestCommonSubstringsFromMultipleStrings.apply(null, potential_theme_entries);
        for (i_substr = 0; i_substr < longest_common_substrings.length; ++i_substr) {
            var longest_common_substring = longest_common_substrings[i_substr];
            retval += '
\nlongest common substring: ' + (longest_common_substring.length > 0 ? longest_common_substring : '<none>') + '
\n';
            retval += '
'
            for (var i = 0; i < potential_theme_entries.length; ++i) {
                retval += '
' + markSubstring(potential_theme_entries[i], longest_common_substring) + '
\n';
            }
            retval += '
'
        }
        retval += '
';
    }

    return retval;
}

// returns a version of {string} with {substring} marked (by  tag)
// TODO: only highlights first instance of substring (per string)--do something else?
function markSubstring(string, substring)
{
    var retval = '';

    var substring_start_index = string.indexOf(substring);
    retval += string.substring(0, substring_start_index);
    retval += '' + substring + '';
    retval += string.substring(substring_start_index + substring.length, string.length);

    return retval;
}

// returns all strings from {strings} of length at least {min_len}
function getStringsOfAtLeastMinLength(strings, min_len)
{
    var retval = [];

    for (var i in strings) {
        var entry = strings[i];
        if (entry.length >= min_len) {
            retval.push(entry);
        }
    }

    return retval;
}

// returns the longest substrings common to {arguments}
function longestCommonSubstringsFromMultipleStrings()
{
    if (arguments.length === 0) {
        return ''; // TODO: do something else (e.g., throw an exception)?
    }

    var substringToSourcesMap = {};
    for (var iArg = 0; iArg < arguments.length; ++iArg) {
        var s = arguments[iArg];
        for (var i = 0; i < s.length; ++i) {
            for (var j = i; j <= s.length; ++j) {
                var substring = s.slice(i, j);
                addKeyValuePairToMultimap(substringToSourcesMap, substring, s);
            }
        }
    }

    var retval = [];
    var maxCommonSubstringLen = -1;
    for (var substring in substringToSourcesMap) {
//        if (!substringToSourcesMap.hasOwnProperty(substring)) { // TODO: is this needed? is this also needed for other for-in constructs?
//            continue;
//        }

        if (substring.length < maxCommonSubstringLen) {
            continue;
        }
        if (substringToSourcesMap[substring].length == arguments.length) {
            if (substring.length > maxCommonSubstringLen) {
                maxCommonSubstringLen = substring.length;
                retval = [];
            }

            retval.push(substring); // when here, substring.length >= (immediately previous value of) maxCommonSubstringLen
        }
    }

    return retval;
}

// bare-bones multimap implementation
function addKeyValuePairToMultimap(multimap, key, value) {
    if (!(key in multimap)) {
        multimap[key] = [];
    }

    if (multimap[key].indexOf(value) == -1) { // TODO: better way to do this?
        multimap[key].push(value);
    }
}
<|endoftext|>


<commit_before>$(window).on('load', function() {
    $('#preloader').fadeOut( 1000 );
    $('body').css({'overflow':'visible'});
});

$(".project-list").hide();

if(!(/Android|webOS|BlackBerry|iPhone|iPod|iPad|Opera Mini|IEMobile/i.test(navigator.userAgent) )) { //if not these devices(userAgents)

  $.scrollify({
    section:".portfolio-section",
    scrollbars:true,
    before:function(i,panels) {

      var ref = panels[i].attr("data-section-name");

      $(".pagination .active").removeClass("active");

      $(".pagination").find("a[href=\"#" + ref + "\"]").addClass("active");

      var dname = $.scrollify.current().attr('data-section-name');

      $(".projects").on('click', function(){
        if($(".projects").hasClass('active')) {
          $.scrollify.move('#landing');
          ($(this).removeClass('active'));
          console.log("hey");
        }
      });

      if($.inArray($.scrollify.current().attr('data-section-name') , ['google-clips', 'azure', 'digital-escrow', 'oh-hey', 'skintcinnati']) != -1){
        $(".project-list, .project-list li").each(function(i) {
          $(this).fadeIn(200);
        });
        $(".projects").addClass("active");
        $(".carat").addClass("carat-active");
      } else {
        $($(".project-list, .project-list li").get().reverse()).each(function(i) {
          $(this).fadeOut(200);
          $(".carat").removeClass("carat-active");
        });
      }

    },
    afterRender:function() {
      var pagination = "
";
      var activeClass = "";
      $(".portfolio-section").each(function(i) {
        activeClass = "";
        if(i===0) {
          activeClass = "active";
        }
        pagination += "
" + $(this).attr("data-section-name").charAt(0).toUpperCase() + $(this).attr("data-section-name").slice(1) + "
";
      });

      pagination += "
";

      $(".home").append(pagination);
      $(".pagination a").on("click",$.scrollify.move);
      $(".nav-logo a").on("click",$.scrollify.move);
    }
  });
};

<commit_msg>Add Timeout for Projects click and goto landing part<commit_after>$(window).on('load', function() {
    $('#preloader').fadeOut( 1000 );
    $('body').css({'overflow':'visible'});
});

$(".project-list").hide();

if(!(/Android|webOS|BlackBerry|iPhone|iPod|iPad|Opera Mini|IEMobile/i.test(navigator.userAgent) )) { //if not these devices(userAgents)

  $(".projects").on('click', function(){
    if($(".projects").hasClass('active')) {
      ($(this).removeClass('active'));
      setTimeout(
        function()
        {
          $.scrollify.move('#landing');
        }, 100);
      console.log("hey");
    }
  });

  $.scrollify({
    section:".portfolio-section",
    scrollbars:true,
    before:function(i,panels) {

      var ref = panels[i].attr("data-section-name");

      $(".pagination .active").removeClass("active");

      $(".pagination").find("a[href=\"#" + ref + "\"]").addClass("active");

      var dname = $.scrollify.current().attr('data-section-name');

      if($.inArray($.scrollify.current().attr('data-section-name') , ['google-clips', 'azure', 'digital-escrow', 'oh-hey', 'skintcinnati']) != -1){
        $(".project-list, .project-list li").each(function(i) {
          $(this).fadeIn(200);
        });
          $(".projects").addClass("active");
        $(".carat").addClass("carat-active");
      } else {
        $($(".project-list, .project-list li").get().reverse()).each(function(i) {
          $(this).fadeOut(200);
        });
        $(".carat").removeClass("carat-active");
      }

    },
    afterRender:function() {
      var pagination = "
";
      var activeClass = "";
      $(".portfolio-section").each(function(i) {
        activeClass = "";
        if(i===0) {
          activeClass = "active";
        }
        pagination += "
" + $(this).attr("data-section-name").charAt(0).toUpperCase() + $(this).attr("data-section-name").slice(1) + "
";
      });

      pagination += "
";

      $(".home").append(pagination);
      $(".pagination a").on("click",$.scrollify.move);
      $(".nav-logo a").on("click",$.scrollify.move);
    }
  });
};

<|endoftext|>


<commit_before>/**
 * Authorization interceptor for adding token to outgoing requests, and handling error responses
*/
(function () {
    'use strict';

    angular
        .module(HygieiaConfig.module)
        .factory('authInterceptor', authInterceptor);

    authInterceptor.$inject = ['$q', '$location', 'tokenService'];
    function authInterceptor($q, $location, tokenService) {
      return {
        responseError: function (response) {
          if (response.status === 401 || response.status === 500) {
            tokenService.removeToken();
            $location.path('/login');
          }
          return $q.reject(response);
        }
      };
    }
})();
<commit_msg>Fix the issues with user logins (#3129)<commit_after>/**
 * Authorization interceptor for adding token to outgoing requests, and handling error responses
*/
(function () {
    'use strict';

    angular
        .module(HygieiaConfig.module)
        .factory('authInterceptor', authInterceptor);

    authInterceptor.$inject = ['$q', '$location', 'tokenService'];
    function authInterceptor($q, $location, tokenService) {
      return {
        responseError: function (response) {
          if (response.status === 401 || response.status === 403) {
            tokenService.removeToken();
            $location.path('/login');
          }
          return $q.reject(response);
        }
      };
    }
})();
<|endoftext|>