annotate src/library/library.cc @ 410:eb554255ea5f default tip

*: no crash
author Paper <paper@tflc.us>
date Thu, 02 Apr 2026 01:09:09 -0400
parents 8d06825d96d1
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
222
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
1 #include "library/library.h"
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
2 #include "core/anime_db.h"
258
862d0d8619f6 *: HUUUGE changes
Paper <paper@paper.us.eu.org>
parents: 228
diff changeset
3 #include "core/session.h"
222
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
4 #include "core/strings.h"
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
5
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
6 #include "anitomy/anitomy.h"
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
7
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
8 #include <filesystem>
258
862d0d8619f6 *: HUUUGE changes
Paper <paper@paper.us.eu.org>
parents: 228
diff changeset
9 #include <string>
222
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
10 #include <unordered_map>
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
11
223
84e0a3c4737a library: implement menu bar buttons
Paper <mrpapersonic@gmail.com>
parents: 222
diff changeset
12 #include <iostream>
84e0a3c4737a library: implement menu bar buttons
Paper <mrpapersonic@gmail.com>
parents: 222
diff changeset
13
84e0a3c4737a library: implement menu bar buttons
Paper <mrpapersonic@gmail.com>
parents: 222
diff changeset
14 namespace Library {
84e0a3c4737a library: implement menu bar buttons
Paper <mrpapersonic@gmail.com>
parents: 222
diff changeset
15
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
16 Database::Database()
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
17 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
18 /* Do this immediately :) */
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
19 /* Nevermind, this causes an immediate segfault on Windows
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
20 UpdateWatchers();
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
21 */
409
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
22 /* Also, this would be completely useless as the paths in
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
23 * the config are not filled until after main() is
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
24 * called. */
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
25 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
26
410
eb554255ea5f *: no crash
Paper <paper@tflc.us>
parents: 409
diff changeset
27 Database::~Database()
eb554255ea5f *: no crash
Paper <paper@tflc.us>
parents: 409
diff changeset
28 {
eb554255ea5f *: no crash
Paper <paper@tflc.us>
parents: 409
diff changeset
29 /* Wait */
eb554255ea5f *: no crash
Paper <paper@tflc.us>
parents: 409
diff changeset
30 if (refresh_thread_.joinable())
eb554255ea5f *: no crash
Paper <paper@tflc.us>
parents: 409
diff changeset
31 refresh_thread_.join();
eb554255ea5f *: no crash
Paper <paper@tflc.us>
parents: 409
diff changeset
32 }
eb554255ea5f *: no crash
Paper <paper@tflc.us>
parents: 409
diff changeset
33
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
34 void Database::UpdateWatchers()
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
35 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
36 /* TODO also need to remove unused watchers */
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
37
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
38 for (const auto &p : session.config.library.paths) {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
39 if (watchers_.count(p))
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
40 continue;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
41
393
963047512d34 *: clang-format
Paper <paper@tflc.us>
parents: 383
diff changeset
42 watchers_[p].reset(
963047512d34 *: clang-format
Paper <paper@tflc.us>
parents: 383
diff changeset
43 Filesystem::GetRecursiveFilesystemWatcher(reinterpret_cast<void *>(this), p, Database::StaticEventHandler));
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
44 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
45 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
46
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
47 bool Database::GetPathAnimeAndEpisode(const std::string &basename, int *aid, int *ep)
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
48 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
49 anitomy::Anitomy anitomy;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
50 anitomy.Parse(basename);
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
51
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
52 const auto &elements = anitomy.elements();
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
53
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
54 const std::string title = Strings::ToUtf8String(elements.get(anitomy::kElementAnimeTitle));
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
55
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
56 const int id = Anime::db.LookupAnimeTitle(title);
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
57 if (id <= 0 || (find_id_ && find_id_.value() != id))
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
58 return false;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
59
393
963047512d34 *: clang-format
Paper <paper@tflc.us>
parents: 383
diff changeset
60 const int episode = Strings::ToInt<int>(Strings::ToUtf8String(elements.get(anitomy::kElementEpisodeNumber)));
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
61
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
62 *aid = id;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
63 *ep = episode;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
64 return true;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
65 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
66
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
67 void Database::EventHandler(const std::filesystem::path &path, Filesystem::IWatcher::Event event)
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
68 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
69 std::string bname = path.filename().u8string();
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
70 int aid, ep;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
71
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
72 if (!GetPathAnimeAndEpisode(bname, &aid, &ep))
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
73 return;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
74
409
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
75 /* Lock the items mutex */
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
76 const std::lock_guard<std::recursive_mutex> lock(items_mutex_);
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
77
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
78 switch (event) {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
79 case Filesystem::IWatcher::Created:
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
80 items[aid][ep] = path;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
81 break;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
82 case Filesystem::IWatcher::Deleted:
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
83 /* kill it off */
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
84 items[aid].erase(ep);
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
85 if (items[aid].empty())
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
86 items.erase(aid);
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
87 break;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
88 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
89 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
90
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
91 void Database::StaticEventHandler(void *opaque, const std::filesystem::path &path, Filesystem::IWatcher::Event event)
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
92 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
93 /* Forward to class function */
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
94 reinterpret_cast<Database *>(opaque)->EventHandler(path, event);
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
95 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
96
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
97 std::optional<std::filesystem::path> Database::GetAnimeFolder(int id)
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
98 {
366
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
99 // this function sucks, but it's the most I can really do for now.
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
100 //
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
101 // in the future the Refresh() function should look for directories
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
102 // as well that fit the anime name and *also* have episodes in them.
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
103 // it should give each of these directories a rating by how many
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
104 // episodes are contained in them. whichever directory has more episodes
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
105 // wins, or the first found if there is an equal amount.
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
106
409
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
107 /* TODO use a shared lock instead */
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
108 const std::lock_guard<std::recursive_mutex> lock(items_mutex_);
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
109
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
110 for (const auto &[anime_id, episodes] : items) {
366
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
111 if (id != anime_id)
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
112 continue;
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
113
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
114 for (const auto &[episode, path] : episodes)
366
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
115 return path.parent_path();
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
116
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
117 break;
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
118 }
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
119
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
120 return std::nullopt;
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
121 }
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
122
409
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
123 void Database::RefreshThread()
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
124 {
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
125 for (const auto &w : watchers_)
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
126 w.second->Process();
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
127 }
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
128
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
129 /* TODO the threading code for this could be better */
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
130 void Database::Refresh(std::optional<int> find_id)
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
131 {
409
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
132 /* Join the thread if it was already run */
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
133 if (refresh_thread_.joinable())
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
134 refresh_thread_.join();
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
135
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
136 /* This is terrible */
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
137 find_id_ = find_id;
222
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
138
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 369
diff changeset
139 UpdateWatchers();
222
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
140
409
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
141 refresh_thread_ = std::thread(&Database::RefreshThread, this);
222
b9f111d84d95 *: move to semver, remove old macos build, add library files
Paper <paper@paper.us.eu.org>
parents:
diff changeset
142 }
223
84e0a3c4737a library: implement menu bar buttons
Paper <mrpapersonic@gmail.com>
parents: 222
diff changeset
143
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
144 void Database::Refresh()
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
145 {
366
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
146 Refresh(std::nullopt);
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
147 }
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
148
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
149 void Database::Refresh(int id)
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 366
diff changeset
150 {
366
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
151 Refresh(std::optional<int>(id));
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
152 }
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
153
409
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
154 std::optional<std::filesystem::path> Database::GetAnimeEpisodePath(int anime, int episode)
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
155 {
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
156 const std::lock_guard<std::recursive_mutex> lock(items_mutex_);
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
157
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
158 if (items.find(anime) == items.end() || items[anime].find(episode) == items[anime].end())
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
159 return std::nullopt;
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
160
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
161 return items[anime][episode];
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
162 }
8d06825d96d1 library: refresh in a separate thread
Paper <paper@tflc.us>
parents: 398
diff changeset
163
383
27c462bc7815 make the "Now Playing" page actually work
Paper <paper@tflc.us>
parents: 382
diff changeset
164 // TODO export to JSON on exit
366
886f66775f31 animone: add preliminary AT-SPI stuff
Paper <paper@tflc.us>
parents: 347
diff changeset
165
328
71396ecb6f7e library: convert to class + database
Paper <paper@paper.us.eu.org>
parents: 319
diff changeset
166 Database db;
71396ecb6f7e library: convert to class + database
Paper <paper@paper.us.eu.org>
parents: 319
diff changeset
167
258
862d0d8619f6 *: HUUUGE changes
Paper <paper@paper.us.eu.org>
parents: 228
diff changeset
168 } // namespace Library