index: Remove the index class
This patch updates the design so indexes are built upon databases using a special IndexEntry. I also updated the tests/index/ test to match the new system, but I have not updated filter or group tests yet. Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
parent
f0533ef663
commit
97d889531a
1
config
1
config
|
@ -39,7 +39,6 @@ class Config:
|
|||
self.FILTER = False
|
||||
self.GROUP = False
|
||||
self.IDLE = False
|
||||
self.INDEX = False
|
||||
self.LIBRARY = False
|
||||
self.TEST = TEST
|
||||
self.reconfigure()
|
||||
|
|
|
@ -46,7 +46,7 @@ Database: (lib/database.cpp)
|
|||
class IndexEntry : public DatabaseEntry {
|
||||
public:
|
||||
string key;
|
||||
vector<unsigned int> values;
|
||||
set<unsigned int> values;
|
||||
|
||||
const std::string &primary_key();
|
||||
void write(File &);
|
||||
|
@ -71,6 +71,7 @@ Database: (lib/database.cpp)
|
|||
void save();
|
||||
void clear();
|
||||
void print();
|
||||
void print_keys();
|
||||
|
||||
unsigned int insert(T);
|
||||
void delete(unsigned int);
|
||||
|
@ -80,7 +81,8 @@ Database: (lib/database.cpp)
|
|||
unsigned int first();
|
||||
unsigned int last();
|
||||
unsigned int next(unsigned int &);
|
||||
unsigned int find(const std::string &);
|
||||
unsigned int find_index(const std::string &);
|
||||
T &find(const std::string &);
|
||||
T &operator[](unsigned int);
|
||||
};
|
||||
|
||||
|
@ -110,6 +112,10 @@ Database: (lib/database.cpp)
|
|||
Following a similar format for writing to disk, print the
|
||||
database to the console in a human-readable format.
|
||||
|
||||
void Database :: print_keys()
|
||||
This function exists only if CONFIG_DEBUG is enabled.
|
||||
Print out the collected primary keys in the database.
|
||||
|
||||
template <class T>
|
||||
unsigned int Database :: insert(T &);
|
||||
Adds a new item to the db and marks it as valid. A reverse
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <print.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
@ -25,6 +26,23 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class IndexEntry : public DatabaseEntry {
|
||||
public:
|
||||
std::string key;
|
||||
std::set<unsigned int> values;
|
||||
|
||||
IndexEntry();
|
||||
IndexEntry(const std::string &, unsigned int);
|
||||
~IndexEntry();
|
||||
const std::string &primary_key();
|
||||
void write(File &);
|
||||
void read(File &);
|
||||
void print();
|
||||
void insert(unsigned int);
|
||||
void remove(unsigned int);
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class Database {
|
||||
private:
|
||||
|
@ -41,6 +59,7 @@ public:
|
|||
#ifdef CONFIG_DEBUG
|
||||
void clear();
|
||||
void print();
|
||||
void print_keys();
|
||||
#endif /* CONFIG_DEBUG */
|
||||
|
||||
unsigned int insert(T);
|
||||
|
@ -51,9 +70,32 @@ public:
|
|||
unsigned int first();
|
||||
unsigned int last();
|
||||
unsigned int next(unsigned int);
|
||||
unsigned int find_index(const std::string &);
|
||||
T &find(const std::string &);
|
||||
T &operator[](unsigned int);
|
||||
};
|
||||
|
||||
static inline void index_insert(Database<IndexEntry> &db,
|
||||
const std::string &key,
|
||||
unsigned int val)
|
||||
{
|
||||
try {
|
||||
db.find(key).insert(val);
|
||||
} catch (...) {
|
||||
db.insert(IndexEntry(key, val));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void index_remove(Database<IndexEntry> &db,
|
||||
const std::string &key,
|
||||
unsigned int val)
|
||||
{
|
||||
unsigned int i = db.find_index(key);
|
||||
db[i].remove(val);
|
||||
if (db[i].values.size() == 0)
|
||||
db.remove(db.find_index(key));
|
||||
}
|
||||
|
||||
#include "database.hpp"
|
||||
|
||||
#endif /* OCARINA_DATABASE_H */
|
||||
|
|
|
@ -48,6 +48,7 @@ void Database<T> :: load()
|
|||
file >> db[i].valid;
|
||||
if (db[i].valid == true) {
|
||||
db[i].read(file);
|
||||
keys.insert(std::pair<std::string, unsigned int>(db[i].primary_key(), i));
|
||||
_size++;
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +77,16 @@ void Database<T> :: print()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Database<T> :: print_keys()
|
||||
{
|
||||
std::map<const std::string, unsigned int>::iterator it;
|
||||
:: print("Found keys:");
|
||||
for (it = keys.begin(); it != keys.end(); it++)
|
||||
:: print(" %s", it->first.c_str());
|
||||
:: print("\n");
|
||||
}
|
||||
#endif /* CONFIG_DEBUG */
|
||||
|
||||
template <class T>
|
||||
|
@ -102,6 +113,7 @@ unsigned int Database<T> :: insert(T val)
|
|||
template <class T>
|
||||
void Database<T> :: remove(unsigned int id)
|
||||
{
|
||||
keys.erase(db[id].primary_key());
|
||||
db[id].valid = false;
|
||||
_size--;
|
||||
}
|
||||
|
@ -154,6 +166,22 @@ unsigned int Database<T> :: next(unsigned int id)
|
|||
return db.size();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
unsigned int Database<T> :: find_index(const std::string &key)
|
||||
{
|
||||
std::map<std::string, unsigned int>::iterator it;
|
||||
it = keys.find(key);
|
||||
if (it == keys.end())
|
||||
throw 0;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T &Database<T> :: find(const std::string &key)
|
||||
{
|
||||
return db[find_index(key)];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T &Database<T> :: operator[](unsigned int id)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#ifndef OCARINA_FILTER_H
|
||||
#define OCARINA_FILTER_H
|
||||
|
||||
#include <index.h>
|
||||
#include <database.h>
|
||||
#include <string>
|
||||
|
||||
namespace filter {
|
||||
|
@ -15,7 +15,7 @@ namespace filter {
|
|||
void print_cache_stats();
|
||||
|
||||
#ifdef CONFIG_TEST
|
||||
Index &get_index();
|
||||
Database<IndexEntry> &get_index();
|
||||
#endif /* CONFIG_TEST */
|
||||
|
||||
};
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 (c) Anna Schumaker.
|
||||
*/
|
||||
#ifndef OCARINA_INDEX_H
|
||||
#define OCARINA_INDEX_H
|
||||
|
||||
#include <file.h>
|
||||
#include <print.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
class Index {
|
||||
private:
|
||||
std::map<std::string, std::set<unsigned int> > index;
|
||||
std::set<std::string> keys;
|
||||
File file;
|
||||
|
||||
public:
|
||||
Index(std::string);
|
||||
void save();
|
||||
void load();
|
||||
#ifdef CONFIG_DEBUG
|
||||
void print();
|
||||
void print_keys();
|
||||
#endif /* CONFIG_DEBUG */
|
||||
|
||||
void insert(std::string, unsigned int);
|
||||
void remove(std::string);
|
||||
void remove(std::string, unsigned int);
|
||||
|
||||
const std::set<std::string>::iterator keys_begin();
|
||||
const std::set<std::string>::iterator keys_end();
|
||||
const std::set<unsigned int> &operator[](const std::string &);
|
||||
};
|
||||
|
||||
#endif /* OCARINA_INDEX_H */
|
|
@ -17,10 +17,9 @@ modules = {
|
|||
|
||||
"DATABASE" : Module("database.cpp", depends = [ "FILE" ]),
|
||||
"FILE" : Module("file.cpp", package = "glib-2.0"),
|
||||
"FILTER" : Module("filter.cpp", depends = [ "INDEX" ]),
|
||||
"FILTER" : Module("filter.cpp", depends = [ "DATABASE" ]),
|
||||
"GROUP" : Module("group.cpp", depends = [ "INDEX" ]),
|
||||
"IDLE" : Module("idle.cpp"),
|
||||
"INDEX" : Module("index.cpp", depends = [ "FILE" ]),
|
||||
"LIBRARY" : Module("library.cpp", package = "taglib", depends = [ "DATABASE", "IDLE" ]),
|
||||
|
||||
###########################
|
||||
|
|
|
@ -7,3 +7,65 @@ DatabaseEntry :: DatabaseEntry()
|
|||
: valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
IndexEntry :: IndexEntry()
|
||||
{
|
||||
}
|
||||
|
||||
IndexEntry :: IndexEntry(const std::string &k, unsigned int v)
|
||||
: key(k)
|
||||
{
|
||||
insert(v);
|
||||
}
|
||||
|
||||
IndexEntry :: ~IndexEntry()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string &IndexEntry :: primary_key()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
void IndexEntry :: write(File &f)
|
||||
{
|
||||
std::set<unsigned int>::iterator it;
|
||||
f << key << std::endl << values.size() << " ";
|
||||
for (it = values.begin(); it != values.end(); it++)
|
||||
f << *it << " ";
|
||||
}
|
||||
|
||||
void IndexEntry :: read(File &f)
|
||||
{
|
||||
unsigned int num, val;
|
||||
|
||||
f >> key >> num;
|
||||
for (unsigned int i = 0; i < num; i++) {
|
||||
f >> val;
|
||||
values.insert(val);
|
||||
}
|
||||
}
|
||||
|
||||
void IndexEntry :: print()
|
||||
{
|
||||
std::set<unsigned int>::iterator it;
|
||||
:: print("{");
|
||||
for (it = values.begin(); it != values.end(); it++) {
|
||||
if (it != values.begin())
|
||||
:: print(" ");
|
||||
:: print("%d", *it);
|
||||
}
|
||||
:: print("}");
|
||||
}
|
||||
|
||||
void IndexEntry :: insert(unsigned int val)
|
||||
{
|
||||
values.insert(val);
|
||||
}
|
||||
|
||||
void IndexEntry :: remove(unsigned int val)
|
||||
{
|
||||
values.erase(val);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
*/
|
||||
|
||||
#include <filter.h>
|
||||
#include <index.h>
|
||||
#include <print.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -11,7 +10,7 @@
|
|||
#include <map>
|
||||
#include <set>
|
||||
|
||||
static Index filter_index("");
|
||||
static Database<IndexEntry> filter_index("");
|
||||
static std::map<std::string, std::string> lowercase_cache;
|
||||
static unsigned int lowercase_cache_hits = 0;
|
||||
|
||||
|
@ -89,8 +88,15 @@ static void parse_text(const std::string &text, std::list<std::string> &ret)
|
|||
|
||||
static void add_substrings(const std::string &text, unsigned int track_id)
|
||||
{
|
||||
for (unsigned int i = 1; i <= text.size(); i++)
|
||||
filter_index.insert(text.substr(0, i), track_id);
|
||||
std::string substr;
|
||||
for (unsigned int i = 1; i <= text.size(); i++) {
|
||||
substr = text.substr(0, i);
|
||||
try {
|
||||
filter_index.find(substr).insert(track_id);
|
||||
} catch (...) {
|
||||
filter_index.insert(IndexEntry(substr, track_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void filter :: add(const std::string &text, unsigned int track_id)
|
||||
|
@ -137,7 +143,7 @@ void filter :: print_cache_stats()
|
|||
}
|
||||
|
||||
#ifdef CONFIG_TEST
|
||||
Index &filter :: get_index()
|
||||
Database<IndexEntry> &filter :: get_index()
|
||||
{
|
||||
return filter_index;
|
||||
}
|
||||
|
|
120
lib/index.cpp
120
lib/index.cpp
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 (c) Anna Schumaker.
|
||||
*/
|
||||
|
||||
#include <index.h>
|
||||
|
||||
Index :: Index(std::string filepath)
|
||||
: file(filepath, FILE_TYPE_DATA)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Index :: save()
|
||||
{
|
||||
std::set<std::string>::iterator k_it;
|
||||
std::set<unsigned int>::iterator u_it;
|
||||
|
||||
if (file.open(OPEN_WRITE) == false)
|
||||
return;
|
||||
|
||||
file << keys.size();
|
||||
for (k_it = keys.begin(); k_it != keys.end(); k_it++) {
|
||||
file << *k_it << std::endl;
|
||||
file << index[*k_it].size() << " ";
|
||||
|
||||
for (u_it = index[*k_it].begin(); u_it != index[*k_it].end(); u_it++)
|
||||
file << *u_it << " ";
|
||||
|
||||
file << std::endl;
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void Index :: load()
|
||||
{
|
||||
std::string key;
|
||||
unsigned int num_keys, num_values, value;
|
||||
|
||||
if (file.open(OPEN_READ) == false)
|
||||
return;
|
||||
|
||||
file >> num_keys;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
file >> key >> num_values;
|
||||
for (unsigned int j = 0; j < num_values; j++) {
|
||||
file >> value;
|
||||
insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void Index :: print()
|
||||
{
|
||||
std::set<std::string>::iterator s_it;
|
||||
std::set<unsigned int>::iterator u_it;
|
||||
|
||||
for (s_it = keys.begin(); s_it != keys.end(); s_it++) {
|
||||
std::string key = *s_it;
|
||||
:: print("index[%s] = {", key.c_str());
|
||||
|
||||
for (u_it = index[key].begin(); u_it != index[key].end(); u_it++) {
|
||||
if (u_it != index[key].begin())
|
||||
:: print(" ");
|
||||
:: print("%d", *u_it);
|
||||
}
|
||||
|
||||
:: print("}\n");
|
||||
}
|
||||
:: print("\n");
|
||||
}
|
||||
|
||||
void Index :: print_keys()
|
||||
{
|
||||
std::set<std::string>::iterator it;
|
||||
|
||||
:: print("Keys:");
|
||||
for (it = keys.begin(); it != keys.end(); it++)
|
||||
:: print(" %s", it->c_str());
|
||||
:: print("\n");
|
||||
}
|
||||
|
||||
void Index :: insert(std::string key, unsigned int value)
|
||||
{
|
||||
if (index.find(key) == index.end()) {
|
||||
index[key] = std::set<unsigned int>();
|
||||
keys.insert(key);
|
||||
}
|
||||
index[key].insert(value);
|
||||
}
|
||||
|
||||
void Index :: remove(std::string key)
|
||||
{
|
||||
index.erase(key);
|
||||
keys.erase(key);
|
||||
}
|
||||
|
||||
void Index :: remove(std::string key, unsigned int value)
|
||||
{
|
||||
index[key].erase(value);
|
||||
if (index[key].size() == 0)
|
||||
remove(key);
|
||||
}
|
||||
|
||||
const std::set<std::string>::iterator Index :: keys_begin()
|
||||
{
|
||||
return keys.begin();
|
||||
}
|
||||
|
||||
const std::set<std::string>::iterator Index :: keys_end()
|
||||
{
|
||||
return keys.end();
|
||||
}
|
||||
|
||||
const std::set<unsigned int> &Index :: operator[](const std::string &key)
|
||||
{
|
||||
return index[key];
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/python
|
||||
Import("Test", "CONFIG")
|
||||
|
||||
CONFIG.INDEX = True
|
||||
CONFIG.DATABASE = True
|
||||
|
||||
Test("index", "index.cpp")
|
||||
|
|
|
@ -1,74 +1,56 @@
|
|||
/*
|
||||
* Copyright 2013 (c) Anna Schumaker.
|
||||
*/
|
||||
#include <index.h>
|
||||
#include <database.h>
|
||||
#include <print.h>
|
||||
|
||||
void print_keys(Index &index)
|
||||
{
|
||||
std::set<std::string>::iterator it;
|
||||
|
||||
print("Found keys:");
|
||||
for (it = index.keys_begin(); it != index.keys_end(); it++)
|
||||
print(" %s", it->c_str());
|
||||
print("\n");
|
||||
}
|
||||
|
||||
void print_index(Index &index)
|
||||
void print_index(Database<IndexEntry> &index)
|
||||
{
|
||||
std::set<std::string>::iterator s_it;
|
||||
std::set<unsigned int>::iterator u_it;
|
||||
|
||||
print("=== Printing index ===\n");
|
||||
print_keys(index);
|
||||
index.print_keys();
|
||||
|
||||
for (s_it = index.keys_begin(); s_it != index.keys_end(); s_it++) {
|
||||
std::string key = *s_it;
|
||||
print("index[%s] = {", key.c_str());
|
||||
|
||||
for (u_it = index[key].begin(); u_it != index[key].end(); u_it++) {
|
||||
if (u_it != index[key].begin())
|
||||
print(" ");
|
||||
print("%d", *u_it);
|
||||
}
|
||||
|
||||
print("}\n");
|
||||
for (unsigned int i = index.first(); i != index.num_rows(); i = index.next(i)) {
|
||||
print("index[%s] = ", index[i].key.c_str());
|
||||
index[i].print();
|
||||
print("\n");
|
||||
}
|
||||
|
||||
print("\n");
|
||||
}
|
||||
|
||||
void populate_index(Index &index)
|
||||
void populate_index(Database<IndexEntry> &index)
|
||||
{
|
||||
std::string key_str;
|
||||
|
||||
for (char key = 'a'; key <= 'z'; key++) {
|
||||
key_str = key;
|
||||
for (unsigned int value = 0; value < 10; value++) {
|
||||
index.insert(key_str, value);
|
||||
}
|
||||
for (unsigned int value = 0; value < 10; value++)
|
||||
index_insert(index, key_str, value);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_keys(Index &index)
|
||||
void remove_keys(Database<IndexEntry> &index)
|
||||
{
|
||||
std::string key_str;
|
||||
|
||||
for (char key = 'a'; key <= 'z'; key+=2) {
|
||||
key_str = key;
|
||||
index.remove(key_str);
|
||||
index.remove(index.find_index(key_str));
|
||||
}
|
||||
}
|
||||
|
||||
void remove_values(Index &index)
|
||||
void remove_values(Database<IndexEntry> &index)
|
||||
{
|
||||
std::string key_str;
|
||||
unsigned int limit = 0;
|
||||
|
||||
for (char key = 'a'; key <= 'z'; key++) {
|
||||
key_str = key;
|
||||
for (unsigned int i = 0; i < limit; i++) {
|
||||
index.remove(key_str, i);
|
||||
}
|
||||
for (unsigned int i = 0; i < limit; i++)
|
||||
index_remove(index, key_str, i);
|
||||
limit++;
|
||||
if (limit == 11)
|
||||
limit = 0;
|
||||
|
@ -81,7 +63,7 @@ void remove_values(Index &index)
|
|||
void test_0()
|
||||
{
|
||||
print("Test 0\n");
|
||||
Index index("");
|
||||
Database<IndexEntry> index("");
|
||||
|
||||
populate_index(index);
|
||||
print_index(index);
|
||||
|
@ -93,7 +75,7 @@ void test_0()
|
|||
void test_1()
|
||||
{
|
||||
print("Test 1\n");
|
||||
Index index("");
|
||||
Database<IndexEntry> index("");
|
||||
|
||||
populate_index(index);
|
||||
remove_keys(index);
|
||||
|
@ -106,7 +88,7 @@ void test_1()
|
|||
void test_2()
|
||||
{
|
||||
print("Test 2\n");
|
||||
Index index("");
|
||||
Database<IndexEntry> index("");
|
||||
|
||||
populate_index(index);
|
||||
remove_values(index);
|
||||
|
@ -119,7 +101,7 @@ void test_2()
|
|||
void test_3()
|
||||
{
|
||||
print("Test 3\n");
|
||||
Index index("test.idx");
|
||||
Database<IndexEntry> index("test.idx");
|
||||
|
||||
populate_index(index);
|
||||
remove_values(index);
|
||||
|
@ -132,7 +114,7 @@ void test_3()
|
|||
void test_4()
|
||||
{
|
||||
print("Test 4\n");
|
||||
Index index("test.idx");
|
||||
Database<IndexEntry> index("test.idx");
|
||||
|
||||
index.load();
|
||||
print_index(index);
|
||||
|
@ -144,21 +126,13 @@ void test_4()
|
|||
void test_5()
|
||||
{
|
||||
print("Test 5\n");
|
||||
Index index("");
|
||||
print("index[nokey].size() = %u\n", index["nokey"].size());
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the print() function
|
||||
*/
|
||||
void test_6()
|
||||
{
|
||||
print("Test 6\n");
|
||||
Index index("");
|
||||
|
||||
populate_index(index);
|
||||
index.print_keys();
|
||||
index.print();
|
||||
Database<IndexEntry> index("");
|
||||
print("index[nokey].size() = ");
|
||||
try {
|
||||
print("%u\n", index.find("nokey").values.size());
|
||||
} catch (...) {
|
||||
print("0\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -169,6 +143,5 @@ int main(int argc, char **argv)
|
|||
test_3();
|
||||
test_4();
|
||||
test_5();
|
||||
test_6();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -104,32 +104,3 @@ index[z] = {3 4 5 6 7 8 9}
|
|||
|
||||
Test 5
|
||||
index[nokey].size() = 0
|
||||
Test 6
|
||||
Keys: a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
index[a] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[b] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[c] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[d] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[e] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[f] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[g] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[h] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[i] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[j] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[k] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[l] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[m] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[n] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[o] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[p] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[q] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[r] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[s] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[t] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[u] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[v] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[w] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[x] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[y] = {0 1 2 3 4 5 6 7 8 9}
|
||||
index[z] = {0 1 2 3 4 5 6 7 8 9}
|
||||
|
||||
|
|
Loading…
Reference in New Issue