<commit_before>'use strict';

if (!process.env.SLACK_API_TOKEN) {
  console.log('Error: Specify token in environment');
  process.exit(1);
}

String.prototype.capitalize = function(){
  return this.toLowerCase().replace( /\b\w/g, (m) => {
    return m.toUpperCase();
  });
};

Number.prototype.formatISK = function(n, x, s, c) {
  var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
    num = this.toFixed(Math.max(0, ~~n));

  return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
};

const os = require('os');
const evejsapi = require('evejsapi');

const EveCentral = require('./lib/central');
const eveCentral = new EveCentral();

const XmlClient = new evejsapi.client.xml({
  cache: new evejsapi.cache.redis(),
});

const Botkit = require('botkit');
const controller = Botkit.slackbot({
  logLevel: process.env.LOG_LEVEL || info,
  storage: require('botkit-storage-redis')()
});

const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('./database/sqlite-latest.sqlite');
db.serialize(() => {
  controller.spawn({
    token: process.env.SLACK_API_TOKEN || ''
  }).startRTM();
});

controller.hears(['^!serverstatus$', '^!server$', '^!ServerStatus$'], 'ambient,direct_message', (bot, message) => {
  XmlClient.fetch('server:ServerStatus')
    .then((data) => {
      bot.reply(message, {
        'attachments': [{
          'fallback': 'ServerStatus - Status couldn\'t be verified:',
          'title': 'EvE Online Server Status',
          'fields': [{
            'title': 'Tranquility',
            'value': '\t' + (data.serverOpen === 'True' ? 'Online' : 'Offline'),
            'short': true
          }, {
            'title': 'Online Player',
            'value': '\t' + data.onlinePlayers,
            'short': true
          }],
          'color': data.serverOpen === 'True' ? 'good' : 'danger'
        }]
      });
    })
    .catch((err) => {
      bot.reply(message, {
        text: 'can not fetch serverStatus (' + err + ')'
      });
    })
  ;
});

controller.hears(['^!hi$', '^!hello$'], 'ambient,direct_message', (bot, message) => {
  bot.startPrivateConversation(message, (err, dm) => {
    dm.say({
      text: 'Hello, im your sister of EVE™ bot for slack. These are your available commands at the moment in this channel.',
      attachments: [{
        color: 'good',
        title: '• [hello], [hi] -- greets you\n' +
        EveCentral.globalHelp() + '\n' +
        '• [serverStatus] -- command returns the server status',
        mrkdwn_in: [
          'title'
        ]
      }]
    });
  });
});

controller.hears(['^!central$'], 'direct_message', (bot, message) => {
  bot.startPrivateConversation(message, (err, dm) => {
    dm.say({
      text: '',
      attachments: EveCentral.allHelp()
    });
  });
});

controller.hears(['^!central hub'], 'direct_message', (bot, message) => {
  eveCentral.hub(bot, message);
});

controller.hears(['^!central price'], 'direct_message', (bot, message) => {
  eveCentral.pricetype(bot, message);
});

controller.hears(['^!central'], 'direct_message', (bot, message) => {
  const search = message.text.match(/([\""].+?[\""]|[^ ]+)/g);

  if (search.length > 4 || message.text.indexOf('"') === -1) {
    bot.startPrivateConversation(message, (err, dm) => {
      dm.say({
        text: '',
        attachments: [{
          color: 'danger',
          title: 'Parameter Match failed'
        }]
      });
    });
  } else {
    eveCentral.fetch(bot, message, search, db);
  }
});

controller.hears(['uptime', 'identify yourself', 'who are you', 'what is your name'],
  'direct_message,direct_mention,mention,ambient', (bot, message) => {

    const hostname = os.hostname();
    const uptime = formatUptime(process.uptime());

    bot.reply(message,
      ':robot_face: I am a bot named <@' + bot.identity.name +
      '>. I have been running for ' + uptime + ' on ' + hostname + '.');
  });

function formatUptime(uptime) {
  let unit = 'second';
  if (uptime > 60) {
    uptime = uptime / 60;
    unit = 'minute';
  }

  if (uptime > 60) {
    uptime = uptime / 60;
    unit = 'hour';
  }

  if (uptime !== 1) {
    unit = unit + 's';
  }

  return uptime.toFixed(2) + ' ' + unit;
}
<commit_msg>remove hostname on identify message<commit_after>'use strict';

if (!process.env.SLACK_API_TOKEN) {
  console.log('Error: Specify token in environment');
  process.exit(1);
}

String.prototype.capitalize = function(){
  return this.toLowerCase().replace( /\b\w/g, (m) => {
    return m.toUpperCase();
  });
};

Number.prototype.formatISK = function(n, x, s, c) {
  var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
    num = this.toFixed(Math.max(0, ~~n));

  return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
};

const evejsapi = require('evejsapi');

const EveCentral = require('./lib/central');
const eveCentral = new EveCentral();

const XmlClient = new evejsapi.client.xml({
  cache: new evejsapi.cache.redis(),
});

const Botkit = require('botkit');
const controller = Botkit.slackbot({
  logLevel: process.env.LOG_LEVEL || info,
  storage: require('botkit-storage-redis')()
});

const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('./database/sqlite-latest.sqlite');
db.serialize(() => {
  controller.spawn({
    token: process.env.SLACK_API_TOKEN || ''
  }).startRTM();
});

controller.hears(['^!serverstatus$', '^!server$', '^!ServerStatus$'], 'ambient,direct_message', (bot, message) => {
  XmlClient.fetch('server:ServerStatus')
    .then((data) => {
      bot.reply(message, {
        'attachments': [{
          'fallback': 'ServerStatus - Status couldn\'t be verified:',
          'title': 'EvE Online Server Status',
          'fields': [{
            'title': 'Tranquility',
            'value': '\t' + (data.serverOpen === 'True' ? 'Online' : 'Offline'),
            'short': true
          }, {
            'title': 'Online Player',
            'value': '\t' + data.onlinePlayers,
            'short': true
          }],
          'color': data.serverOpen === 'True' ? 'good' : 'danger'
        }]
      });
    })
    .catch((err) => {
      bot.reply(message, {
        text: 'can not fetch serverStatus (' + err + ')'
      });
    })
  ;
});

controller.hears(['^!hi$', '^!hello$'], 'ambient,direct_message', (bot, message) => {
  bot.startPrivateConversation(message, (err, dm) => {
    dm.say({
      text: 'Hello, im your sister of EVE™ bot for slack. These are your available commands at the moment in this channel.',
      attachments: [{
        color: 'good',
        title: '• [hello], [hi] -- greets you\n' +
        EveCentral.globalHelp() + '\n' +
        '• [serverStatus] -- command returns the server status',
        mrkdwn_in: [
          'title'
        ]
      }]
    });
  });
});

controller.hears(['^!central$'], 'direct_message', (bot, message) => {
  bot.startPrivateConversation(message, (err, dm) => {
    dm.say({
      text: '',
      attachments: EveCentral.allHelp()
    });
  });
});

controller.hears(['^!central hub'], 'direct_message', (bot, message) => {
  eveCentral.hub(bot, message);
});

controller.hears(['^!central price'], 'direct_message', (bot, message) => {
  eveCentral.pricetype(bot, message);
});

controller.hears(['^!central'], 'direct_message', (bot, message) => {
  const search = message.text.match(/([\""].+?[\""]|[^ ]+)/g);

  if (search.length > 4 || message.text.indexOf('"') === -1) {
    bot.startPrivateConversation(message, (err, dm) => {
      dm.say({
        text: '',
        attachments: [{
          color: 'danger',
          title: 'Parameter Match failed'
        }]
      });
    });
  } else {
    eveCentral.fetch(bot, message, search, db);
  }
});

controller.hears(['uptime', 'identify yourself', 'who are you', 'what is your name'],
  'direct_message,direct_mention,mention,ambient', (bot, message) => {

    const uptime = formatUptime(process.uptime());

    bot.reply(message,
      ':robot_face: I am a bot named <@' + bot.identity.name +
      '>. I have been running for ' + uptime + '.');
  });

function formatUptime(uptime) {
  let unit = 'second';
  if (uptime > 60) {
    uptime = uptime / 60;
    unit = 'minute';
  }

  if (uptime > 60) {
    uptime = uptime / 60;
    unit = 'hour';
  }

  if (uptime !== 1) {
    unit = unit + 's';
  }

  return uptime.toFixed(2) + ' ' + unit;
}
<|endoftext|>


<commit_before>'use strict';

// ---------------------------------------------------------------------------

const liqui = require ('./liqui.js');

// ---------------------------------------------------------------------------

module.exports = class tidex extends liqui {

    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'tidex',
            'name': 'Tidex',
            'countries': 'UK',
            'rateLimit': 2000,
            'version': '3',
            'has': {
                // 'CORS': false,
                // 'fetchTickers': true
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/30781780-03149dc4-a12e-11e7-82bb-313b269d24d4.jpg',
                'api': {
                    'public': 'https://api.tidex.com/api',
                    'private': 'https://api.tidex.com/tapi',
                },
                'www': 'https://tidex.com',
                'doc': 'https://tidex.com/public-api',
                'fees': [
                    'https://tidex.com/assets-spec',
                    'https://tidex.com/pairs-spec',
                ],
            },
            'fees': {
                'trading': {
                    'tierBased': false,
                    'percentage': true,
                    'taker': 0.1 / 100,
                    'maker': 0.1 / 100,
                },
                'funding': {
                    'tierBased': false,
                    'percentage': false,
                    'withdraw': {
                        'BTC': 0.002,
                        'LTC': 0.001,
                        'ETH': 0.01,
                        'DASH': 0.01,
                        'DOGE': 0.01,
                        'BTS': 5.0,
                        'STEEM': 0.01,
                        'WAVES': 0.01,
                        'WCT': 0.01,
                        'WBTC': 0.0001,
                        'INCNT': 0.1,
                        'B': 0.1,
                        'MRT': 1.0,
                        'MER': 5.0,
                        'AQUA': 0.001,
                        'RBX': 100.0,
                        'TKS': 0.1,
                        'WUSD': 0.1,
                        'WEUR': 0.1,
                        'WGO': 1.0,
                        'GNT': 1.0,
                        'EDG': 1.0,
                        'RLC': 0.3,
                        'ICN': 0.3,
                        'WINGS': 1.0,
                        'VSL': 1.0,
                        'TIME': 0.01,
                        'TAAS': 0.3,
                        'KOLION': 0.1,
                        'RIDDLE': 10.0,
                        'ANT': 0.1,
                        'EFYT': 0.1,
                        'MGO': 0.5,
                        'wETT': 1.0,
                        'eETT': 1.0,
                        'QRL': 1.0,
                        'eMGO': 1.0,
                        'BNT': 1.0,
                        'SNM': 10.0,
                        'ZRC': 0.1,
                        'SNT': 30.0,
                        'MCO': 0.3,
                        'STORJ': 1.0,
                        'EOS': 0.3,
                        'WGR': 3.0,
                        'STA': 0.1,
                        'PBT': 0.0001,
                        'BCH': 0.00125,
                        'wSUR': 0.05,
                        'SUR': 0.05,
                        'MSP': 5.0,
                        'InPay': 0.5,
                        'MTL': 0.1,
                        'AHT': 0.2,
                        'PING': 1.0,
                        'EOT': 0.2,
                        'AE': 3.0,
                        'PIX': 10.0,
                        'CREDO': 30.0,
                        'LIFE': 1000.0,
                        'MTH': 5.0,
                        'BMC': 1.0,
                        'TRCT': 5.0,
                        'KNC': 1.0,
                        'MSD': 0.2,
                        'SUB': 10.0,
                        'ENJ': 20.0,
                        'EVX': 1.0,
                        'OCL': 3.0,
                        'ENG': 2.0,
                        'TDX': 1.0,
                        'LA': 2.0,
                        'PRG': 0.5,
                        'ICOS': 0.03,
                        'USDT': 40.0,
                        'ARN': 2.0,
                        'RYZ': 10.0,
                        'B2B': 1.0,
                        'CAT': 10.0,
                        'SNOV': 25.0,
                        'DRGN': 3.0,
                        'TIE': 20.0,
                        'TRX': 50.0,
                        'WAX': 5.0,
                        'AGI': 5.0,
                        'VEE': 20.0,
                    },
                    'deposit': {
                        'BTC': 0,
                        'ETH': 0,
                        'LTC': 0,
                        'DOGE': 0,
                        'ICN': 0,
                        'DASH': 0,
                        'GNO': 0,
                        'EOS': 0,
                        'BCH': 0,
                        'USDT': 0,
                    },
                },
            },
        });
    }
}
<commit_msg>tidex MGO → WMGO, EMGO → MGO, #1487<commit_after>'use strict';

// ---------------------------------------------------------------------------

const liqui = require ('./liqui.js');

// ---------------------------------------------------------------------------

module.exports = class tidex extends liqui {

    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'tidex',
            'name': 'Tidex',
            'countries': 'UK',
            'rateLimit': 2000,
            'version': '3',
            'has': {
                // 'CORS': false,
                // 'fetchTickers': true
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/30781780-03149dc4-a12e-11e7-82bb-313b269d24d4.jpg',
                'api': {
                    'public': 'https://api.tidex.com/api',
                    'private': 'https://api.tidex.com/tapi',
                },
                'www': 'https://tidex.com',
                'doc': 'https://tidex.com/public-api',
                'fees': [
                    'https://tidex.com/assets-spec',
                    'https://tidex.com/pairs-spec',
                ],
            },
            'fees': {
                'trading': {
                    'tierBased': false,
                    'percentage': true,
                    'taker': 0.1 / 100,
                    'maker': 0.1 / 100,
                },
                'funding': {
                    'tierBased': false,
                    'percentage': false,
                    'withdraw': {
                        'BTC': 0.002,
                        'LTC': 0.001,
                        'ETH': 0.01,
                        'DASH': 0.01,
                        'DOGE': 0.01,
                        'BTS': 5.0,
                        'STEEM': 0.01,
                        'WAVES': 0.01,
                        'WCT': 0.01,
                        'WBTC': 0.0001,
                        'INCNT': 0.1,
                        'B': 0.1,
                        'MRT': 1.0,
                        'MER': 5.0,
                        'AQUA': 0.001,
                        'RBX': 100.0,
                        'TKS': 0.1,
                        'WUSD': 0.1,
                        'WEUR': 0.1,
                        'WGO': 1.0,
                        'GNT': 1.0,
                        'EDG': 1.0,
                        'RLC': 0.3,
                        'ICN': 0.3,
                        'WINGS': 1.0,
                        'VSL': 1.0,
                        'TIME': 0.01,
                        'TAAS': 0.3,
                        'KOLION': 0.1,
                        'RIDDLE': 10.0,
                        'ANT': 0.1,
                        'EFYT': 0.1,
                        'MGO': 0.5,
                        'wETT': 1.0,
                        'eETT': 1.0,
                        'QRL': 1.0,
                        'eMGO': 1.0,
                        'BNT': 1.0,
                        'SNM': 10.0,
                        'ZRC': 0.1,
                        'SNT': 30.0,
                        'MCO': 0.3,
                        'STORJ': 1.0,
                        'EOS': 0.3,
                        'WGR': 3.0,
                        'STA': 0.1,
                        'PBT': 0.0001,
                        'BCH': 0.00125,
                        'wSUR': 0.05,
                        'SUR': 0.05,
                        'MSP': 5.0,
                        'InPay': 0.5,
                        'MTL': 0.1,
                        'AHT': 0.2,
                        'PING': 1.0,
                        'EOT': 0.2,
                        'AE': 3.0,
                        'PIX': 10.0,
                        'CREDO': 30.0,
                        'LIFE': 1000.0,
                        'MTH': 5.0,
                        'BMC': 1.0,
                        'TRCT': 5.0,
                        'KNC': 1.0,
                        'MSD': 0.2,
                        'SUB': 10.0,
                        'ENJ': 20.0,
                        'EVX': 1.0,
                        'OCL': 3.0,
                        'ENG': 2.0,
                        'TDX': 1.0,
                        'LA': 2.0,
                        'PRG': 0.5,
                        'ICOS': 0.03,
                        'USDT': 40.0,
                        'ARN': 2.0,
                        'RYZ': 10.0,
                        'B2B': 1.0,
                        'CAT': 10.0,
                        'SNOV': 25.0,
                        'DRGN': 3.0,
                        'TIE': 20.0,
                        'TRX': 50.0,
                        'WAX': 5.0,
                        'AGI': 5.0,
                        'VEE': 20.0,
                    },
                    'deposit': {
                        'BTC': 0,
                        'ETH': 0,
                        'LTC': 0,
                        'DOGE': 0,
                        'ICN': 0,
                        'DASH': 0,
                        'GNO': 0,
                        'EOS': 0,
                        'BCH': 0,
                        'USDT': 0,
                    },
                },
            },
        });
    }

    commonCurrencyCode (currency) {
        if (!this.substituteCommonCurrencyCodes)
            return currency;
        if (currency === 'XBT')
            return 'BTC';
        if (currency === 'BCC')
            return 'BCH';
        if (currency === 'DRK')
            return 'DASH';
        // they misspell DASH as DSH? (may not be true)
        if (currency === 'DSH')
            return 'DASH';
        // their MGO stands for MGO on WAVES (aka WMGO), see issue #1487
        if (currency === 'MGO')
            return 'WMGO';
        // the MGO on ETH is called EMGO on Tidex
        if (currency === 'EMGO')
            return 'MGO';
        return currency;
    }
}
<|endoftext|>


<commit_before>define([
  'underscore'
], function(_) {

  // APP INFO
  // name: name of the app
  // svg: svg-id linked to svg icon definitions
  // content: content that will be shown when you click one app
  // source: the source of the app
  // tags: you should choose one of these => africa, asia, boreal-forests, commodities, crowdsourcing, data, fires, global-forest-watch, latin-america, maps, mining, mobile, palm-oil, satellite-imagery
  //       if you want more than once, please separate them by commas

  // LINK BUTTON
  // href: link to the app will be shown when you click one app
  // link_text: text that should appear inside the button
  // classname: classes that should have the link/button (mobile-friendly should prevent mobile users to leave GFW)
  // mobile_friendly: other => when you don't know if the app that is requested is mobile optimized. That should change the message
  // target: true if you need to open it in a new page

  var applicationsHelper = [
    {
      id: 1,
      name: 'GFW Interactive map',
      svg: '#shape-world',
      content: 'View and analyze data on the GFW Interactive Map.',
      href: '/map',
      link_text: 'Open map',
      classname: 'btn green medium',
      source: 'World Resources Institute',
      tags: 'data, fires, global-forest-watch, maps, mining, mobile, palm-oil, satellite-imagery'
    },
    {
      id: 2,
      name: 'Country profiles & rankings',
      svg: '#shape-country',
      content: 'View country-specific data, analyze forest change within a country or subnational jurisdiction, or view country rankings based on forest statistics.',
      href: '/countries',
      link_text: 'View countries',
      classname: 'btn green medium',
      source: 'World Resources Institute',
      tags: 'boreal-forests, data, global-forest-watch'
    },
    {
      id: 3,
      name: 'Open Data Portal',
      svg: '#shape-download',
      content: 'Browse, learn more about, and download the data displayed on Global Forest Watch.',
      href: 'http://data.globalforestwatch.org',
      link_text: 'Browse data',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'data, fires, global-forest-watch, maps, mining, palm-oil, satellite-imagery'
    },
    {
      id: 4,
      name: 'Fires',
      svg: '#shape-fire',
      content: 'Track forest fires and haze in the ASEAN region.',
      href: 'http://fires.globalforestwatch.org/',
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'asia, data, fires, global-forest-watch, maps, palm-oil, satellite-imagery'
    },
    {
      id: 5,
      name: 'Commodities',
      svg: '#shape-commodities',
      content: 'Identify deforestation risk in commodity supply chains.',
      href: 'http://commodities.globalforestwatch.org/',
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'asia, commodities, data, fires, global-forest-watch, maps, mining, palm-oil'
    },
    {
      id: 6,
      name: 'Climate',
      svg: '#shape-climate',
      content: 'Track carbon emissions and removals in forest landscapes.',
      href: 'http://climate.globalforestwatch.org/',
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'data, global-forest-watch, maps'
    },
    {
      id: 7,
      name: 'Global Forest Watch: Sumatra campaign on Tomnod',
      svg: '#shape-tomnod',
      content: 'Help Global Forest Watch Fires track illegal fires and preserve the health of people and forests in Southeast Asia.',
      href: 'http://www.tomnod.com/campaign/gfw2_2014/map/2qwx1oy6u',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Digital Globe',
      mobile_friendly: 'other',
      tags: 'asia, crowdsourcing, data, fires, maps, palm-oil, satellite-imagery'
    },
    {
      id: 8,
      name: 'Open Landscape Partnership Platform',
      svg: '#shape-landscape',
      content: 'View and analyze ultra-high-resolution satellite imagery (up to 50 centimeters) for select forest landscapes.',
      href: 'http://www.sustainablepalmoil.org/spott',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Transparent World',
      mobile_friendly: 'other',
      tags: 'crowdsourcing, data, maps, satellite-imagery'
    },
    {
      id: 9,
      name: 'Sustainable Palm Oil Transparency Toolkit (SPOTT)',
      svg: '#shape-spott',
      content: 'Assess oil palm growers on the information that they make publicly available about the sustainability of their operations.',
      href: 'http://www.sustainablepalmoil.org/spott',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Zoological Society of London',
      mobile_friendly: 'other',
      tags: 'asia, commodities, data, global-forest-watch, maps, palm-oil'
    },
    {
      id: 10,
      name: 'Monitoring of the Andean Amazon Project (MAAP)',
      svg: '#shape-aca',
      content: 'View information, maps and analysis from a new deforestation monitoring system for the Andean Amazon.',
      href: 'http://maaproject.org/en/',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Amazon Conservation Association',
      mobile_friendly: 'other',
      tags: 'data, latin-america, maps, mining, satellite imagery'
    },
    {
      id: 11,
      name: 'Cameroon Forest Atlas',
      svg: '#shape-CMR',
      content: 'View an interactive map with land-use data for Cameroon.',
      href: 'http://cmr.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Forest and Wildlife of Cameroon',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 12,
      name: 'Central African Republic Forest Atlas',
      svg: '#shape-CAF',
      content: 'View an interactive map with land-use data for the Central African Republic.',
      href: 'http://caf.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Water, Forests, Hunting, and Fishing of the Central African Republic',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps'
    },
    {
      id: 13,
      name: 'Republic of Congo Forest Atlas',
      svg: '#shape-COG',
      content: 'View an interactive map with land-use data for the Congo.',
      href: 'http://cog.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Economy and Sustainable Forestry Development of the Congo',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 14,
      name: 'Democratic Republic of Congo Forest Atlas',
      svg: '#shape-COD',
      content: 'View an interactive map with land-use data for the Democratic Republic of the Congo.',
      href: 'http://cod.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Environment, Nature Conservation, and Tourism of the Democratic Republic of the Congo',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 15,
      name: 'Equatorial Guinea Forest Atlas',
      svg: '#shape-GNQ',
      content: 'View an interactive map with land-use data for Equatorial Guinea.',
      href: 'http://gnq.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Agriculture and Forestry of Equatorial Guinea',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps'
    },
    {
      id: 16,
      name: 'Gabon Forest Atlas',
      svg: '#shape-GAB',
      content: 'View an interactive map with land-use data for Gabon.',
      href: 'http://gab.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of the Forest, Environment, and Protection of Natural Resources of Gabon',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 17,
      name: 'Open Foris',
      svg: '#shape-open-foris',
      content: 'A set of free and open-source software tools that facilitates flexible and efficient data collection, analysis, and reporting.',
      href: 'http://www.openforis.org/',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Forestry Department of the Food and Agriculture Organization of the United Nations',
      mobile_friendly: 'other',
      tags: 'crowdsourcing, data, maps, mobile, satellite-imagery'
    },
    {
      id: 18,
      name: 'Forest Watcher Mobile App',
      svg: '#shape-globe-mobile',
      content: 'This easy-to-use app enables anyone with limited Internet connectivity to find GFW alerts in their forests and upload observations like photos and other data from the field. The Jane Goodall Institute, in partnership with Global Forest Watch, Google, and TouchLab, is currently piloting this app in Uganda to improve local forest monitoring. The beta version is now live!.',
      href: 'mailto:gfw@wri.org',
      target: true,
      link_text: 'Contact us to become a beta tester',
      classname: 'btn green medium mobile-friendly',
      source: 'Jane Goodall Institute, Google, TouchLab, and World Resources Institute',
      tags: 'crowdsourcing, data, maps, mobile, satellite-imagery'
    },
    {
      id: 19,
      name: 'My Forest Atlas',
      svg: '#shape-my-forest-atlas',
      content: 'A tool for building your own online interactive map',
      link_text: 'Coming soon',
      classname: 'btn soon',
      source: 'World Resources Institute',
      tags: 'crowdsourcing, data, maps, mobile, satellite-imagery'
    },
    {
      id: 20,
      name: 'Logging Roads',
      svg: '#shape-logging-roads',
      content: 'View and help document the spread of logging roads across the Congo Basin region of Central Africa',
      href: 'http://loggingroads.org/',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Moabi',
      mobile_friendly: 'other',
      tags: 'crowdsourcing, maps, satellite imagery, Africa, data, Global Forest Watch, logging'
    },
    {
      id: 21,
      name: 'Water',
      svg: '#shape-water',
      content: 'View critical watershed information, understand type and severity of threats such as forest changes to watershed health, and screen for cost-effective, sustainable solutions.',
      link_text: 'Coming soon',
      classname: 'btn soon',
      source: 'World Resources Institute and Aqueduct',
      tags: 'data, global-forest-watch, maps'
    },
    {
      id: 22,
      name: 'Develop your own app',
      svg: '#shape-develop',
      content: 'Learn how to develop your own application with Global Forest Watch data.',
      href: '/getinvolved/develop-your-own-app',
      link_text: 'Read more',
      classname: 'btn gray medium',
    },

  ]

// Add a card for "My Forest Atlas" (coming soon).  The source is WRI and the descriptive text should say: A tool for building your own online interactive map (text will probably change but this is good enough for now!).  See attached image for preliminary design.

  function tagged(arr) {
    return _.map(arr, function(app){
      if (app.tags) {
        app.tags = _.map(app.tags.split(","), function(t){
          return t.trim();
        });
      }
      return app;
    })
  }

  return tagged(applicationsHelper);

});

<commit_msg>Explore: my forest atlas removed<commit_after>define([
  'underscore'
], function(_) {

  // APP INFO
  // name: name of the app
  // svg: svg-id linked to svg icon definitions
  // content: content that will be shown when you click one app
  // source: the source of the app
  // tags: you should choose one of these => africa, asia, boreal-forests, commodities, crowdsourcing, data, fires, global-forest-watch, latin-america, maps, mining, mobile, palm-oil, satellite-imagery
  //       if you want more than once, please separate them by commas

  // LINK BUTTON
  // href: link to the app will be shown when you click one app
  // link_text: text that should appear inside the button
  // classname: classes that should have the link/button (mobile-friendly should prevent mobile users to leave GFW)
  // mobile_friendly: other => when you don't know if the app that is requested is mobile optimized. That should change the message
  // target: true if you need to open it in a new page

  var applicationsHelper = [
    {
      id: 1,
      name: 'GFW Interactive map',
      svg: '#shape-world',
      content: 'View and analyze data on the GFW Interactive Map.',
      href: '/map',
      link_text: 'Open map',
      classname: 'btn green medium',
      source: 'World Resources Institute',
      tags: 'data, fires, global-forest-watch, maps, mining, mobile, palm-oil, satellite-imagery'
    },
    {
      id: 2,
      name: 'Country profiles & rankings',
      svg: '#shape-country',
      content: 'View country-specific data, analyze forest change within a country or subnational jurisdiction, or view country rankings based on forest statistics.',
      href: '/countries',
      link_text: 'View countries',
      classname: 'btn green medium',
      source: 'World Resources Institute',
      tags: 'boreal-forests, data, global-forest-watch'
    },
    {
      id: 3,
      name: 'Open Data Portal',
      svg: '#shape-download',
      content: 'Browse, learn more about, and download the data displayed on Global Forest Watch.',
      href: 'http://data.globalforestwatch.org',
      link_text: 'Browse data',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'data, fires, global-forest-watch, maps, mining, palm-oil, satellite-imagery'
    },
    {
      id: 4,
      name: 'Fires',
      svg: '#shape-fire',
      content: 'Track forest fires and haze in the ASEAN region.',
      href: 'http://fires.globalforestwatch.org/',
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'asia, data, fires, global-forest-watch, maps, palm-oil, satellite-imagery'
    },
    {
      id: 5,
      name: 'Commodities',
      svg: '#shape-commodities',
      content: 'Identify deforestation risk in commodity supply chains.',
      href: 'http://commodities.globalforestwatch.org/',
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'asia, commodities, data, fires, global-forest-watch, maps, mining, palm-oil'
    },
    {
      id: 6,
      name: 'Climate',
      svg: '#shape-climate',
      content: 'Track carbon emissions and removals in forest landscapes.',
      href: 'http://climate.globalforestwatch.org/',
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute',
      tags: 'data, global-forest-watch, maps'
    },
    {
      id: 7,
      name: 'Global Forest Watch: Sumatra campaign on Tomnod',
      svg: '#shape-tomnod',
      content: 'Help Global Forest Watch Fires track illegal fires and preserve the health of people and forests in Southeast Asia.',
      href: 'http://www.tomnod.com/campaign/gfw2_2014/map/2qwx1oy6u',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Digital Globe',
      mobile_friendly: 'other',
      tags: 'asia, crowdsourcing, data, fires, maps, palm-oil, satellite-imagery'
    },
    {
      id: 8,
      name: 'Open Landscape Partnership Platform',
      svg: '#shape-landscape',
      content: 'View and analyze ultra-high-resolution satellite imagery (up to 50 centimeters) for select forest landscapes.',
      href: 'http://www.sustainablepalmoil.org/spott',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Transparent World',
      mobile_friendly: 'other',
      tags: 'crowdsourcing, data, maps, satellite-imagery'
    },
    {
      id: 9,
      name: 'Sustainable Palm Oil Transparency Toolkit (SPOTT)',
      svg: '#shape-spott',
      content: 'Assess oil palm growers on the information that they make publicly available about the sustainability of their operations.',
      href: 'http://www.sustainablepalmoil.org/spott',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Zoological Society of London',
      mobile_friendly: 'other',
      tags: 'asia, commodities, data, global-forest-watch, maps, palm-oil'
    },
    {
      id: 10,
      name: 'Monitoring of the Andean Amazon Project (MAAP)',
      svg: '#shape-aca',
      content: 'View information, maps and analysis from a new deforestation monitoring system for the Andean Amazon.',
      href: 'http://maaproject.org/en/',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Amazon Conservation Association',
      mobile_friendly: 'other',
      tags: 'data, latin-america, maps, mining, satellite imagery'
    },
    {
      id: 11,
      name: 'Cameroon Forest Atlas',
      svg: '#shape-CMR',
      content: 'View an interactive map with land-use data for Cameroon.',
      href: 'http://cmr.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Forest and Wildlife of Cameroon',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 12,
      name: 'Central African Republic Forest Atlas',
      svg: '#shape-CAF',
      content: 'View an interactive map with land-use data for the Central African Republic.',
      href: 'http://caf.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Water, Forests, Hunting, and Fishing of the Central African Republic',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps'
    },
    {
      id: 13,
      name: 'Republic of Congo Forest Atlas',
      svg: '#shape-COG',
      content: 'View an interactive map with land-use data for the Congo.',
      href: 'http://cog.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Economy and Sustainable Forestry Development of the Congo',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 14,
      name: 'Democratic Republic of Congo Forest Atlas',
      svg: '#shape-COD',
      content: 'View an interactive map with land-use data for the Democratic Republic of the Congo.',
      href: 'http://cod.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Environment, Nature Conservation, and Tourism of the Democratic Republic of the Congo',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 15,
      name: 'Equatorial Guinea Forest Atlas',
      svg: '#shape-GNQ',
      content: 'View an interactive map with land-use data for Equatorial Guinea.',
      href: 'http://gnq.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of Agriculture and Forestry of Equatorial Guinea',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps'
    },
    {
      id: 16,
      name: 'Gabon Forest Atlas',
      svg: '#shape-GAB',
      content: 'View an interactive map with land-use data for Gabon.',
      href: 'http://gab.forest-atlas.org',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Ministry of the Forest, Environment, and Protection of Natural Resources of Gabon',
      mobile_friendly: 'other',
      tags: 'africa, data, global-forest-watch, maps, mining'
    },
    {
      id: 17,
      name: 'Open Foris',
      svg: '#shape-open-foris',
      content: 'A set of free and open-source software tools that facilitates flexible and efficient data collection, analysis, and reporting.',
      href: 'http://www.openforis.org/',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'Forestry Department of the Food and Agriculture Organization of the United Nations',
      mobile_friendly: 'other',
      tags: 'crowdsourcing, data, maps, mobile, satellite-imagery'
    },
    {
      id: 18,
      name: 'Forest Watcher Mobile App',
      svg: '#shape-globe-mobile',
      content: 'This easy-to-use app enables anyone with limited Internet connectivity to find GFW alerts in their forests and upload observations like photos and other data from the field. The Jane Goodall Institute, in partnership with Global Forest Watch, Google, and TouchLab, is currently piloting this app in Uganda to improve local forest monitoring. The beta version is now live!.',
      href: 'mailto:gfw@wri.org',
      target: true,
      link_text: 'Contact us to become a beta tester',
      classname: 'btn green medium mobile-friendly',
      source: 'Jane Goodall Institute, Google, TouchLab, and World Resources Institute',
      tags: 'crowdsourcing, data, maps, mobile, satellite-imagery'
    },
    {
      id: 19,
      name: 'Logging Roads',
      svg: '#shape-logging-roads',
      content: 'View and help document the spread of logging roads across the Congo Basin region of Central Africa',
      href: 'http://loggingroads.org/',
      target: true,
      link_text: 'Launch App',
      classname: 'btn green medium mobile-friendly',
      source: 'World Resources Institute and Moabi',
      mobile_friendly: 'other',
      tags: 'crowdsourcing, maps, satellite imagery, Africa, data, Global Forest Watch, logging'
    },
    {
      id: 20,
      name: 'Water',
      svg: '#shape-water',
      content: 'View critical watershed information, understand type and severity of threats such as forest changes to watershed health, and screen for cost-effective, sustainable solutions.',
      link_text: 'Coming soon',
      classname: 'btn soon',
      source: 'World Resources Institute and Aqueduct',
      tags: 'data, global-forest-watch, maps'
    },
    {
      id: 21,
      name: 'Develop your own app',
      svg: '#shape-develop',
      content: 'Learn how to develop your own application with Global Forest Watch data.',
      href: '/getinvolved/develop-your-own-app',
      link_text: 'Read more',
      classname: 'btn gray medium',
    },

  ]

// Add a card for "My Forest Atlas" (coming soon).  The source is WRI and the descriptive text should say: A tool for building your own online interactive map (text will probably change but this is good enough for now!).  See attached image for preliminary design.

  function tagged(arr) {
    return _.map(arr, function(app){
      if (app.tags) {
        app.tags = _.map(app.tags.split(","), function(t){
          return t.trim();
        });
      }
      return app;
    })
  }

  return tagged(applicationsHelper);

});

<|endoftext|>


<commit_before>/*global chrome */
/*jslint browser: true, devel: true */

(function () {
    "use strict";

    var classNames = [
            "external_links",
            "links",
            "apps",
            "instagram",
            "group_share",
            "mem_link",
            "event_share",
            "wall_post_more",
            "likes",
            "comments"
        ],
        css = {
            groups: "[id^='feed_repost-'], [id^='feed_reposts_'] " +
                    "{ display: none; }",
            myGroups: "[id^='post-'].post_copy { display: none; }",
            groupsAndPeople: "[id^='feed_repost'] { display: none; }",

            filters: classNames.map(function (className) {
                return ".cffvk-" + className;
            }).join() + "{ display: none; }",

            show: function show(rule) {
                return rule.replace(/none/g, "block");
            }
        },
        settings = {};

    // The main function
    function execute(tabId) {
        var cssCode = "";

        if (settings.groups === "checked") {

            if (settings.people === "checked") {
                cssCode += css.groupsAndPeople;
            } else {
                cssCode += css.show(css.groupsAndPeople) + css.groups;
            }

            if (settings.mygroups === "checked") {
                cssCode += css.myGroups;
            } else {
                cssCode += css.show(css.myGroups);
            }

        } else {
            cssCode += css.show(css.groupsAndPeople + css.myGroups);
        }

        chrome.tabs.insertCSS(tabId, {code: cssCode});
        chrome.tabs.sendMessage(tabId, {
            action: "clean",
            settings: settings
        });
    }

    function setUpTheSettingsPage() {
        var checkboxes;

        function hideOrShowSomeCheckboxes() {
            var labels2and3 = [
                    document.getElementById("mygroups-label"),
                    document.getElementById("people-label")
                ],
                linksLabel = document.getElementById("links-label"),
                linksCheckbox = linksLabel.children[0],
                newSettings = {};

            // If the first checkbox (`groups`) is unchecked
            // then uncheck the second and the third, hide them,
            // and reset their settings in storage:
            labels2and3.forEach(function (label) {
                var checkbox = label.children[0];

                if (settings.groups === "checked") {
                    label.style.display = "block";

                    return;
                }

                label.style.display = "none";
                checkbox.checked = false;
                newSettings[checkbox.name] = "";
                settings[checkbox.name] = "";
            });

            // If the `external_links` checkbox is checked
            // then uncheck the `links` checkbox, hide it,
            // and reset its setting in storage:
            if (settings.external_links === "checked") {
                linksLabel.style.display = "none";
                linksCheckbox.checked = false;
                newSettings[linksCheckbox.name] = "";
                settings[linksCheckbox.name] = "";
            } else {
                linksLabel.style.display = "block";
            }

            if (Object.keys(newSettings).length > 0) {
                chrome.storage.sync.set(settings);
            }
        }

        // Catch clicks on checkboxes and remember the values ("checked"),
        // reapply the main function:
        function handleClick(event) {
            var name = event.target.name,
                value = event.target.value;

            settings[name] = settings[name] === value
                ? ""
                : value;

            chrome.storage.sync.set(settings, function () {
                hideOrShowSomeCheckboxes();
                chrome.tabs.query(
                    {
                        active: true,
                        currentWindow: true
                    },
                    function (tabs) {
                        execute(tabs[0].id);
                    }
                );
            });
        }

        if (document.settingsForm) {
            checkboxes = Array.prototype.slice.call(
                document.settingsForm.getElementsByTagName("input")
            );

            hideOrShowSomeCheckboxes();

            checkboxes.forEach(function (checkbox) {
                checkbox.addEventListener("click", handleClick);
                if (settings[checkbox.name] === "checked") {
                    checkbox.checked = true;
                }
            });
        }
    }

    // Launch the main function only on certain pages of VK:
    function checkForValidUrl(tabId, changeInfo, tab) {
        var url;

        if (changeInfo.status !== "loading") {
            return;
        }

        url = tab.url;

        if (url.indexOf("vk.com/feed") === -1) {
            return chrome.pageAction.hide(tabId);
        }

        if (/photos|videos|articles|likes|notifications|comments|updates|replies/
            .test(url)) {
            chrome.pageAction.hide(tabId);

            // Show all the divs that have been hidden, stop observing:
            chrome.tabs.insertCSS(tabId, {
                code: css.show(
                    css.groupsAndPeople + css.myGroups + css.filters
                )
            });

            return chrome.tabs.sendMessage(tabId, {
                action: "disable"
            });
        }

        if (!(/\/feed\?[wz]=/).test(url)) {

            // We have to get the settings on every page load
            // because `handleClick` works in a different context
            // (popup) and it doesn't update our `settings` variable
            chrome.storage.sync.get(function (loadedSettings) {
                settings = loadedSettings;
                chrome.tabs.executeScript(
                    tabId,
                    {file: "content-script.js"},
                    function () {
                        execute(tabId);
                    }
                );
            });

            chrome.pageAction.show(tabId);

            chrome.tabs.insertCSS(tabId, {code: css.filters});
        }
    }

    // Load settings. If there are none, set them to defaults
    // (check only the first checkbox):
    chrome.storage.sync.get(function (loadedSettings) {
        settings = loadedSettings;
        if (Object.keys(loadedSettings).length === 0) {
            settings = {groups: "checked"};
            chrome.storage.sync.set(settings);
        }
        setUpTheSettingsPage();
    });

    chrome.tabs.onUpdated.addListener(checkForValidUrl);
}());
<commit_msg>Move form existence check<commit_after>/*global chrome */
/*jslint browser: true, devel: true */

(function () {
    "use strict";

    var classNames = [
            "external_links",
            "links",
            "apps",
            "instagram",
            "group_share",
            "mem_link",
            "event_share",
            "wall_post_more",
            "likes",
            "comments"
        ],
        css = {
            groups: "[id^='feed_repost-'], [id^='feed_reposts_'] " +
                    "{ display: none; }",
            myGroups: "[id^='post-'].post_copy { display: none; }",
            groupsAndPeople: "[id^='feed_repost'] { display: none; }",

            filters: classNames.map(function (className) {
                return ".cffvk-" + className;
            }).join() + "{ display: none; }",

            show: function show(rule) {
                return rule.replace(/none/g, "block");
            }
        },
        settings = {};

    // The main function
    function execute(tabId) {
        var cssCode = "";

        if (settings.groups === "checked") {

            if (settings.people === "checked") {
                cssCode += css.groupsAndPeople;
            } else {
                cssCode += css.show(css.groupsAndPeople) + css.groups;
            }

            if (settings.mygroups === "checked") {
                cssCode += css.myGroups;
            } else {
                cssCode += css.show(css.myGroups);
            }

        } else {
            cssCode += css.show(css.groupsAndPeople + css.myGroups);
        }

        chrome.tabs.insertCSS(tabId, {code: cssCode});
        chrome.tabs.sendMessage(tabId, {
            action: "clean",
            settings: settings
        });
    }

    function setUpTheSettingsPage() {
        var checkboxes;

        function hideOrShowSomeCheckboxes() {
            var labels2and3 = [
                    document.getElementById("mygroups-label"),
                    document.getElementById("people-label")
                ],
                linksLabel = document.getElementById("links-label"),
                linksCheckbox = linksLabel.children[0],
                newSettings = {};

            // If the first checkbox (`groups`) is unchecked
            // then uncheck the second and the third, hide them,
            // and reset their settings in storage:
            labels2and3.forEach(function (label) {
                var checkbox = label.children[0];

                if (settings.groups === "checked") {
                    label.style.display = "block";

                    return;
                }

                label.style.display = "none";
                checkbox.checked = false;
                newSettings[checkbox.name] = "";
                settings[checkbox.name] = "";
            });

            // If the `external_links` checkbox is checked
            // then uncheck the `links` checkbox, hide it,
            // and reset its setting in storage:
            if (settings.external_links === "checked") {
                linksLabel.style.display = "none";
                linksCheckbox.checked = false;
                newSettings[linksCheckbox.name] = "";
                settings[linksCheckbox.name] = "";
            } else {
                linksLabel.style.display = "block";
            }

            if (Object.keys(newSettings).length > 0) {
                chrome.storage.sync.set(settings);
            }
        }

        // Catch clicks on checkboxes and remember the values ("checked"),
        // reapply the main function:
        function handleClick(event) {
            var name = event.target.name,
                value = event.target.value;

            settings[name] = settings[name] === value
                ? ""
                : value;

            chrome.storage.sync.set(settings, function () {
                hideOrShowSomeCheckboxes();
                chrome.tabs.query(
                    {
                        active: true,
                        currentWindow: true
                    },
                    function (tabs) {
                        execute(tabs[0].id);
                    }
                );
            });
        }

        checkboxes = Array.prototype.slice.call(
            document.settingsForm.getElementsByTagName("input")
        );

        hideOrShowSomeCheckboxes();

        checkboxes.forEach(function (checkbox) {
            checkbox.addEventListener("click", handleClick);
            if (settings[checkbox.name] === "checked") {
                checkbox.checked = true;
            }
        });
    }

    // Launch the main function only on certain pages of VK:
    function checkForValidUrl(tabId, changeInfo, tab) {
        var url;

        if (changeInfo.status !== "loading") {
            return;
        }

        url = tab.url;

        if (url.indexOf("vk.com/feed") === -1) {
            return chrome.pageAction.hide(tabId);
        }

        if (/photos|videos|articles|likes|notifications|comments|updates|replies/
            .test(url)) {
            chrome.pageAction.hide(tabId);

            // Show all the divs that have been hidden, stop observing:
            chrome.tabs.insertCSS(tabId, {
                code: css.show(
                    css.groupsAndPeople + css.myGroups + css.filters
                )
            });

            return chrome.tabs.sendMessage(tabId, {
                action: "disable"
            });
        }

        if (!(/\/feed\?[wz]=/).test(url)) {

            // We have to get the settings on every page load
            // because `handleClick` works in a different context
            // (popup) and it doesn't update our `settings` variable
            chrome.storage.sync.get(function (loadedSettings) {
                settings = loadedSettings;
                chrome.tabs.executeScript(
                    tabId,
                    {file: "content-script.js"},
                    function () {
                        execute(tabId);
                    }
                );
            });

            chrome.pageAction.show(tabId);

            chrome.tabs.insertCSS(tabId, {code: css.filters});
        }
    }

    // Load settings. If there are none, set them to defaults
    // (check only the first checkbox):
    chrome.storage.sync.get(function (loadedSettings) {
        settings = loadedSettings;
        if (Object.keys(loadedSettings).length === 0) {
            settings = {groups: "checked"};
            chrome.storage.sync.set(settings);
        }
        if (document.settingsForm) {
            setUpTheSettingsPage();
        }
    });

    chrome.tabs.onUpdated.addListener(checkForValidUrl);
}());
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/core/LayoutData",
	"sap/ui/layout/library"
], function(LayoutData) {
	"use strict";

	var mGridItemProperties = {
		gridColumnStart: "grid-column-start",
		gridColumnEnd: "grid-column-end",
		gridRowStart: "grid-row-start",
		gridRowEnd: "grid-row-end",
		gridColumn: "grid-column",
		gridRow: "grid-row"
	};

	/**
	 * Constructor for a new sap.ui.layout.cssgrid.GridItemLayoutData.
	 *
	 * @param {string} [sId] ID for the new element, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new element.
	 *
	 * @class
	 * Holds layout data for a grid item.
	 *
	 * @extends sap.ui.core.LayoutData
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.layout.cssgrid.GridItemLayoutData
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var GridItemLayoutData = LayoutData.extend("sap.ui.layout.cssgrid.GridItemLayoutData", { metadata: {
		library: "sap.ui.layout",
		properties: {

			/**
			 * Sets the value for the CSS display:grid item property grid-column-start
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-start}
			 */
			gridColumnStart: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-column-end
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-end}
			 */
			gridColumnEnd: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-row-start
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-start}
			 */
			gridRowStart: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-row-end
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-end}
			 */
			gridRowEnd: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-column
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column}
			 */
			gridColumn: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-row
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row}
			 */
			gridRow: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: ""}
		}
	}});

	/**
	 * Updates the display:grid styles of a single item
	 *
	 * @private
	 * @static
	 * @param {sap.ui.core.Control} oItem The item which styles have to be updated
	 */
	GridItemLayoutData._setItemStyles = function (oItem) {

		if (!oItem) {
			return;
		}

		var oLayoutData = GridItemLayoutData._getLayoutDataForControl(oItem),
			oElement = GridItemLayoutData._getElement(oItem),
			oProperties,
			sProp,
			sPropValue;

		if (!oElement) {
			return;
		}

		if (!oLayoutData) {
			GridItemLayoutData._removeItemStyles(oElement);
			return;
		}

		oProperties = oLayoutData.getMetadata().getProperties();

		for (sProp in mGridItemProperties) {
			if (oProperties[sProp]) {
				sPropValue = oLayoutData.getProperty(sProp);

				if (typeof sPropValue !== "undefined") {
					GridItemLayoutData._setItemStyle(oElement, mGridItemProperties[sProp], sPropValue);
				}
			}
		}
	};

	/**
	 * Return the DOM ref of the item or the item's wrapper
	 *
	 * @param {sap.ui.core.Control} oItem The item
	 */
	GridItemLayoutData._getElement = function (oItem) {
		var oItemDom = oItem.getDomRef();
		var oWrapper = oItemDom.parentNode;

		if (oWrapper && oWrapper.classList.contains("sapUiLayoutCSSGridItemWrapper")) {
			return oWrapper;
		}
		return oItemDom;
	};

	/**
	 * Remove all grid properties from the item
	 *
	 * @private
	 * @static
	 * @param {HTMLElement} oItemDom The Item DOM reference
	 */
	GridItemLayoutData._removeItemStyles = function (oItemDom) {
		for (var sProp in mGridItemProperties) {
			oItemDom.style.removeProperty(mGridItemProperties[sProp]);
		}
	};

	/**
	 * Sets a property on the DOM element
	 *
	 * @private
	 * @static
	 * @param {HTMLElement} oItemDom The item DOM reference
	 * @param {string} sProperty The name of the property to set
	 * @param {string} sValue The value of the property to set
	 */
	GridItemLayoutData._setItemStyle = function (oItemDom, sProperty, sValue) {
		if (sValue !== "0" && !sValue) {
			oItemDom.style.removeProperty(sProperty);
		} else {
			oItemDom.style.setProperty(sProperty, sValue);
		}
	};

	/**
	 * @private
	 * @static
	 * @param {sap.ui.core.Control} oControl The control to get the layoutData from
	 * @returns {sap.ui.layout.cssgrid.GridItemLayoutData|undefined} The layoutData used by the grid item
	 */
	GridItemLayoutData._getLayoutDataForControl = function (oControl) {
		var oLayoutData,
			aLayoutData,
			oInnerLayoutData;

		if (!oControl) {
			return undefined;
		}

		oLayoutData = oControl.getLayoutData();

		if (!oLayoutData) {
			return undefined;
		}

		if (oLayoutData.isA("sap.ui.layout.cssgrid.GridItemLayoutData")) {
			return oLayoutData;
		}

		if (oLayoutData.isA("sap.ui.core.VariantLayoutData")) {
			aLayoutData = oLayoutData.getMultipleLayoutData();
			for (var i = 0; i < aLayoutData.length; i++) {
				oInnerLayoutData = aLayoutData[i];
				if (oInnerLayoutData.isA("sap.ui.layout.cssgrid.GridItemLayoutData")) {
					return oInnerLayoutData;
				}
			}
		}
	};

	return GridItemLayoutData;
});<commit_msg>[FIX] Fix in CSSGrid layout for use in bindings<commit_after>/*!
 * ${copyright}
 */

sap.ui.define([
	"sap/ui/core/LayoutData",
	"sap/ui/layout/library"
], function(LayoutData) {
	"use strict";

	var mGridItemProperties = {
		gridColumnStart: "grid-column-start",
		gridColumnEnd: "grid-column-end",
		gridRowStart: "grid-row-start",
		gridRowEnd: "grid-row-end",
		gridColumn: "grid-column",
		gridRow: "grid-row"
	};

	/**
	 * Constructor for a new sap.ui.layout.cssgrid.GridItemLayoutData.
	 *
	 * @param {string} [sId] ID for the new element, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new element.
	 *
	 * @class
	 * Holds layout data for a grid item.
	 *
	 * @extends sap.ui.core.LayoutData
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.layout.cssgrid.GridItemLayoutData
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var GridItemLayoutData = LayoutData.extend("sap.ui.layout.cssgrid.GridItemLayoutData", { metadata: {
		library: "sap.ui.layout",
		properties: {

			/**
			 * Sets the value for the CSS display:grid item property grid-column-start
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-start}
			 */
			gridColumnStart: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-column-end
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-end}
			 */
			gridColumnEnd: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-row-start
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-start}
			 */
			gridRowStart: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-row-end
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-end}
			 */
			gridRowEnd: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-column
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column}
			 */
			gridColumn: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: "" },

			/**
			 * Sets the value for the CSS display:grid item property grid-row
			 * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row}
			 */
			gridRow: { type: "sap.ui.layout.cssgrid.CSSGridLine", defaultValue: ""}
		}
	}});

	/**
	 * Updates the display:grid styles of a single item
	 *
	 * @private
	 * @static
	 * @param {sap.ui.core.Control} oItem The item which styles have to be updated
	 */
	GridItemLayoutData._setItemStyles = function (oItem) {

		if (!oItem) {
			return;
		}

		var oLayoutData = GridItemLayoutData._getLayoutDataForControl(oItem),
			oElement = GridItemLayoutData._getElement(oItem),
			oProperties,
			sProp,
			sPropValue;

		if (!oElement) {
			return;
		}

		if (!oLayoutData) {
			GridItemLayoutData._removeItemStyles(oElement);
			return;
		}

		oProperties = oLayoutData.getMetadata().getProperties();

		for (sProp in mGridItemProperties) {
			if (oProperties[sProp]) {
				sPropValue = oLayoutData.getProperty(sProp);

				if (typeof sPropValue !== "undefined") {
					GridItemLayoutData._setItemStyle(oElement, mGridItemProperties[sProp], sPropValue);
				}
			}
		}
	};

	/**
	 * Return the DOM ref of the item or the item's wrapper
	 *
	 * @param {sap.ui.core.Control} oItem The item
	 */
	GridItemLayoutData._getElement = function (oItem) {
		var oItemDom = oItem.getDomRef();

		if (!oItemDom) {
			return undefined;
		}

		var oWrapper = oItemDom.parentNode;

		if (oWrapper && oWrapper.classList.contains("sapUiLayoutCSSGridItemWrapper")) {
			return oWrapper;
		}
		return oItemDom;
	};

	/**
	 * Remove all grid properties from the item
	 *
	 * @private
	 * @static
	 * @param {HTMLElement} oItemDom The Item DOM reference
	 */
	GridItemLayoutData._removeItemStyles = function (oItemDom) {
		for (var sProp in mGridItemProperties) {
			oItemDom.style.removeProperty(mGridItemProperties[sProp]);
		}
	};

	/**
	 * Sets a property on the DOM element
	 *
	 * @private
	 * @static
	 * @param {HTMLElement} oItemDom The item DOM reference
	 * @param {string} sProperty The name of the property to set
	 * @param {string} sValue The value of the property to set
	 */
	GridItemLayoutData._setItemStyle = function (oItemDom, sProperty, sValue) {
		if (sValue !== "0" && !sValue) {
			oItemDom.style.removeProperty(sProperty);
		} else {
			oItemDom.style.setProperty(sProperty, sValue);
		}
	};

	/**
	 * @private
	 * @static
	 * @param {sap.ui.core.Control} oControl The control to get the layoutData from
	 * @returns {sap.ui.layout.cssgrid.GridItemLayoutData|undefined} The layoutData used by the grid item
	 */
	GridItemLayoutData._getLayoutDataForControl = function (oControl) {
		var oLayoutData,
			aLayoutData,
			oInnerLayoutData;

		if (!oControl) {
			return undefined;
		}

		oLayoutData = oControl.getLayoutData();

		if (!oLayoutData) {
			return undefined;
		}

		if (oLayoutData.isA("sap.ui.layout.cssgrid.GridItemLayoutData")) {
			return oLayoutData;
		}

		if (oLayoutData.isA("sap.ui.core.VariantLayoutData")) {
			aLayoutData = oLayoutData.getMultipleLayoutData();
			for (var i = 0; i < aLayoutData.length; i++) {
				oInnerLayoutData = aLayoutData[i];
				if (oInnerLayoutData.isA("sap.ui.layout.cssgrid.GridItemLayoutData")) {
					return oInnerLayoutData;
				}
			}
		}
	};

	return GridItemLayoutData;
});<|endoftext|>


<commit_before>
		postscribe('#job-board-target', '
Job Board


<commit_before>/*
 * Pattern matching the prefix of at least one stripped query string
 * parameter. We'll search the query string portion of the URL for this
 * pattern to determine if there's any stripping work to do.
 */
const searchPattern = new RegExp('utm_|stm_|clid|_hs|icid|igshid|mc_|mkt_tok|yclid|_openstat|wicked|otc|oly_|rb_clickid|soc_|cvid|oicd', 'i');

/*
 * Pattern matching the query string parameters (key=value) that will be
 * stripped from the final URL.
 */
const replacePattern = new RegExp(
    '([?&]' +
    '(icid|mkt_tok|(g|fb)clid|igshid|_hs(enc|mi)|mc_[ce]id|(utm|stm)_(source|medium|term|campaign|content|cid|reader|referrer|name|social|social-type)|rb_clickid|yclid|_openstat|wickedid|otc|oly_(anon|enc)_id|soc_(src|trk)|cvid|oicd)' +
    '=[^&#]*)',
    'ig');

chrome.webRequest.onBeforeRequest.addListener((details) => {
    const url = details.url;
    const queryStringIndex = url.indexOf('?');
    if (url.search(searchPattern) > queryStringIndex) {
        let stripped = url.replace(replacePattern, '');
        if (stripped.charAt(queryStringIndex) === '&') {
            stripped = `${stripped.substr(0, queryStringIndex)}?${stripped.substr(queryStringIndex + 1)}`;
        }
        if (stripped != url) {
            return {redirectUrl: stripped};
        }
    }
},
{urls: ['https://*/*?*', 'http://*/*?*'], types: ['main_frame']}, ['blocking']);
<commit_msg>Also remove 'utm_id'<commit_after>/*
 * Pattern matching the prefix of at least one stripped query string
 * parameter. We'll search the query string portion of the URL for this
 * pattern to determine if there's any stripping work to do.
 */
const searchPattern = new RegExp('utm_|stm_|clid|_hs|icid|igshid|mc_|mkt_tok|yclid|_openstat|wicked|otc|oly_|rb_clickid|soc_|cvid|oicd', 'i');

/*
 * Pattern matching the query string parameters (key=value) that will be
 * stripped from the final URL.
 */
const replacePattern = new RegExp(
    '([?&]' +
    '(icid|mkt_tok|(g|fb)clid|igshid|_hs(enc|mi)|mc_[ce]id|(utm|stm)_(id|source|medium|term|campaign|content|cid|reader|referrer|name|social|social-type)|rb_clickid|yclid|_openstat|wickedid|otc|oly_(anon|enc)_id|soc_(src|trk)|cvid|oicd)' +
    '=[^&#]*)',
    'ig');

chrome.webRequest.onBeforeRequest.addListener((details) => {
    const url = details.url;
    const queryStringIndex = url.indexOf('?');
    if (url.search(searchPattern) > queryStringIndex) {
        let stripped = url.replace(replacePattern, '');
        if (stripped.charAt(queryStringIndex) === '&') {
            stripped = `${stripped.substr(0, queryStringIndex)}?${stripped.substr(queryStringIndex + 1)}`;
        }
        if (stripped != url) {
            return {redirectUrl: stripped};
        }
    }
},
{urls: ['https://*/*?*', 'http://*/*?*'], types: ['main_frame']}, ['blocking']);
<|endoftext|>


<commit_before>/*!

Name: Reading Time
Dependencies: jQuery
Author: Michael Lynch
Author URL: http://michaelynch.com
Date Created: August 14, 2013
Date Updated: January 24, 2014
Licensed under the MIT license

*/
(function(e){e.fn.readingTime=function(t){if(!this.length){return this}var n={readingTimeTarget:".eta",wordCountTarget:null,wordsPerMinute:270,round:true,lang:"en",lessThanAMinuteString:"",prependTimeString:"",prependWordString:"",remotePath:null,remoteTarget:null};var r=this;var i=e(this);r.settings=e.extend({},n,t);var s=r.settings.readingTimeTarget;var o=r.settings.wordCountTarget;var u=r.settings.wordsPerMinute;var a=r.settings.round;var f=r.settings.lang;var l=r.settings.lessThanAMinuteString;var c=r.settings.prependTimeString;var h=r.settings.prependWordString;var p=r.settings.remotePath;var d=r.settings.remoteTarget;if(f=="fr"){var v=l||"Moins d'une minute";var m="min"}else if(f=="de"){var v=l||"Weniger als eine Minute";var m="min"}else if(f=="es"){var v=l||"Menos de un minuto";var m="min"}else if(f=="nl"){var v=l||"Minder dan een minuut";var m="min"}else{var v=l||"Less than a minute";var m="min"}var g=function(e){var t=e.split(" ").length;var n=u/60;var r=t/n;var f=Math.round(r/60);var l=Math.round(r-f*60);if(a===true){if(f>0){i.find(s).text(c+f+" "+m)}else{i.find(s).text(c+v)}}else{var p=f+":"+l;i.find(s).text(c+p)}if(o!==""&&o!==undefined){i.find(o).text(h+t)}};i.each(function(){if(p!=null&&d!=null){e.get(p,function(t){g(e("<div>").html(t).find(d).text())})}else{g(i.text())}})}})(jQuery)<commit_msg>plugin fix<commit_after>/*!

Name: Reading Time
Dependencies: jQuery
Author: Michael Lynch
Author URL: http://michaelynch.com
Date Created: August 14, 2013
Date Updated: January 24, 2014
Licensed under the MIT license

*/
(function(e){e.fn.readingTime=function(t){if(!this.length){return this}var n={readingTimeTarget:".eta",wordCountTarget:null,wordsPerMinute:270,round:true,lang:"en",lessThanAMinuteString:"",prependTimeString:"",prependWordString:"",remotePath:null,remoteTarget:null};var r=this;var i=e(this);r.settings=e.extend({},n,t);var s=r.settings.readingTimeTarget;var o=r.settings.wordCountTarget;var u=r.settings.wordsPerMinute;var a=r.settings.round;var f=r.settings.lang;var l=r.settings.lessThanAMinuteString;var c=r.settings.prependTimeString;var h=r.settings.prependWordString;var p=r.settings.remotePath;var d=r.settings.remoteTarget;if(f=="fr"){var v=l||"Moins d'une minute";var m="min"}else if(f=="de"){var v=l||"Weniger als eine Minute";var m="min"}else if(f=="es"){var v=l||"Menos de un minuto";var m="min"}else if(f=="nl"){var v=l||"Minder dan een minuut";var m="min"}else{var v=l||"Меньше минуты";var m="мин"}var g=function(e){var t=e.split(" ").length;var n=u/60;var r=t/n;var f=Math.round(r/60);var l=Math.round(r-f*60);if(a===true){if(f>0){i.find(s).text(c+f+" "+m)}else{i.find(s).text(c+v)}}else{var p=f+":"+l;i.find(s).text(c+p)}if(o!==""&&o!==undefined){i.find(o).text(h+t)}};i.each(function(){if(p!=null&&d!=null){e.get(p,function(t){g(e("<div>").html(t).find(d).text())})}else{g(i.text())}})}})(jQuery)<|endoftext|>


<commit_before>applicantControllers.controller('ApplicantCtrl', ['$scope', '$location', 'Applicant', 'Label', 'Upload', '$window', 'ngToast', '$timeout',
  function($scope, $location, Applicant, Label, Upload, $window, ngToast, $timeout) {

    //default dropdown menu to 'new' on page load
    $scope.selection = "new";
    $scope.sort = "score";
    $scope.sortOrder = "desc";

    //query should start off at index 0, displaying first item
    $scope.index = 0;
    //displaying 25 applicants at a time
    $scope.pageSize = 25;
    $scope.loadingData = false;
    $scope.hasData = true;

    //sorting table by column code
    $scope.propertyName = null;
    $scope.reverse = false;
    $scope.searchText = "";

    //default query
    $scope.applicants = Applicant.query({
      from: $scope.index,
      size: $scope.pageSize,
      sort: $scope.sort,
      order: $scope.sortOrder
    });

    /**
     * sort by property name. function is called when column is clicked
     *
     * @param type- type to sort by (i.e. Score)
     */

    $scope.sortColumn = function(type) {
      $scope.index = 0;
      $scope.hasData = true;
      $scope.sort = type;

      if (type == "score") {
        $scope.sortBool = false;
      } else {
        $scope.sortBool = true;
      }

      if ($scope.sortOrder == "asc") {
        $scope.sortOrder = "desc";
        $scope.reverse = false;
      }

      else if ($scope.sortOrder == "desc") {
        $scope.sortOrder = "asc";
        $scope.reverse = true;
      }

      $scope.applicants = Applicant.query({
        type: $scope.selection,
        from: $scope.index,
        size: $scope.pageSize,
        sort: $scope.sort,
        order: $scope.sortOrder
      });
    }

    /**
     * change queries when new type is selected from the dropdown menu
     *
     * @param type- select box value
     */
    $scope.showSelectValue = function(type) {
      $scope.searchText = "";
      $scope.index = 0;
      $scope.hasData = true;
      $scope.selection = type;
      $scope.applicants = Applicant.query({
        type: type,
        from: $scope.index,
        size: $scope.pageSize,
        sort: $scope.sort,
        order: $scope.sortOrder
      });
    };

    /**
     * adds to query if there is more data, else change hasData to false
     *
     * @param result- rest of the query
     */
    $scope.dataLoaded = function(result) {
      if (result.length > 0) {
        $scope.applicants = $scope.applicants.concat(result);
      } else {
        $scope.hasData = false;
        $scope.index = 0;
      }

      $scope.loadingData = false;
    };

    /**
     * check if there is more data to load from the query, for infinite scroll
     *
     */
    $scope.nextPage = function() {
      if ($scope.hasData) {
        $scope.loadingData = true;
        $scope.index += $scope.pageSize;

        Applicant.query({
          query: $scope.searchText,
          type: $scope.selection,
          from: $scope.index,
          size: $scope.pageSize,
          order: $scope.sortOrder,
          sort: $scope.sort
        }, $scope.dataLoaded);
      };
    }

    // Only enable if the document has a long scroll bar
    // Note the window height + offset
    $('#top-link-block').removeClass('hidden').affix({
      offset: {
        top: 100
      }
    });

    /**
     * function that is called when action button is clicked, i.e. Favorite, Archive, Review
     *
     * @param id- id number of the applicant
     * @param type- type of the applicant
     * @param applicant- applicant object itself, passed in to avoid wrong indexing
     */
    $scope.mark = function(id, type, applicant) {
      var label = new Label({
        'id': id,
        'type': type
      });
      label.$save().then(function() {
        $scope.applicants.splice($scope.applicants.indexOf(applicant), 1);
      });
    }

    /**
     * function that is called when applicant is placed back in 'New
     *
     * @param id- id number of the applicant
     * @param applicant- applicant object itself, passed in to avoid wrong indexing
     */
    $scope.remove = function(id, applicant) {
      Label.delete({
        'id': id
      }).$promise.then(function() {
        $scope.applicants.splice($scope.applicants.indexOf(applicant), 1);
      });
    }

    /**
     * change toast CSS to show the message
     * after about three seconds, hide the toast
     *
     * @param type- type of toast to show
     *
     */
    $scope.showToast = function(type) {
      if (type == 'Favorite') {
        ngToast.create("Applicant added to Favorites");
      }

      else if (type == 'Review') {
        ngToast.create({
          className: 'warning',
          content: 'Applicant added to Review'
        });

      }

      else if (type == 'Archive') {
        ngToast.create({
          className: 'danger',
          content: 'Applicant added to Archive'
        });

      }

      else {
        ngToast.create({
          className: 'info',
          content: 'Applicant sent back to home page'
        });

      }
    }

    /**
     * return document (image or PDF) from a link
     *
     * @param id- id of applicant
     * @param type- type of document either an image or a PDF
     *
     */

    $scope.getLink = function(id, type) {
      return "service/attachments?id=" + id + "&type=" + type;
    }

    /**
     * return query based on text that was input in search bar
     *
     * @param searchText- text that was input in search bar
     *
     */
    $scope.search = function(searchText) {
      $scope.index = 0;
      $scope.searchText = searchText;

      $scope.applicants = Applicant.query({
        query: $scope.searchText,
        from: $scope.index,
        size: $scope.pageSize
      });
    }

    /**
     * Converts user uploaded files to base64 strings and indexes them
     *
     */
    $scope.upload = function() {
      var files = document.querySelector('input[type=file]').files;
      for(var i = 0; i < files.length; i++) {
        (function(file) {
          if(file.type === 'application/pdf') {
            var reader = new FileReader();

            reader.addEventListener("load", function () {
              var temp = reader.result;
              var base64string = temp.substring(28);
              console.log(base64string);
              console.log(file.type);

              var upload = new Upload({
                'type': 'upload',
                'base64string': base64string
              });

              upload.$save();
            }, false);

            if(file)
              reader.readAsDataURL(file);
          }
        })(files[i]);
      }
    }

    //scroll code
    $(function() {
      var lastScrollTop = 0,
        delta = 5;
      $(window).scroll(function(event) {
        var st = $(this).scrollTop();

        if (Math.abs(lastScrollTop - st) <= delta)
          return;

        //if scrolling up, hide the footer
        if (st <= lastScrollTop) {;
          angular.element("#footer").hide();
        }

        lastScrollTop = st;
      });
    });

    //if at bottom of window, show footer
    $(window).scroll(function() {
      if ($(window).scrollTop() + $(window).height() == $(document).height()) {
        angular.element("#footer").show();
      } else {
        angular.element("#footer").hide();
      }
    });
  }
]);<commit_msg>added word doc filter to upload<commit_after>applicantControllers.controller('ApplicantCtrl', ['$scope', '$location', 'Applicant', 'Label', 'Upload', '$window', 'ngToast', '$timeout',
  function($scope, $location, Applicant, Label, Upload, $window, ngToast, $timeout) {

    //default dropdown menu to 'new' on page load
    $scope.selection = "new";
    $scope.sort = "score";
    $scope.sortOrder = "desc";

    //query should start off at index 0, displaying first item
    $scope.index = 0;
    //displaying 25 applicants at a time
    $scope.pageSize = 25;
    $scope.loadingData = false;
    $scope.hasData = true;

    //sorting table by column code
    $scope.propertyName = null;
    $scope.reverse = false;
    $scope.searchText = "";

    //default query
    $scope.applicants = Applicant.query({
      from: $scope.index,
      size: $scope.pageSize,
      sort: $scope.sort,
      order: $scope.sortOrder
    });

    /**
     * sort by property name. function is called when column is clicked
     *
     * @param type- type to sort by (i.e. Score)
     */

    $scope.sortColumn = function(type) {
      $scope.index = 0;
      $scope.hasData = true;
      $scope.sort = type;

      if (type == "score") {
        $scope.sortBool = false;
      } else {
        $scope.sortBool = true;
      }

      if ($scope.sortOrder == "asc") {
        $scope.sortOrder = "desc";
        $scope.reverse = false;
      }

      else if ($scope.sortOrder == "desc") {
        $scope.sortOrder = "asc";
        $scope.reverse = true;
      }

      $scope.applicants = Applicant.query({
        type: $scope.selection,
        from: $scope.index,
        size: $scope.pageSize,
        sort: $scope.sort,
        order: $scope.sortOrder
      });
    }

    /**
     * change queries when new type is selected from the dropdown menu
     *
     * @param type- select box value
     */
    $scope.showSelectValue = function(type) {
      $scope.searchText = "";
      $scope.index = 0;
      $scope.hasData = true;
      $scope.selection = type;
      $scope.applicants = Applicant.query({
        type: type,
        from: $scope.index,
        size: $scope.pageSize,
        sort: $scope.sort,
        order: $scope.sortOrder
      });
    };

    /**
     * adds to query if there is more data, else change hasData to false
     *
     * @param result- rest of the query
     */
    $scope.dataLoaded = function(result) {
      if (result.length > 0) {
        $scope.applicants = $scope.applicants.concat(result);
      } else {
        $scope.hasData = false;
        $scope.index = 0;
      }

      $scope.loadingData = false;
    };

    /**
     * check if there is more data to load from the query, for infinite scroll
     *
     */
    $scope.nextPage = function() {
      if ($scope.hasData) {
        $scope.loadingData = true;
        $scope.index += $scope.pageSize;

        Applicant.query({
          query: $scope.searchText,
          type: $scope.selection,
          from: $scope.index,
          size: $scope.pageSize,
          order: $scope.sortOrder,
          sort: $scope.sort
        }, $scope.dataLoaded);
      };
    }

    // Only enable if the document has a long scroll bar
    // Note the window height + offset
    $('#top-link-block').removeClass('hidden').affix({
      offset: {
        top: 100
      }
    });

    /**
     * function that is called when action button is clicked, i.e. Favorite, Archive, Review
     *
     * @param id- id number of the applicant
     * @param type- type of the applicant
     * @param applicant- applicant object itself, passed in to avoid wrong indexing
     */
    $scope.mark = function(id, type, applicant) {
      var label = new Label({
        'id': id,
        'type': type
      });
      label.$save().then(function() {
        $scope.applicants.splice($scope.applicants.indexOf(applicant), 1);
      });
    }

    /**
     * function that is called when applicant is placed back in 'New
     *
     * @param id- id number of the applicant
     * @param applicant- applicant object itself, passed in to avoid wrong indexing
     */
    $scope.remove = function(id, applicant) {
      Label.delete({
        'id': id
      }).$promise.then(function() {
        $scope.applicants.splice($scope.applicants.indexOf(applicant), 1);
      });
    }

    /**
     * change toast CSS to show the message
     * after about three seconds, hide the toast
     *
     * @param type- type of toast to show
     *
     */
    $scope.showToast = function(type) {
      if (type == 'Favorite') {
        ngToast.create("Applicant added to Favorites");
      }

      else if (type == 'Review') {
        ngToast.create({
          className: 'warning',
          content: 'Applicant added to Review'
        });

      }

      else if (type == 'Archive') {
        ngToast.create({
          className: 'danger',
          content: 'Applicant added to Archive'
        });

      }

      else {
        ngToast.create({
          className: 'info',
          content: 'Applicant sent back to home page'
        });

      }
    }

    /**
     * return document (image or PDF) from a link
     *
     * @param id- id of applicant
     * @param type- type of document either an image or a PDF
     *
     */

    $scope.getLink = function(id, type) {
      return "service/attachments?id=" + id + "&type=" + type;
    }

    /**
     * return query based on text that was input in search bar
     *
     * @param searchText- text that was input in search bar
     *
     */
    $scope.search = function(searchText) {
      $scope.index = 0;
      $scope.searchText = searchText;

      $scope.applicants = Applicant.query({
        query: $scope.searchText,
        from: $scope.index,
        size: $scope.pageSize
      });
    }

    /**
     * Converts user uploaded files to base64 strings and indexes them
     *
     */
    $scope.upload = function() {
      var files = document.querySelector('input[type=file]').files;
      for(var i = 0; i < files.length; i++) {
        (function(file) {
          if(file.type === 'application/pdf' || file.type === 'application/doc') {
            var reader = new FileReader();

            reader.addEventListener("load", function () {
              var temp = reader.result;
              var base64string = temp.substring(28);
              console.log(base64string);
              console.log(file.type);

              var upload = new Upload({
                'type': 'upload',
                'base64string': base64string
              });

              upload.$save();
            }, false);

            if(file)
              reader.readAsDataURL(file);
          }
        })(files[i]);
      }
    }

    //scroll code
    $(function() {
      var lastScrollTop = 0,
        delta = 5;
      $(window).scroll(function(event) {
        var st = $(this).scrollTop();

        if (Math.abs(lastScrollTop - st) <= delta)
          return;

        //if scrolling up, hide the footer
        if (st <= lastScrollTop) {;
          angular.element("#footer").hide();
        }

        lastScrollTop = st;
      });
    });

    //if at bottom of window, show footer
    $(window).scroll(function() {
      if ($(window).scrollTop() + $(window).height() == $(document).height()) {
        angular.element("#footer").show();
      } else {
        angular.element("#footer").hide();
      }
    });
  }
]);<|endoftext|>


<commit_before>(function($){

	$.fn.timer = function(options){

		var timer_obj = this;

		var starttime,
			endtime,
			timertimeout,
			timerinterval;

		var output,
			output_sec,
			output_min;

		this.duration = 0;

		set(0);

		this.start = start;
		function start(){
			if( !starttime ){
				starttime = new Date().getTime();
				output_sec = 0;
				output_min = 0;
				timerinterval = setInterval( function(){
					increase();
				}, 1000);
			} else {
				var diff = this.duration;
				while( diff > 1 ){
					diff--;
				}
				diff = (1 - diff) * 1000;
				timertimeout = setTimeout(function(){
					increase();
					timerinterval = setInterval( function(){
						increase();
					}, 1000);
				}, diff);
			}

			function increase(){
				output_sec++;
				if( output_sec >= 60 ){
					output_min++;
					output_sec = 0;
				}
				output = ('00' + output_min).substr(-2) + ':' + ('00' + output_sec).substr(-2);
				timer_obj.text(output);
			}
		}

		this.stop = stop;
		function stop(){
			endtime = new Date().getTime();
			clearTimeout(timertimeout);
			clearInterval(timerinterval);
			this.duration = ( endtime - starttime ) / 1000;
			clear();
		}

		this.pause = pause
		function pause(){
			endtime = new Date().getTime();
			clearTimeout(timertimeout);
			clearInterval(timerinterval);
			this.duration = ( endtime - starttime ) / 1000;
		}

		this.clear = clear
		function clear(){
			starttime = null;
			endtime = null;
		}

		this.set = set;
		function set( seconds ){
			clear();
			this.duration = seconds;
			endtime =  new Date().getTime();
			starttime = endtime - ( seconds *  1000 );
			output_sec = Math.round( parseFloat(seconds) );
			output_min = 0;
			while( output_sec > 60 ){
				output_sec -= 60;
				output_min++;
			}
			output = ('00' + output_min).substr(-2) + ':' + ('00' + output_sec).substr(-2);
			timer_obj.text(output);
		}

		return this;

	}

})( jQuery );<commit_msg>UPD timer plugin for demo<commit_after>(function($){

	$.fn.timer = function(options){

		var timer_obj = this;

		var starttime,
			endtime,
			timertimeout,
			timerinterval;

		var output,
			output_sec,
			output_min;

		this.duration = 0;

		set(0);

		this.start = start;
		function start(){
			if( !starttime ){
				starttime = new Date().getTime();
				set(0);
				output_sec = 0;
				output_min = 0;
				timerinterval = setInterval( function(){
					increase();
				}, 1000);
			} else {
				var diff = this.duration;
				while( diff > 1 ){
					diff--;
				}
				diff = (1 - diff) * 1000;
				timertimeout = setTimeout(function(){
					increase();
					timerinterval = setInterval( function(){
						increase();
					}, 1000);
				}, diff);
			}

			function increase(){
				output_sec++;
				if( output_sec >= 60 ){
					output_min++;
					output_sec = 0;
				}
				output = ('00' + output_min).substr(-2) + ':' + ('00' + output_sec).substr(-2);
				timer_obj.text(output);
			}
		}

		this.stop = stop;
		function stop(){
			endtime = new Date().getTime();
			this.duration = ( endtime - starttime ) / 1000;
			clearTimeout(timertimeout);
			clearInterval(timerinterval);
			clear();
		}

		this.pause = pause
		function pause(){
			endtime = new Date().getTime();
			clearTimeout(timertimeout);
			clearInterval(timerinterval);
			this.duration = ( endtime - starttime ) / 1000;
		}

		this.clear = clear
		function clear(){
			starttime = null;
			endtime = null;
			output = '';
			output_sec = 0;
			output_min = 0;
		}

		this.set = set;
		function set( seconds ){
			clear();
			this.duration = seconds;
			endtime =  new Date().getTime();
			starttime = endtime - ( seconds *  1000 );
			output_sec = Math.floor( parseFloat(seconds) );
			output_min = 0;
			while( output_sec > 60 ){
				output_sec -= 60;
				output_min++;
			}
			output = ('00' + output_min).substr(-2) + ':' + ('00' + output_sec).substr(-2);
			timer_obj.text(output);
		}

		return this;

	}

})( jQuery );<|endoftext|>