/**
  * Get all of the "standard" job types.
  * This provides information such as whether the job type is failable or not.
  * In the future, all of this should be moved into individual job definitions
  * particularly with {@code openclerk/jobs}, e.g. {@link FailableJob}
  */
 static function getStandardJobs()
 {
     $result = array();
     // address jobs are now named in common patterns
     // make sure to add the _block job below too if necessary
     $address_jobs = array();
     foreach (get_address_currencies() as $cur) {
         $address_jobs[] = array('table' => 'addresses', 'type' => 'address_' . $cur, 'query' => " AND currency='{$cur}'");
     }
     // premium address balance jobs needs to run much more frequently, but only for the system user (#412)
     foreach (get_address_currencies() as $cur) {
         $address_jobs[] = array('table' => 'addresses', 'type' => 'address_' . $cur, 'query' => " AND currency='{$cur}' AND user_id='" . get_site_config('system_user_id') . "'", 'hours' => get_site_config('refresh_queue_hours_system'));
     }
     // account jobs are now named in common patterns
     $account_jobs = array();
     foreach (Accounts::getKeys() as $exchange) {
         if (!in_array($exchange, \DiscoveredComponents\Accounts::getDisabled())) {
             $account_jobs[] = array('table' => 'accounts_' . $exchange, 'type' => 'account_' . $exchange, 'failure' => true);
         }
     }
     // standard jobs involve an 'id' from a table and a 'user_id' from the same table (unless 'user_id' is set)
     // the table needs 'last_queue' unless 'always' is specified (in which case, it will always happen)
     // if no 'user_id' is specified, then the user will also be checked for disable status
     $standard_jobs = array_merge($address_jobs, $account_jobs, array(array('table' => 'accounts_generic', 'type' => 'generic', 'failure' => true), array('table' => 'accounts_cryptostocks', 'type' => 'cryptostocks', 'failure' => true), array('table' => 'securities_cryptostocks', 'type' => 'securities_cryptostocks', 'user_id' => get_site_config('system_user_id'), 'failure' => true), array('table' => 'accounts_havelock', 'type' => 'havelock', 'failure' => true), array('table' => 'securities_havelock', 'type' => 'securities_havelock', 'user_id' => get_site_config('system_user_id'), 'failure' => true), array('table' => 'securities_cryptotrade', 'type' => 'securities_crypto-trade', 'user_id' => get_site_config('system_user_id'), 'failure' => true), array('table' => 'accounts_796', 'type' => '796', 'failure' => true), array('table' => 'securities_796', 'type' => 'securities_796', 'user_id' => get_site_config('system_user_id'), 'failure' => true), array('table' => 'accounts_litecoininvest', 'type' => 'litecoininvest', 'failure' => true), array('table' => 'accounts_individual_cryptostocks', 'type' => 'individual_cryptostocks', 'failure' => true), array('table' => 'accounts_individual_havelock', 'type' => 'individual_havelock', 'failure' => true), array('table' => 'accounts_individual_cryptotrade', 'type' => 'individual_crypto-trade', 'failure' => true), array('table' => 'accounts_individual_796', 'type' => 'individual_796', 'failure' => true), array('table' => 'accounts_individual_litecoininvest', 'type' => 'individual_litecoininvest', 'failure' => true)));
     $standard_jobs = array_merge($standard_jobs, array(array('table' => 'user_properties', 'type' => 'delete_user', 'query' => ' AND is_deleted=1', 'always' => true, 'user_id_field' => 'id'), array('table' => 'user_properties', 'type' => 'sum', 'user_id_field' => 'id'), array('table' => 'outstanding_premiums', 'type' => 'outstanding', 'query' => ' AND is_paid=0 AND is_unpaid=0', 'user_id' => get_site_config('system_user_id')), array('table' => 'user_properties', 'type' => 'expiring', 'query' => ' AND is_premium=1
     AND is_reminder_sent=0
     AND NOW() > DATE_SUB(premium_expires, INTERVAL ' . get_site_config('premium_reminder_days') . ' DAY)', 'user_id' => get_site_config('system_user_id'), 'always' => true), array('table' => 'user_properties', 'type' => 'expire', 'query' => ' AND is_premium=1
     AND NOW() > premium_expires', 'user_id' => get_site_config('system_user_id'), 'always' => true), array('table' => 'user_properties', 'type' => 'disable_warning', 'query' => ' AND is_premium=0 AND is_disabled=0
     AND is_disable_warned=0 AND is_system=0
     AND DATE_ADD(GREATEST(IFNULL(last_login, 0),
         IFNULL(DATE_ADD(premium_expires, INTERVAL ' . get_site_config('user_expiry_days') . ' DAY), 0),
         created_at), INTERVAL ' . get_site_config('user_expiry_days') * 0.8 . ' DAY) < NOW()', 'user_id' => get_site_config('system_user_id'), 'always' => true), array('table' => 'user_properties', 'type' => 'disable', 'query' => ' AND is_premium=0 AND is_disabled=0
     AND is_disable_warned=1 AND is_system=0
     AND DATE_ADD(GREATEST(IFNULL(last_login, 0),
         IFNULL(DATE_ADD(premium_expires, INTERVAL ' . get_site_config('user_expiry_days') . ' DAY), 0),
         created_at), INTERVAL ' . get_site_config('user_expiry_days') . '+1 DAY) < NOW()', 'user_id' => get_site_config('system_user_id'), 'always' => true), array('table' => 'user_properties', 'type' => 'securities_count', 'query' => ' AND is_disabled=0 AND is_system=0', 'queue_field' => 'securities_last_count_queue', 'user_id_field' => 'id'), array('table' => 'user_properties', 'type' => 'transaction_creator', 'query' => ' AND is_disabled=0 AND is_system=0', 'queue_field' => 'last_tx_creator_queue', 'user_id_field' => 'id'), array('table' => 'securities_update', 'type' => 'securities_update', 'user_id' => get_site_config('system_user_id')), array('table' => 'transaction_creators', 'type' => 'transactions', 'failure' => true), array('table' => 'notifications', 'type' => 'notification', 'query' => " AND period='hour'", 'failure' => true, 'hours' => 1), array('table' => 'notifications', 'type' => 'notification', 'query' => " AND period='day'", 'failure' => true, 'hours' => 24), array('table' => 'notifications', 'type' => 'notification', 'query' => " AND period='week'", 'failure' => true, 'hours' => 24 * 7), array('table' => 'notifications', 'type' => 'notification', 'query' => " AND period='month'", 'failure' => true, 'hours' => 24 * 7 * 30)));
     foreach ($standard_jobs as $i => $s) {
         // add default parameters
         $standard_jobs[$i] += array('failure' => false);
     }
     return $standard_jobs;
 }
 function run(Connection $db, Logger $logger)
 {
     $job = $this->job;
     switch ($job['job_type']) {
         // average jobs
         case "average":
             require __DIR__ . "/../jobs/average.php";
             break;
             // account jobs
         // account jobs
         case "generic":
             require __DIR__ . "/../jobs/generic.php";
             break;
         case "cryptostocks":
             require __DIR__ . "/../jobs/cryptostocks.php";
             break;
         case "securities_cryptostocks":
             require __DIR__ . "/../jobs/securities_cryptostocks.php";
             break;
         case "havelock":
             require __DIR__ . "/../jobs/havelock.php";
             break;
         case "securities_havelock":
             require __DIR__ . "/../jobs/securities_havelock.php";
             break;
         case "securities_crypto-trade":
             require __DIR__ . "/../jobs/securities_cryptotrade.php";
             break;
         case "796":
             require __DIR__ . "/../jobs/796.php";
             break;
         case "securities_796":
             require __DIR__ . "/../jobs/securities_796.php";
             break;
         case "litecoininvest":
             require __DIR__ . "/../jobs/litecoininvest.php";
             break;
             // individual securities jobs
         // individual securities jobs
         case "individual_cryptostocks":
             require __DIR__ . "/../jobs/individual_cryptostocks.php";
             break;
         case "individual_havelock":
             require __DIR__ . "/../jobs/individual_havelock.php";
             break;
         case "individual_crypto-trade":
             require __DIR__ . "/../jobs/individual_crypto-trade.php";
             break;
         case "individual_796":
             require __DIR__ . "/../jobs/individual_796.php";
             break;
         case "individual_litecoininvest":
             require __DIR__ . "/../jobs/individual_litecoininvest.php";
             break;
             // summary jobs
         // summary jobs
         case "sum":
             require __DIR__ . "/../jobs/sum.php";
             break;
         case "securities_count":
             require __DIR__ . "/../jobs/securities_count.php";
             break;
             // notification jobs
         // notification jobs
         case "notification":
             require __DIR__ . "/../jobs/notification.php";
             break;
             // system jobs
         // system jobs
         case "securities_update":
             require __DIR__ . "/../jobs/securities_update.php";
             break;
         case "version_check":
             require __DIR__ . "/../jobs/version_check.php";
             break;
         case "vote_coins":
             require __DIR__ . "/../jobs/vote_coins.php";
             break;
         case "missing_average_find":
             require __DIR__ . "/../jobs/missing_average_find.php";
             break;
         case "missing_average":
             require __DIR__ . "/../jobs/missing_average.php";
             break;
             // transaction jobs
         // transaction jobs
         case "transaction_creator":
             require __DIR__ . "/../jobs/transaction_creator.php";
             break;
         case "transactions":
             require __DIR__ . "/../jobs/transactions.php";
             break;
             // cleanup jobs, admin jobs etc
         // cleanup jobs, admin jobs etc
         case "outstanding":
             require __DIR__ . "/../jobs/outstanding.php";
             break;
         case "expiring":
             require __DIR__ . "/../jobs/expiring.php";
             break;
         case "expire":
             require __DIR__ . "/../jobs/expire.php";
             break;
         case "cleanup":
             require __DIR__ . "/../jobs/cleanup.php";
             break;
         case "disable_warning":
             require __DIR__ . "/../jobs/disable_warning.php";
             break;
         case "disable":
             require __DIR__ . "/../jobs/disable.php";
             break;
         case "delete_user":
             require __DIR__ . "/../jobs/delete_user.php";
             break;
         default:
             if (substr($job['job_type'], 0, strlen("address_")) === "address_") {
                 // address job
                 $currency = substr($job['job_type'], strlen("address_"));
                 if (!in_array($currency, get_address_currencies())) {
                     throw new JobException("Currency {$currency} is not a valid address currency");
                 }
                 if (in_array($currency, \DiscoveredComponents\Currencies::getBalanceCurrencies())) {
                     require __DIR__ . "/../jobs/addresses/discovered.php";
                 } else {
                     // TODO eventually remove this block once we have no currencies that are also in getBalanceCurrencies()
                     if (!file_exists(__DIR__ . "/../jobs/addresses/" . safe_include_arg($currency) . ".php")) {
                         throw new JobException("Could not find any addresses/{$currency}.php include");
                     }
                     require __DIR__ . "/../jobs/addresses/" . safe_include_arg($currency) . ".php";
                 }
                 break;
             }
             if (substr($job['job_type'], 0, strlen("blockcount_")) === "blockcount_") {
                 // address job
                 $currency = substr($job['job_type'], strlen("blockcount_"));
                 if (!in_array($currency, \DiscoveredComponents\Currencies::getBlockCurrencies())) {
                     throw new JobException("Currency {$currency} is not a valid block currency");
                 }
                 require __DIR__ . "/../jobs/blockcount/discovered.php";
                 break;
             }
             if (substr($job['job_type'], 0, strlen("difficulty_")) === "difficulty_") {
                 // address job
                 $currency = substr($job['job_type'], strlen("difficulty_"));
                 if (!in_array($currency, \DiscoveredComponents\Currencies::getDifficultyCurrencies())) {
                     throw new JobException("Currency {$currency} is not a valid difficulty currency");
                 }
                 require __DIR__ . "/../jobs/difficulty/discovered.php";
                 break;
             }
             if (substr($job['job_type'], 0, strlen("markets_")) === "markets_") {
                 // address job
                 $exchange = substr($job['job_type'], strlen("markets_"));
                 if (!in_array($exchange, \DiscoveredComponents\Exchanges::getKeys())) {
                     throw new JobException("Exchange {$exchange} is not a valid exchange");
                 }
                 require __DIR__ . "/../jobs/markets/discovered.php";
                 break;
             }
             if (substr($job['job_type'], 0, strlen("ticker_")) === "ticker_") {
                 // address job
                 $exchange = substr($job['job_type'], strlen("ticker_"));
                 if (!in_array($exchange, \DiscoveredComponents\Exchanges::getKeys())) {
                     throw new JobException("Exchange {$exchange} is not a valid exchange");
                 }
                 require __DIR__ . "/../jobs/ticker/discovered.php";
                 break;
             }
             if (substr($job['job_type'], 0, strlen("currencies_")) === "currencies_") {
                 // address job
                 $exchange = substr($job['job_type'], strlen("currencies_"));
                 if (!in_array($exchange, \DiscoveredComponents\Accounts::getKeys())) {
                     throw new JobException("Account {$exchange} is not a valid account");
                 }
                 require __DIR__ . "/../jobs/currencies/discovered.php";
                 break;
             }
             if (substr($job['job_type'], 0, strlen("hashrates_")) === "hashrates_") {
                 // address job
                 $exchange = substr($job['job_type'], strlen("hashrates_"));
                 if (!in_array($exchange, \DiscoveredComponents\Accounts::getMiners())) {
                     throw new JobException("Account {$exchange} is not a valid miner");
                 }
                 require __DIR__ . "/../jobs/hashrates/discovered.php";
                 break;
             }
             if (substr($job['job_type'], 0, strlen("account_")) === "account_") {
                 // address job
                 $exchange = substr($job['job_type'], strlen("account_"));
                 if (!in_array($exchange, \DiscoveredComponents\Accounts::getKeys())) {
                     throw new JobException("Account {$exchange} is not a valid account");
                 }
                 require __DIR__ . "/../jobs/account/discovered.php";
                 break;
             }
             throw new JobException("Unknown job type '" . htmlspecialchars($job['job_type']) . "'");
     }
 }
Example #3
0
 /**
  * All currencies defined in {@link get_address_currencies()} should have
  * an equivalent PHP script in {@code jobs/addresses/CUR.php}.
  */
 function testAllAddressCurrenciesHaveAddressIncludes()
 {
     foreach (get_address_currencies() as $cur) {
         // skip ones that are discovered
         if (\DiscoveredComponents\Currencies::hasKey($cur)) {
             continue;
         }
         $file = __DIR__ . "/../jobs/addresses/{$cur}.php";
         $this->assertTrue(file_exists($file), "File '{$file}' did not exist for address currency '{$cur}'");
     }
 }
Example #4
0
/**
 * Return a grouped array of (job_type => (table, gruop, wizard, failure, ...))
 */
function account_data_grouped()
{
    $addresses_data = array();
    $mining_pools_data = array();
    $exchange_wallets_data = array();
    // we can generate this automatically
    foreach (get_address_currencies() as $cur) {
        $addresses_data["address_" . $cur] = array('title' => get_currency_abbr($cur) . ' addresses', 'label' => 'address', 'labels' => 'addresses', 'table' => 'addresses', 'group' => 'addresses', 'query' => " AND currency='{$cur}'", 'wizard' => 'addresses', 'currency' => $cur, 'job_type' => 'addresses_' . $cur);
    }
    foreach (Accounts::getKeys() as $exchange) {
        if (in_array($exchange, Accounts::getMiners())) {
            // a miner
            $mining_pools_data[$exchange] = array('table' => 'accounts_' . safe_table_name($exchange), 'group' => 'accounts', 'wizard' => 'pools', 'failure' => true, 'disabled' => in_array($exchange, Accounts::getDisabled()), 'job_type' => 'account_' . $exchange);
        } else {
            // otherwise, assume an exchange wallet
            $exchange_wallets_data[$exchange] = array('table' => 'accounts_' . safe_table_name($exchange), 'group' => 'accounts', 'wizard' => 'exchanges', 'failure' => true, 'disabled' => in_array($exchange, Accounts::getDisabled()), 'job_type' => 'account_' . $exchange);
        }
    }
    $data = array('Addresses' => $addresses_data, 'Mining pools' => $mining_pools_data, 'Exchanges' => $exchange_wallets_data, 'Securities' => array('796' => array('table' => 'accounts_796', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true), 'bitfunder' => array('table' => 'accounts_bitfunder', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true, 'disabled' => true), 'btcinve' => array('table' => 'accounts_btcinve', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true, 'disabled' => true), 'btct' => array('table' => 'accounts_btct', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true, 'disabled' => true), 'crypto-trade' => array('table' => 'accounts_cryptotrade', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true), 'cryptostocks' => array('table' => 'accounts_cryptostocks', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true), 'havelock' => array('table' => 'accounts_havelock', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true), 'litecoininvest' => array('table' => 'accounts_litecoininvest', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true), 'litecoinglobal' => array('table' => 'accounts_litecoinglobal', 'group' => 'accounts', 'wizard' => 'securities', 'failure' => true, 'disabled' => true)), 'Individual Securities' => array('individual_796' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_796', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => '796', 'securities_table' => 'securities_796', 'failure' => true), 'individual_bitfunder' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_bitfunder', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'bitfunder', 'securities_table' => 'securities_bitfunder', 'failure' => true, 'disabled' => true), 'individual_btcinve' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_btcinve', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'btcinve', 'securities_table' => 'securities_btcinve', 'failure' => true, 'disabled' => true), 'individual_btct' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_btct', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'btct', 'securities_table' => 'securities_btct', 'failure' => true, 'disabled' => true), 'individual_crypto-trade' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_cryptotrade', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'crypto-trade', 'securities_table' => 'securities_cryptotrade', 'failure' => true), 'individual_cryptostocks' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_cryptostocks', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'cryptostocks', 'securities_table' => 'securities_cryptostocks', 'failure' => true), 'individual_havelock' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_havelock', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'havelock', 'securities_table' => 'securities_havelock', 'failure' => true), 'individual_litecoininvest' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_litecoininvest', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'litecoininvest', 'securities_table' => 'securities_litecoininvest', 'failure' => true), 'individual_litecoinglobal' => array('label' => 'security', 'labels' => 'securities', 'table' => 'accounts_individual_litecoinglobal', 'group' => 'accounts', 'wizard' => 'individual', 'exchange' => 'litecoinglobal', 'securities_table' => 'securities_litecoinglobal', 'failure' => true, 'disabled' => true)), 'Securities Tickers' => array('securities_796' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_796', 'exchange' => '796', 'securities_table' => 'securities_796'), 'securities_bitfunder' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_bitfunder', 'exchange' => 'bitfunder', 'securities_table' => 'securities_bitfunder', 'disabled' => true), 'securities_btcinve' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_btcinve', 'exchange' => 'btcinve', 'securities_table' => 'securities_btcinve', 'disabled' => true), 'securities_btct' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_btct', 'exchange' => 'btct', 'securities_table' => 'securities_btct', 'disabled' => true), 'securities_crypto-trade' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_cryptotrade', 'exchange' => 'crypto-trade', 'securities_table' => 'securities_cryptotrade', 'disabled' => true), 'securities_cryptostocks' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_cryptostocks', 'exchange' => 'cryptostocks', 'securities_table' => 'securities_cryptostocks', 'disabled' => true), 'securities_havelock' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_havelock', 'exchange' => 'havelock', 'securities_table' => 'securities_havelock', 'failure' => true), 'securities_litecoininvest' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_litecoininvest', 'exchange' => 'litecoininvest', 'securities_table' => 'securities_litecoininvest'), 'securities_litecoinglobal' => array('label' => 'security ticker', 'labels' => 'securities', 'table' => 'securities_litecoinglobal', 'exchange' => 'litecoinglobal', 'securities_table' => 'securities_litecoinglobal', 'disabled' => true)), 'Finance' => array('finance_accounts' => array('title' => 'Finance account', 'label' => 'finance account', 'table' => 'finance_accounts', 'group' => 'finance_accounts', 'job' => false), 'finance_categories' => array('title' => 'Finance category', 'label' => 'finance category', 'titles' => 'finance categories', 'table' => 'finance_categories', 'group' => 'finance_categories', 'job' => false)), 'Other' => array('generic' => array('title' => 'Generic APIs', 'label' => 'API', 'table' => 'accounts_generic', 'group' => 'accounts', 'wizard' => 'other', 'failure' => true)), 'Hidden' => array('graph' => array('title' => 'Graphs', 'table' => 'graphs', 'query' => ' AND is_removed=0', 'job' => false), 'graph_pages' => array('title' => 'Graph page', 'table' => 'graph_pages', 'group' => 'graph_pages', 'query' => ' AND is_removed=0', 'job' => false), 'summaries' => array('title' => 'Currency summaries', 'table' => 'summaries', 'group' => 'summaries', 'job' => false), 'notifications' => array('title' => 'Notifications', 'table' => 'notifications', 'group' => 'notifications', 'wizard' => 'notifications')), 'Offsets' => array());
    // add all offset currencies
    foreach (get_all_currencies() as $cur) {
        $data['Offsets']['offset_' . $cur] = array('title' => get_currency_name($cur), 'label' => 'offset', 'table' => 'offsets', 'group' => 'offsets', 'wizard' => 'offsets', 'query' => ' AND currency=\'' . $cur . '\'', 'currency' => $cur, 'job' => false);
    }
    foreach ($data as $key0 => $row0) {
        foreach ($row0 as $key => $row) {
            if (!isset($data[$key0][$key]['label'])) {
                $data[$key0][$key]['label'] = "account";
            }
            if (!isset($data[$key0][$key]['labels'])) {
                $data[$key0][$key]['labels'] = $data[$key0][$key]['label'] . "s";
            }
            if (!isset($data[$key0][$key]['title'])) {
                $data[$key0][$key]['title'] = get_exchange_name($key) . (isset($row['suffix']) ? $row['suffix'] : "") . " " . $data[$key0][$key]['labels'];
            }
            if (!isset($data[$key0][$key]['title_key'])) {
                $data[$key0][$key]['title_key'] = $key;
            }
            if (!isset($data[$key0][$key]['failure'])) {
                $data[$key0][$key]['failure'] = false;
            }
            if (!isset($data[$key0][$key]['job'])) {
                $data[$key0][$key]['job'] = true;
            }
            if (!isset($data[$key0][$key]['disabled'])) {
                $data[$key0][$key]['disabled'] = false;
            }
            if (!isset($data[$key0][$key]['suffix'])) {
                $data[$key0][$key]['suffix'] = false;
            }
            if (!isset($data[$key0][$key]['system'])) {
                $data[$key0][$key]['system'] = false;
            }
            if (!isset($data[$key0][$key]['query'])) {
                $data[$key0][$key]['query'] = '';
            }
            if (!isset($data[$key0][$key]['job_type']) && isset($data[$key0][$key]['exchange'])) {
                $data[$key0][$key]['job_type'] = $data[$key0][$key]['exchange'];
            }
            if (!isset($data[$key0][$key]['job_type']) && $key0 == "Exchanges") {
                $data[$key0][$key]['job_type'] = $key;
            }
        }
    }
    return $data;
}
page_header(t("Add Addresses"), "page_wizard_accounts_addresses", array('js' => array('accounts', 'wizard'), 'class' => 'page_accounts wizard_page'));
global $user;
$user = get_user(user_id());
require_user($user);
$messages = array();
// get all of our currencies
$summaries = get_all_summaries();
$currencies = array();
foreach ($summaries as $key => $summary) {
    $c = substr($key, strlen("summary_"), 3);
    if (in_array($c, get_all_cryptocurrencies())) {
        $currencies[] = $c;
    }
}
// order by the order defined in crypto.php, and only ones that we can actually address
$currencies = array_intersect(get_address_currencies(), $currencies);
require_template("wizard_accounts_addresses");
?>

<div class="wizard">

<div class="tabs" id="tabs_wizard">
  <ul class="tab_list">
    <?php 
/* each <li> must not have any whitespace between them otherwise whitespace will appear when rendered */
?>
    <?php 
foreach ($currencies as $c) {
    echo "<li id=\"tab_wizard_" . $c . "\"><span class=\"currency_name_" . $c . "\">" . htmlspecialchars(get_currency_name($c)) . "</span></li>";
}
?>