From 3c7edb80d0663365c5828b95bf909af87bad857d Mon Sep 17 00:00:00 2001 From: XFFXFF <1247714429@qq.com> Date: Mon, 15 May 2023 00:20:43 +0000 Subject: [PATCH 01/52] refactor: reduce connections created with RedisCache --- .gitignore | 2 ++ src/cache/cacher.rs | 36 ++++++++++++++++-------------------- src/server/routes.rs | 12 +++++------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index ea8c4bf..c39800b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target + +dump.rdb \ No newline at end of file diff --git a/src/cache/cacher.rs b/src/cache/cacher.rs index 54d9a48..87a6c6d 100644 --- a/src/cache/cacher.rs +++ b/src/cache/cacher.rs @@ -10,9 +10,8 @@ use redis::{Client, Commands, Connection}; /// # Fields /// /// * `redis_connection_url` - It stores the redis Connection url address. -#[derive(Clone)] pub struct RedisCache { - redis_connection_url: String, + connection: Connection, } impl RedisCache { @@ -21,10 +20,11 @@ impl RedisCache { /// # Arguments /// /// * `redis_connection_url` - It stores the redis Connection url address. - pub fn new(redis_connection_url: String) -> Self { - RedisCache { - redis_connection_url, - } + pub fn new(redis_connection_url: String) -> Result> { + let client = Client::open(redis_connection_url)?; + let connection = client.get_connection()?; + let redis_cache = RedisCache { connection }; + Ok(redis_cache) } /// A helper function which computes the hash of the url and formats and returns it as string. @@ -32,7 +32,7 @@ impl RedisCache { /// # Arguments /// /// * `url` - It takes an url as string. - fn compute_url_hash(self, url: &str) -> String { + fn compute_url_hash(url: &str) -> String { format!("{:?}", compute(url)) } @@ -41,11 +41,9 @@ impl RedisCache { /// # Arguments /// /// * `url` - It takes an url as a string. - pub fn cached_results_json(self, url: String) -> Result> { - let hashed_url_string = self.clone().compute_url_hash(&url); - let mut redis_connection: Connection = - Client::open(self.redis_connection_url)?.get_connection()?; - Ok(redis_connection.get(hashed_url_string)?) + pub fn cached_results_json(&mut self, url: &str) -> Result> { + let hashed_url_string = Self::compute_url_hash(url); + Ok(self.connection.get(hashed_url_string)?) } /// A function which caches the results by using the hashed `url` as the key and @@ -57,20 +55,18 @@ impl RedisCache { /// * `json_results` - It takes the json results string as an argument. /// * `url` - It takes the url as a String. pub fn cache_results( - self, + &mut self, json_results: String, - url: String, + url: &str, ) -> Result<(), Box> { - let hashed_url_string = self.clone().compute_url_hash(&url); - let mut redis_connection: Connection = - Client::open(self.redis_connection_url)?.get_connection()?; + let hashed_url_string = Self::compute_url_hash(url); // put results_json into cache - redis_connection.set(hashed_url_string.clone(), json_results)?; + self.connection.set(&hashed_url_string, json_results)?; // Set the TTL for the key to 60 seconds - redis_connection - .expire::(hashed_url_string.clone(), 60) + self.connection + .expire::(hashed_url_string, 60) .unwrap(); Ok(()) diff --git a/src/server/routes.rs b/src/server/routes.rs index 1ee9f35..e97bc2b 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -73,7 +73,7 @@ pub async fn search( let params = web::Query::::from_query(req.query_string())?; //Initialize redis cache connection struct - let redis_cache = RedisCache::new(config.redis_connection_url.clone()); + let mut redis_cache = RedisCache::new(config.redis_connection_url.clone())?; match ¶ms.q { Some(query) => { if query.trim().is_empty() { @@ -117,7 +117,7 @@ pub async fn search( }; // fetch the cached results json. - let cached_results_json = redis_cache.clone().cached_results_json(page_url.clone()); + let cached_results_json = redis_cache.cached_results_json(&page_url); // check if fetched results was indeed fetched or it was an error and if so // handle the data accordingly. match cached_results_json { @@ -128,12 +128,10 @@ pub async fn search( } Err(_) => { let mut results_json: crate::search_results_handler::aggregation_models::SearchResults = - aggregate(query, page).await?; + aggregate(query, page).await?; results_json.add_style(config.style.clone()); - redis_cache.clone().cache_results( - serde_json::to_string(&results_json)?, - page_url.clone(), - )?; + redis_cache + .cache_results(serde_json::to_string(&results_json)?, &page_url)?; let page_content: String = hbs.render("search", &results_json)?; Ok(HttpResponse::Ok().body(page_content)) } From 2fc3ab42fe849af780a61d10cafe4b74bdda9663 Mon Sep 17 00:00:00 2001 From: B C SAMRUDH <114090255+bcsamrudh@users.noreply.github.com> Date: Wed, 17 May 2023 22:53:10 +0530 Subject: [PATCH 02/52] Added an about page. --- public/templates/about.html | 39 +++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/public/templates/about.html b/public/templates/about.html index 56c2165..9c4cbb0 100644 --- a/public/templates/about.html +++ b/public/templates/about.html @@ -1,20 +1,29 @@ {{>header this}}
-

Websurfx

- a lightening fast, privacy respecting, secure meta search engine -
- Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim - labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. - Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum - Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident. - Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex - occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat - officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in - Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non - excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco ut - ea consectetur et est culpa et culpa duis. +
+
+

Websurfx

+
+
+

A modern-looking, lightning-fast, privacy-respecting, secure meta search engine written in Rust. It provides a fast and secure search experience while respecting user privacy.
It aggregates results from multiple search engines and presents them in an unbiased manner, filtering out trackers and ads. +

+ +

Some of the Top Features:

+ +
    Lightning fast - Results load within milliseconds for an instant search experience.
+ +
    Secure search - All searches are performed over an encrypted connection to prevent snooping.
+ +
    Ad free results - All search results are ad free and clutter free for a clean search experience.
+ +
    Privacy focused - Websurface does not track, store or sell your search data. Your privacy is our priority.
+ +
    Free and Open source - The entire project's code is open source and available for free on GitHub under an GNU Affero General Public License.
+ +
    Highly customizable - Websurface comes with 9 built-in color themes and supports creating custom themes effortlessly.
+ +

Devoloped by: Websurfx team

{{>footer}} + From 0a947cd400878658a40cdd4bdbfe91fb36305e56 Mon Sep 17 00:00:00 2001 From: B C SAMRUDH <114090255+bcsamrudh@users.noreply.github.com> Date: Wed, 17 May 2023 22:54:16 +0530 Subject: [PATCH 03/52] Added the CSS code for about.html --- public/static/themes/simple.css | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/public/static/themes/simple.css b/public/static/themes/simple.css index 97643e8..b9390e7 100644 --- a/public/static/themes/simple.css +++ b/public/static/themes/simple.css @@ -260,3 +260,40 @@ footer { .page_navigation button:active { filter: brightness(1.2); } + +/* Styles for the about page */ + + .about-container article{ + font-size: 1.5rem; + color:var(--fg); + padding-bottom: 10px; + } + + .about-container article h1{ + color: var(--2); + font-size: 2.8rem; + } + + .about-container article div{ + padding-bottom: 15px; + } + + .about-container a{ + color:var(--3); + } + + .about-container article h2{ + color: var(--3); + font-size: 1.8rem; + padding-bottom: 10px; + } + + .about-container p{ + color:var(--fg); + font-size: 1.6rem; + padding-bottom: 10px; + } + + .about-container h3{ + font-size: 1.5rem; + } From 85e5868ac38fcf2516705c033677e695f22b79e3 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Thu, 18 May 2023 10:12:51 +0000 Subject: [PATCH 04/52] ci: remove releases automation github action --- .github/workflows/releases.yml | 74 ---------------------------------- 1 file changed, 74 deletions(-) delete mode 100644 .github/workflows/releases.yml diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml deleted file mode 100644 index e46c5aa..0000000 --- a/.github/workflows/releases.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Releases -on: - push: - branches: - - "rolling" - -concurrency: - group: "rolling-branch" - -jobs: - changelog: - if: github.repository == 'neon-mmd/websurfx' - runs-on: ubuntu-latest - - steps: - # Create a temporary, uniquely named branch to push release info to - - name: create temporary branch - uses: peterjgrainger/action-create-branch@v2.3.0 - id: create-branch - with: - branch: "release-from-${{ github.sha }}" - sha: "${{ github.sha }}" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # check out the repository afterwards - - uses: actions/checkout@v3 - - # fetch branches and switch to the temporary branch - - name: switch to new branch - run: git fetch --all && git checkout --track origin/release-from-${{ github.sha }} - - # update app config with version - - name: get-npm-version - id: package-version - uses: martinbeentjes/npm-get-version-action@master - - name: update app config - run: sed -i 's/0.0.0/${{ steps.package-version.outputs.current-version}}/g' config/app.json - - # create release info and push it upstream - - name: conventional Changelog Action - id: changelog - uses: TriPSs/conventional-changelog-action@v3 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - version-file: "./Cargo.toml" - git-branch: "release-from-${{ github.sha }}" - skip-on-empty: false - skip-git-pull: true - - # create PR using GitHub CLI - - name: create PR with release info - id: create-pr - run: gh pr create --base main --head release-from-${{ github.sha }} --title 'Merge new release into rolling' --body 'Created by Github action' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # merge PR using GitHub CLI - - name: merge PR with release info - id: merge-pr - run: gh pr merge --admin --merge --subject 'Merge release info' --delete-branch - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # release info is now in main so we can continue as before - - name: create release with last commit - uses: actions/create-release@v1 - if: steps.changelog.outputs.skipped == 'false' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.changelog.outputs.tag }} - release_name: ${{ steps.changelog.outputs.tag }} - body: ${{ steps.changelog.outputs.clean_changelog }} From 9a204b2f985c29020d8a177ed2894b98a1b4adc5 Mon Sep 17 00:00:00 2001 From: MD AL AMIN TALUKDAR <129589283+alamin655@users.noreply.github.com> Date: Fri, 19 May 2023 17:13:11 +0530 Subject: [PATCH 05/52] Fix page_url assignment in search route The page_url variable in the search route was not being properly assigned in certain cases. This commit fixes the issue by ensuring that page_url is assigned the correct value based on the search parameters. In the match expression, the conditions have been adjusted to correctly handle the page number and construct the appropriate page_url. This ensures that the generated URL for the search page is accurate and reflects the search query and page number. This change improves the functionality and reliability of the search route by correctly setting the page_url variable based on the provided search parameters. --- src/server/routes.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/server/routes.rs b/src/server/routes.rs index e97bc2b..5116bac 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -81,11 +81,10 @@ pub async fn search( .insert_header(("location", "/")) .finish()) } else { - // Initialize the page url as an empty string - let mut page_url = String::new(); + let page_url: String; // Declare the page_url variable without initializing it - // Find whether the page is valid page number if not then return - // the first page number and also construct the page_url accordingly + // ... + let page = match params.page { Some(page_number) => { if page_number <= 1 { @@ -99,7 +98,7 @@ pub async fn search( "http://{}:{}/search?q={}&page={}", config.binding_ip_addr, config.port, query, page_number ); - + page_number } } @@ -111,11 +110,13 @@ pub async fn search( req.uri(), 1 ); - + 1 } }; - + + // Use the page_url variable as needed + // fetch the cached results json. let cached_results_json = redis_cache.cached_results_json(&page_url); // check if fetched results was indeed fetched or it was an error and if so From ae2fdb557cd801a833e2e2c85b1dea14edd5e7c4 Mon Sep 17 00:00:00 2001 From: MD AL AMIN TALUKDAR <129589283+alamin655@users.noreply.github.com> Date: Sat, 20 May 2023 08:01:24 +0530 Subject: [PATCH 06/52] Removed unnecessary comment --- src/server/routes.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/server/routes.rs b/src/server/routes.rs index 5116bac..ed2299f 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -114,9 +114,7 @@ pub async fn search( 1 } }; - - // Use the page_url variable as needed - + // fetch the cached results json. let cached_results_json = redis_cache.cached_results_json(&page_url); // check if fetched results was indeed fetched or it was an error and if so From 6e19246cb2a02f06d6e2ca3851d78b2f01f7bdb0 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Mon, 22 May 2023 13:07:37 +0300 Subject: [PATCH 07/52] fix: reduce the time to build user-agents --- Cargo.lock | 1 + Cargo.toml | 1 + src/search_results_handler/user_agent.rs | 20 +++++++++++--------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85310e9..cec7cf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3328,6 +3328,7 @@ dependencies = [ "handlebars", "log", "md5", + "once_cell", "rand 0.8.5", "redis", "reqwest 0.11.17", diff --git a/Cargo.toml b/Cargo.toml index ce99ca3..efe9435 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ rlua = {version="*"} redis = {version="*"} md5 = {version="*"} rand={version="*"} +once_cell = {version="*"} diff --git a/src/search_results_handler/user_agent.rs b/src/search_results_handler/user_agent.rs index 09dd684..13166bf 100644 --- a/src/search_results_handler/user_agent.rs +++ b/src/search_results_handler/user_agent.rs @@ -1,13 +1,8 @@ //! This module provides the functionality to generate random user agent string. -use fake_useragent::{Browsers, UserAgentsBuilder}; +use fake_useragent::{Browsers, UserAgents, UserAgentsBuilder}; -/// A function to generate random user agent to improve privacy of the user. -/// -/// # Returns -/// -/// A randomly generated user agent string. -pub fn random_user_agent() -> String { +static USER_AGENTS: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| { UserAgentsBuilder::new() .cache(false) .dir("/tmp") @@ -21,6 +16,13 @@ pub fn random_user_agent() -> String { .set_mozilla(), ) .build() - .random() - .to_string() +}); + +/// A function to generate random user agent to improve privacy of the user. +/// +/// # Returns +/// +/// A randomly generated user agent string. +pub fn random_user_agent() -> String { + USER_AGENTS.random().to_string() } From ab20f08e42251dbb052ec5aa08534187d8283f03 Mon Sep 17 00:00:00 2001 From: gotoworq <110043355+gotoworq@users.noreply.github.com> Date: Mon, 22 May 2023 14:44:46 -0400 Subject: [PATCH 08/52] Added logo, and changed logon to be on main page --- public/images/websurfx_logo.png | Bin 0 -> 8264 bytes public/templates/index.html | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 public/images/websurfx_logo.png diff --git a/public/images/websurfx_logo.png b/public/images/websurfx_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9449e33ff4400ee97da4186599ead26e0ead74a7 GIT binary patch literal 8264 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 this}}
- Websurfx meta-search engine logo + Websurfx meta-search engine logo {{>search_bar}}
From ff325153f06dbcb18c78a30dbf6c076996f75d7a Mon Sep 17 00:00:00 2001 From: XFFXFF <1247714429@qq.com> Date: Tue, 23 May 2023 00:31:46 +0000 Subject: [PATCH 09/52] add format and clippy checks to the CI jobs --- .github/workflows/rust_format.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust_format.yml b/.github/workflows/rust_format.yml index d865c8c..c300863 100644 --- a/.github/workflows/rust_format.yml +++ b/.github/workflows/rust_format.yml @@ -19,7 +19,16 @@ jobs: profile: minimal toolchain: stable components: rustfmt, clippy - + - name: Format + uses: actions-rs/cargo@v1 + with: + command: fmt + args: -- --check + - name: Clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-features --all-targets --all - name: Run cargo check uses: actions-rs/cargo@v1 with: From cecffe41555d76ed254ead5a7cebf277e6b98172 Mon Sep 17 00:00:00 2001 From: XFFXFF <1247714429@qq.com> Date: Tue, 23 May 2023 09:34:46 +0000 Subject: [PATCH 10/52] make format happy --- src/cache/mod.rs | 2 +- src/search_results_handler/aggregation_models.rs | 2 +- src/server/routes.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 91a91ca..de7dd4e 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -1 +1 @@ -pub mod cacher; +pub mod cacher; diff --git a/src/search_results_handler/aggregation_models.rs b/src/search_results_handler/aggregation_models.rs index 4fe670e..b6e6b81 100644 --- a/src/search_results_handler/aggregation_models.rs +++ b/src/search_results_handler/aggregation_models.rs @@ -116,7 +116,7 @@ impl RawSearchResult { } } -/// A named struct to store, serialize, deserialize the all the search results scraped and +/// A named struct to store, serialize, deserialize the all the search results scraped and /// aggregated from the upstream search engines. /// /// # Fields diff --git a/src/server/routes.rs b/src/server/routes.rs index ed2299f..85c522d 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -81,10 +81,10 @@ pub async fn search( .insert_header(("location", "/")) .finish()) } else { - let page_url: String; // Declare the page_url variable without initializing it + let page_url: String; // Declare the page_url variable without initializing it // ... - + let page = match params.page { Some(page_number) => { if page_number <= 1 { @@ -98,7 +98,7 @@ pub async fn search( "http://{}:{}/search?q={}&page={}", config.binding_ip_addr, config.port, query, page_number ); - + page_number } } @@ -110,11 +110,11 @@ pub async fn search( req.uri(), 1 ); - + 1 } }; - + // fetch the cached results json. let cached_results_json = redis_cache.cached_results_json(&page_url); // check if fetched results was indeed fetched or it was an error and if so From 05272884bac1e6068f58180e964227126b9f9067 Mon Sep 17 00:00:00 2001 From: XFFXFF <1247714429@qq.com> Date: Mon, 22 May 2023 01:13:06 +0000 Subject: [PATCH 11/52] supports the option to add a random delay --- src/config_parser/parser.rs | 13 +++++++++++++ src/search_results_handler/aggregator.rs | 10 +++++++--- src/server/routes.rs | 2 +- websurfx/config.lua | 5 +++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/config_parser/parser.rs b/src/config_parser/parser.rs index 4625bd8..21a9bf5 100644 --- a/src/config_parser/parser.rs +++ b/src/config_parser/parser.rs @@ -20,6 +20,14 @@ pub struct Config { pub binding_ip_addr: String, pub style: Style, pub redis_connection_url: String, + pub aggregator: AggreatorConfig, +} + +/// Configuration options for the aggregator. +#[derive(Clone)] +pub struct AggreatorConfig { + /// Whether to introduce a random delay before sending the request to the search engine. + pub random_delay: bool, } impl Config { @@ -41,6 +49,8 @@ impl Config { .load(&fs::read_to_string("./websurfx/config.lua")?) .exec()?; + let aggregator_config = globals.get::<_, rlua::Table>("aggregator")?; + Ok(Config { port: globals.get::<_, u16>("port")?, binding_ip_addr: globals.get::<_, String>("binding_ip_addr")?, @@ -49,6 +59,9 @@ impl Config { globals.get::<_, String>("colorscheme")?, ), redis_connection_url: globals.get::<_, String>("redis_connection_url")?, + aggregator: AggreatorConfig { + random_delay: aggregator_config.get::<_, bool>("random_delay")?, + }, }) }) } diff --git a/src/search_results_handler/aggregator.rs b/src/search_results_handler/aggregator.rs index 5133094..8b86972 100644 --- a/src/search_results_handler/aggregator.rs +++ b/src/search_results_handler/aggregator.rs @@ -29,6 +29,7 @@ use crate::engines::{duckduckgo, searx}; /// /// * `query` - Accepts a string to query with the above upstream search engines. /// * `page` - Accepts an u32 page number. +/// * `random_delay` - Accepts a boolean value to add a random delay before making the request. /// /// # Error /// @@ -38,14 +39,17 @@ use crate::engines::{duckduckgo, searx}; pub async fn aggregate( query: &str, page: u32, + random_delay: bool, ) -> Result> { let user_agent: String = random_user_agent(); let mut result_map: HashMap = HashMap::new(); // Add a random delay before making the request. - let mut rng = rand::thread_rng(); - let delay_secs = rng.gen_range(1..10); - std::thread::sleep(Duration::from_secs(delay_secs)); + if random_delay { + let mut rng = rand::thread_rng(); + let delay_secs = rng.gen_range(1..10); + std::thread::sleep(Duration::from_secs(delay_secs)); + } // fetch results from upstream search engines simultaneously/concurrently. let (ddg_map_results, searx_map_results) = join!( diff --git a/src/server/routes.rs b/src/server/routes.rs index 85c522d..0f84cc9 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -127,7 +127,7 @@ pub async fn search( } Err(_) => { let mut results_json: crate::search_results_handler::aggregation_models::SearchResults = - aggregate(query, page).await?; + aggregate(query, page, config.aggregator.random_delay).await?; results_json.add_style(config.style.clone()); redis_cache .cache_results(serde_json::to_string(&results_json)?, &page_url)?; diff --git a/websurfx/config.lua b/websurfx/config.lua index 916a9b3..7dfd515 100644 --- a/websurfx/config.lua +++ b/websurfx/config.lua @@ -19,3 +19,8 @@ theme = "simple" -- the theme name which should be used for the website -- Caching redis_connection_url = "redis://127.0.0.1:8082" -- redis connection url address on which the client should connect on. + +-- Aggregator +aggregator = { + random_delay = false, -- whether to add random delay before sending the request to the search engine +} \ No newline at end of file From 9773cee38dd312696bd17168e5758176a5563b8e Mon Sep 17 00:00:00 2001 From: XFFXFF <1247714429@qq.com> Date: Tue, 23 May 2023 00:56:44 +0000 Subject: [PATCH 12/52] change the 'aggregator' option to 'production_use' --- src/config_parser/parser.rs | 15 +++++++++++---- websurfx/config.lua | 7 +++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/config_parser/parser.rs b/src/config_parser/parser.rs index 21a9bf5..4b73a73 100644 --- a/src/config_parser/parser.rs +++ b/src/config_parser/parser.rs @@ -49,7 +49,16 @@ impl Config { .load(&fs::read_to_string("./websurfx/config.lua")?) .exec()?; - let aggregator_config = globals.get::<_, rlua::Table>("aggregator")?; + let production_use = globals.get::<_, bool>("production_use")?; + let aggregator_config = if production_use { + AggreatorConfig { + random_delay: true, + } + } else { + AggreatorConfig { + random_delay: false, + } + }; Ok(Config { port: globals.get::<_, u16>("port")?, @@ -59,9 +68,7 @@ impl Config { globals.get::<_, String>("colorscheme")?, ), redis_connection_url: globals.get::<_, String>("redis_connection_url")?, - aggregator: AggreatorConfig { - random_delay: aggregator_config.get::<_, bool>("random_delay")?, - }, + aggregator: aggregator_config }) }) } diff --git a/websurfx/config.lua b/websurfx/config.lua index 7dfd515..1c0be7d 100644 --- a/websurfx/config.lua +++ b/websurfx/config.lua @@ -20,7 +20,6 @@ theme = "simple" -- the theme name which should be used for the website -- Caching redis_connection_url = "redis://127.0.0.1:8082" -- redis connection url address on which the client should connect on. --- Aggregator -aggregator = { - random_delay = false, -- whether to add random delay before sending the request to the search engine -} \ No newline at end of file +production_use = false -- whether to use production mode or not +-- if production_use is set to true + -- there will be a random delay before sending the request to the search engines, this is to prevent the search engines from blocking the ip address \ No newline at end of file From 4b70a74ff6196a00d8878333ab4b56b065427230 Mon Sep 17 00:00:00 2001 From: zhou fan <1247714429@qq.com> Date: Tue, 23 May 2023 17:30:36 +0800 Subject: [PATCH 13/52] Update websurfx/config.lua Co-authored-by: neon_arch --- websurfx/config.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/websurfx/config.lua b/websurfx/config.lua index 1c0be7d..c30f376 100644 --- a/websurfx/config.lua +++ b/websurfx/config.lua @@ -20,6 +20,6 @@ theme = "simple" -- the theme name which should be used for the website -- Caching redis_connection_url = "redis://127.0.0.1:8082" -- redis connection url address on which the client should connect on. -production_use = false -- whether to use production mode or not +production_use = false -- whether to use production mode or not (in other words this option should be used if it is to be used to host it on the server to provide a service to a large number of users) -- if production_use is set to true - -- there will be a random delay before sending the request to the search engines, this is to prevent the search engines from blocking the ip address \ No newline at end of file + -- There will be a random delay before sending the request to the search engines, this is to prevent DDoSing the upstream search engines from a large number of simultaneous requests. \ No newline at end of file From ea013e718edae23136befa9609100960431ab5f4 Mon Sep 17 00:00:00 2001 From: XFFXFF <1247714429@qq.com> Date: Tue, 23 May 2023 10:00:35 +0000 Subject: [PATCH 14/52] make format happy --- src/config_parser/parser.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/config_parser/parser.rs b/src/config_parser/parser.rs index 4b73a73..f8dac14 100644 --- a/src/config_parser/parser.rs +++ b/src/config_parser/parser.rs @@ -51,9 +51,7 @@ impl Config { let production_use = globals.get::<_, bool>("production_use")?; let aggregator_config = if production_use { - AggreatorConfig { - random_delay: true, - } + AggreatorConfig { random_delay: true } } else { AggreatorConfig { random_delay: false, @@ -68,7 +66,7 @@ impl Config { globals.get::<_, String>("colorscheme")?, ), redis_connection_url: globals.get::<_, String>("redis_connection_url")?, - aggregator: aggregator_config + aggregator: aggregator_config, }) }) } From 89796a054f0b0b9535e40d13e4a4effc242737e6 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Tue, 23 May 2023 23:47:36 +0300 Subject: [PATCH 15/52] feat: add ability to put config file on different paths --- src/config_parser/parser.rs | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/config_parser/parser.rs b/src/config_parser/parser.rs index 4625bd8..66a9284 100644 --- a/src/config_parser/parser.rs +++ b/src/config_parser/parser.rs @@ -3,7 +3,7 @@ use super::parser_models::Style; use rlua::Lua; -use std::fs; +use std::{format, fs, path::Path}; /// A named struct which stores the parsed config file options. /// @@ -32,13 +32,13 @@ impl Config { /// or io error if the config.lua file doesn't exists otherwise it returns a newly contructed /// Config struct with all the parsed config options from the parsed config file. pub fn parse() -> Result> { - let lua = Lua::new(); - - lua.context(|context| { + Lua::new().context(|context| -> Result> { let globals = context.globals(); context - .load(&fs::read_to_string("./websurfx/config.lua")?) + .load(&fs::read_to_string( + Config::handle_different_config_file_path()?, + )?) .exec()?; Ok(Config { @@ -52,4 +52,38 @@ impl Config { }) }) } + /// A helper function which returns an appropriate config file path checking if the config + /// file exists on that path. + /// + /// # Error + /// + /// Returns a `config file not found!!` error if the config file is not present under following + /// paths which are: + /// 1. `~/.config/websurfx/` if it not present here then it fallbacks to the next one (2) + /// 2. `/etc/xdg/websurfx/config.lua` if it is not present here then it fallbacks to the next + /// one (3). + /// 3. `websurfx/` (under project folder ( or codebase in other words)) if it is not present + /// here then it returns an error as mentioned above. + fn handle_different_config_file_path() -> Result> { + if Path::new( + format!( + "{}/.config/websurfx/config.lua", + std::env::var("HOME").unwrap() + ) + .as_str(), + ) + .exists() + { + Ok(format!( + "{}/.config/websurfx/config.lua", + std::env::var("HOME").unwrap() + )) + } else if Path::new("/etc/xdg/websurfx/config.lua").exists() { + Ok("/etc/xdg/websurfx/config.lua".to_string()) + } else if Path::new("./websurfx/config.lua").exists() { + Ok("./websurfx/config.lua".to_string()) + } else { + Err(format!("Config file not found!!").into()) + } + } } From c5b62f1087781b0e98dcbe03d4ca155d08ffedf9 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Wed, 24 May 2023 10:50:08 +0300 Subject: [PATCH 16/52] chore: Bump version to v0.8.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index efe9435..d19acb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "websurfx" -version = "0.6.0" +version = "0.8.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From ea3f21139f3fcd25d2915838ffc83b5bf4ea3566 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Wed, 24 May 2023 11:53:40 +0300 Subject: [PATCH 17/52] chore: fix the lock error during build --- Cargo.lock | 194 ++++++++++++++++++++++++++--------------------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cec7cf7..02bf14f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,19 @@ version = 3 [[package]] name = "actix-codec" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ "bitflags", "bytes 1.4.0", "futures-core", "futures-sink", - "log", "memchr", "pin-project-lite", - "tokio 1.28.0", + "tokio 1.28.1", "tokio-util", + "tracing", ] [[package]] @@ -53,7 +53,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash 0.8.3", - "base64 0.21.0", + "base64 0.21.1", "bitflags", "brotli", "bytes 1.4.0", @@ -62,7 +62,7 @@ dependencies = [ "encoding_rs", "flate2", "futures-core", - "h2 0.3.18", + "h2 0.3.19", "http 0.2.9", "httparse", "httpdate", @@ -75,7 +75,7 @@ dependencies = [ "rand 0.8.5", "sha1", "smallvec 1.10.0", - "tokio 1.28.0", + "tokio 1.28.1", "tokio-util", "tracing", "zstd", @@ -111,7 +111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" dependencies = [ "futures-core", - "tokio 1.28.0", + "tokio 1.28.1", ] [[package]] @@ -128,7 +128,7 @@ dependencies = [ "mio 0.8.6", "num_cpus", "socket2", - "tokio 1.28.0", + "tokio 1.28.1", "tracing", ] @@ -201,7 +201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" dependencies = [ "actix-router", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "syn 1.0.109", ] @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" [[package]] name = "bit-set" @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -605,7 +605,7 @@ dependencies = [ "itoa 1.0.6", "matches", "phf 0.10.1", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "smallvec 1.10.0", "syn 1.0.109", @@ -628,7 +628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "rustc_version 0.4.0", "syn 1.0.109", @@ -636,9 +636,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -730,7 +730,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "syn 1.0.109", "synstructure", @@ -959,9 +959,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes 1.4.0", "fnv", @@ -971,16 +971,16 @@ dependencies = [ "http 0.2.9", "indexmap", "slab", - "tokio 1.28.0", + "tokio 1.28.1", "tokio-util", "tracing", ] [[package]] name = "handlebars" -version = "4.3.6" +version = "4.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" +checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d" dependencies = [ "log", "pest", @@ -1035,7 +1035,7 @@ dependencies = [ "log", "mac", "markup5ever 0.11.0", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "syn 1.0.109", ] @@ -1149,7 +1149,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.18", + "h2 0.3.19", "http 0.2.9", "http-body 0.4.5", "httparse", @@ -1157,7 +1157,7 @@ dependencies = [ "itoa 1.0.6", "pin-project-lite", "socket2", - "tokio 1.28.0", + "tokio 1.28.1", "tower-service", "tracing", "want 0.3.0", @@ -1185,7 +1185,7 @@ dependencies = [ "bytes 1.4.0", "hyper 0.14.26", "native-tls", - "tokio 1.28.0", + "tokio 1.28.1", "tokio-native-tls", ] @@ -1301,9 +1301,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.62" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -1338,9 +1338,9 @@ checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "local-channel" @@ -1631,9 +1631,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -1749,9 +1749,9 @@ checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -1863,7 +1863,7 @@ dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", "proc-macro-hack", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "syn 1.0.109", ] @@ -1942,9 +1942,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" dependencies = [ "unicode-ident", ] @@ -1974,7 +1974,7 @@ version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", ] [[package]] @@ -2213,9 +2213,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" dependencies = [ "aho-corasick", "memchr", @@ -2224,9 +2224,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" @@ -2264,16 +2264,16 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.17" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64 0.21.0", + "base64 0.21.1", "bytes 1.4.0", "encoding_rs", "futures-core", "futures-util", - "h2 0.3.18", + "h2 0.3.19", "http 0.2.9", "http-body 0.4.5", "hyper 0.14.26", @@ -2289,7 +2289,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded 0.7.1", - "tokio 1.28.0", + "tokio 1.28.1", "tokio-native-tls", "tower-service", "url 2.3.1", @@ -2410,9 +2410,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.8.2" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ "bitflags", "core-foundation", @@ -2423,9 +2423,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" dependencies = [ "core-foundation-sys", "libc", @@ -2482,22 +2482,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2680,7 +2680,7 @@ checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6" dependencies = [ "phf_generator 0.7.24", "phf_shared 0.7.24", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "string_cache_shared", ] @@ -2693,7 +2693,7 @@ checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", ] @@ -2720,18 +2720,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "unicode-ident", ] @@ -2742,7 +2742,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", "syn 1.0.109", "unicode-xid 0.2.4", @@ -2796,9 +2796,9 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2875,9 +2875,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.28.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" dependencies = [ "autocfg 1.1.0", "bytes 1.4.0", @@ -2940,9 +2940,9 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2952,7 +2952,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio 1.28.0", + "tokio 1.28.1", ] [[package]] @@ -3037,7 +3037,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", - "tokio 1.28.0", + "tokio 1.28.1", "tracing", ] @@ -3061,9 +3061,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] @@ -3243,9 +3243,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -3253,24 +3253,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.15", + "syn 2.0.16", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.35" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "083abe15c5d88556b77bdf7aef403625be9e327ad37c62c4e4129af740168163" +checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -3280,9 +3280,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote 1.0.27", "wasm-bindgen-macro-support", @@ -3290,28 +3290,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.58", "quote 1.0.27", - "syn 2.0.15", + "syn 2.0.16", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "web-sys" -version = "0.3.62" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", @@ -3319,7 +3319,7 @@ dependencies = [ [[package]] name = "websurfx" -version = "0.6.0" +version = "0.8.0" dependencies = [ "actix-files", "actix-web", @@ -3331,12 +3331,12 @@ dependencies = [ "once_cell", "rand 0.8.5", "redis", - "reqwest 0.11.17", + "reqwest 0.11.18", "rlua", "scraper", "serde", "serde_json", - "tokio 1.28.0", + "tokio 1.28.1", ] [[package]] From a7a28ed8c64d54c7f47a53106032d49c2aeef058 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Wed, 24 May 2023 12:01:36 +0300 Subject: [PATCH 18/52] chore: make websurfx directory and config file names as constants --- src/config_parser/parser.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/config_parser/parser.rs b/src/config_parser/parser.rs index 66a9284..bbeba86 100644 --- a/src/config_parser/parser.rs +++ b/src/config_parser/parser.rs @@ -5,6 +5,10 @@ use super::parser_models::Style; use rlua::Lua; use std::{format, fs, path::Path}; +// ------- Constants -------- +static COMMON_DIRECTORY_NAME: &str = "websurfx"; +static CONFIG_FILE_NAME: &str = "config.lua"; + /// A named struct which stores the parsed config file options. /// /// # Fields @@ -67,20 +71,29 @@ impl Config { fn handle_different_config_file_path() -> Result> { if Path::new( format!( - "{}/.config/websurfx/config.lua", - std::env::var("HOME").unwrap() + "{}/.config/{}/config.lua", + std::env::var("HOME").unwrap(), + COMMON_DIRECTORY_NAME ) .as_str(), ) .exists() { Ok(format!( - "{}/.config/websurfx/config.lua", - std::env::var("HOME").unwrap() + "{}/.config/{}/{}", + std::env::var("HOME").unwrap(), + COMMON_DIRECTORY_NAME, + CONFIG_FILE_NAME )) - } else if Path::new("/etc/xdg/websurfx/config.lua").exists() { + } else if Path::new( + format!("/etc/xdg/{}/{}", COMMON_DIRECTORY_NAME, CONFIG_FILE_NAME).as_str(), + ) + .exists() + { Ok("/etc/xdg/websurfx/config.lua".to_string()) - } else if Path::new("./websurfx/config.lua").exists() { + } else if Path::new(format!("./{}/{}", COMMON_DIRECTORY_NAME, CONFIG_FILE_NAME).as_str()) + .exists() + { Ok("./websurfx/config.lua".to_string()) } else { Err(format!("Config file not found!!").into()) From 29456650f1c86eb6bf690c92b3006ac8d1cfceb7 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Wed, 24 May 2023 17:37:41 +0300 Subject: [PATCH 19/52] feat: add ability to put the themes folder on different paths --- src/lib.rs | 16 ++++++++++--- src/server/routes.rs | 4 +++- src/theme_handler/mod.rs | 1 + src/theme_handler/theme_path_handler.rs | 31 +++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/theme_handler/mod.rs create mode 100644 src/theme_handler/theme_path_handler.rs diff --git a/src/lib.rs b/src/lib.rs index c234658..0763c96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub mod config_parser; pub mod engines; pub mod search_results_handler; pub mod server; +pub mod theme_handler; use std::net::TcpListener; @@ -15,6 +16,7 @@ use actix_files as fs; use actix_web::{dev::Server, middleware::Logger, web, App, HttpServer}; use config_parser::parser::Config; use handlebars::Handlebars; +use theme_handler::theme_path_handler::handle_different_theme_path; /// Runs the web server on the provided TCP listener and returns a `Server` instance. /// @@ -39,8 +41,10 @@ use handlebars::Handlebars; pub fn run(listener: TcpListener, config: Config) -> std::io::Result { let mut handlebars: Handlebars = Handlebars::new(); + let theme_folder_path: String = handle_different_theme_path()?; + handlebars - .register_templates_directory(".html", "./public/templates") + .register_templates_directory(".html", format!("{}/templates", theme_folder_path)) .unwrap(); let handlebars_ref: web::Data = web::Data::new(handlebars); @@ -51,8 +55,14 @@ pub fn run(listener: TcpListener, config: Config) -> std::io::Result { .app_data(web::Data::new(config.clone())) .wrap(Logger::default()) // added logging middleware for logging. // Serve images and static files (css and js files). - .service(fs::Files::new("/static", "./public/static").show_files_listing()) - .service(fs::Files::new("/images", "./public/images").show_files_listing()) + .service( + fs::Files::new("/static", format!("{}/static", theme_folder_path)) + .show_files_listing(), + ) + .service( + fs::Files::new("/images", format!("{}/images", theme_folder_path)) + .show_files_listing(), + ) .service(routes::robots_data) // robots.txt .service(routes::index) // index page .service(routes::search) // search page diff --git a/src/server/routes.rs b/src/server/routes.rs index 0f84cc9..bb6be27 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -8,6 +8,7 @@ use crate::{ cache::cacher::RedisCache, config_parser::parser::Config, search_results_handler::{aggregation_models::SearchResults, aggregator::aggregate}, + theme_handler::theme_path_handler::handle_different_theme_path, }; use actix_web::{get, web, HttpRequest, HttpResponse}; use handlebars::Handlebars; @@ -146,7 +147,8 @@ pub async fn search( /// Handles the route of robots.txt page of the `websurfx` meta search engine website. #[get("/robots.txt")] pub async fn robots_data(_req: HttpRequest) -> Result> { - let page_content: String = read_to_string("./public/robots.txt")?; + let page_content: String = + read_to_string(format!("{}/robots.txt", handle_different_theme_path()?))?; Ok(HttpResponse::Ok() .content_type("text/plain; charset=ascii") .body(page_content)) diff --git a/src/theme_handler/mod.rs b/src/theme_handler/mod.rs new file mode 100644 index 0000000..3bbca9d --- /dev/null +++ b/src/theme_handler/mod.rs @@ -0,0 +1 @@ +pub mod theme_path_handler; diff --git a/src/theme_handler/theme_path_handler.rs b/src/theme_handler/theme_path_handler.rs new file mode 100644 index 0000000..df3e5cc --- /dev/null +++ b/src/theme_handler/theme_path_handler.rs @@ -0,0 +1,31 @@ +//! This module provides the functionality to handle theme folder present on different paths and +//! provide one appropriate path on which it is present and can be used. + +use std::io::Error; +use std::path::Path; + +// ------- Constants -------- +static THEME_DIRECTORY_NAME: &str = "public"; + +/// A function which returns an appropriate theme directory path checking if the theme +/// directory exists on that path. +/// +/// # Error +/// +/// Returns a `Theme (public) folder not found!!` error if the theme folder is not present under following +/// paths which are: +/// 1. `/opt/websurfx` if it not present here then it fallbacks to the next one (2) +/// 2. Under project folder ( or codebase in other words) if it is not present +/// here then it returns an error as mentioned above. +pub fn handle_different_theme_path() -> Result { + if Path::new(format!("/opt/websurfx/{}/", THEME_DIRECTORY_NAME).as_str()).exists() { + Ok(format!("/opt/websurfx/{}", THEME_DIRECTORY_NAME)) + } else if Path::new(format!("./{}/", THEME_DIRECTORY_NAME).as_str()).exists() { + Ok(format!("./{}", THEME_DIRECTORY_NAME)) + } else { + Err(Error::new( + std::io::ErrorKind::NotFound, + "Themes (public) folder not found!!", + )) + } +} From 42feda0c460fa47d0adf2553197b519aef94c295 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Wed, 24 May 2023 17:40:21 +0300 Subject: [PATCH 20/52] chore: Bump version to v0.9.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d19acb2..76335f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "websurfx" -version = "0.8.0" +version = "0.9.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 211f170178b12c6c40a033b7a70a91156132a89f Mon Sep 17 00:00:00 2001 From: neon_arch Date: Wed, 24 May 2023 17:46:35 +0300 Subject: [PATCH 21/52] chore: fix lock error during build --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02bf14f..ef32619 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1242,9 +1242,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", @@ -3319,7 +3319,7 @@ dependencies = [ [[package]] name = "websurfx" -version = "0.8.0" +version = "0.9.0" dependencies = [ "actix-files", "actix-web", From dc3308cb5f5e28f6dbebe80aafdc2bd2efcf2532 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Thu, 25 May 2023 11:50:37 +0300 Subject: [PATCH 22/52] chore: rename from theme to public --- src/handler/mod.rs | 1 + .../public_path_handler.rs} | 12 ++++++------ src/lib.rs | 12 ++++++------ src/server/routes.rs | 4 ++-- src/theme_handler/mod.rs | 1 - 5 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 src/handler/mod.rs rename src/{theme_handler/theme_path_handler.rs => handler/public_path_handler.rs} (68%) delete mode 100644 src/theme_handler/mod.rs diff --git a/src/handler/mod.rs b/src/handler/mod.rs new file mode 100644 index 0000000..daa5212 --- /dev/null +++ b/src/handler/mod.rs @@ -0,0 +1 @@ +pub mod public_path_handler; diff --git a/src/theme_handler/theme_path_handler.rs b/src/handler/public_path_handler.rs similarity index 68% rename from src/theme_handler/theme_path_handler.rs rename to src/handler/public_path_handler.rs index df3e5cc..b99283e 100644 --- a/src/theme_handler/theme_path_handler.rs +++ b/src/handler/public_path_handler.rs @@ -5,7 +5,7 @@ use std::io::Error; use std::path::Path; // ------- Constants -------- -static THEME_DIRECTORY_NAME: &str = "public"; +static PUBLIC_DIRECTORY_NAME: &str = "public"; /// A function which returns an appropriate theme directory path checking if the theme /// directory exists on that path. @@ -17,11 +17,11 @@ static THEME_DIRECTORY_NAME: &str = "public"; /// 1. `/opt/websurfx` if it not present here then it fallbacks to the next one (2) /// 2. Under project folder ( or codebase in other words) if it is not present /// here then it returns an error as mentioned above. -pub fn handle_different_theme_path() -> Result { - if Path::new(format!("/opt/websurfx/{}/", THEME_DIRECTORY_NAME).as_str()).exists() { - Ok(format!("/opt/websurfx/{}", THEME_DIRECTORY_NAME)) - } else if Path::new(format!("./{}/", THEME_DIRECTORY_NAME).as_str()).exists() { - Ok(format!("./{}", THEME_DIRECTORY_NAME)) +pub fn handle_different_public_path() -> Result { + if Path::new(format!("/opt/websurfx/{}/", PUBLIC_DIRECTORY_NAME).as_str()).exists() { + Ok(format!("/opt/websurfx/{}", PUBLIC_DIRECTORY_NAME)) + } else if Path::new(format!("./{}/", PUBLIC_DIRECTORY_NAME).as_str()).exists() { + Ok(format!("./{}", PUBLIC_DIRECTORY_NAME)) } else { Err(Error::new( std::io::ErrorKind::NotFound, diff --git a/src/lib.rs b/src/lib.rs index 0763c96..6b6d4fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,9 +4,9 @@ pub mod cache; pub mod config_parser; pub mod engines; +pub mod handler; pub mod search_results_handler; pub mod server; -pub mod theme_handler; use std::net::TcpListener; @@ -16,7 +16,7 @@ use actix_files as fs; use actix_web::{dev::Server, middleware::Logger, web, App, HttpServer}; use config_parser::parser::Config; use handlebars::Handlebars; -use theme_handler::theme_path_handler::handle_different_theme_path; +use handler::public_path_handler::handle_different_public_path; /// Runs the web server on the provided TCP listener and returns a `Server` instance. /// @@ -41,10 +41,10 @@ use theme_handler::theme_path_handler::handle_different_theme_path; pub fn run(listener: TcpListener, config: Config) -> std::io::Result { let mut handlebars: Handlebars = Handlebars::new(); - let theme_folder_path: String = handle_different_theme_path()?; + let public_folder_path: String = handle_different_public_path()?; handlebars - .register_templates_directory(".html", format!("{}/templates", theme_folder_path)) + .register_templates_directory(".html", format!("{}/templates", public_folder_path)) .unwrap(); let handlebars_ref: web::Data = web::Data::new(handlebars); @@ -56,11 +56,11 @@ pub fn run(listener: TcpListener, config: Config) -> std::io::Result { .wrap(Logger::default()) // added logging middleware for logging. // Serve images and static files (css and js files). .service( - fs::Files::new("/static", format!("{}/static", theme_folder_path)) + fs::Files::new("/static", format!("{}/static", public_folder_path)) .show_files_listing(), ) .service( - fs::Files::new("/images", format!("{}/images", theme_folder_path)) + fs::Files::new("/images", format!("{}/images", public_folder_path)) .show_files_listing(), ) .service(routes::robots_data) // robots.txt diff --git a/src/server/routes.rs b/src/server/routes.rs index bb6be27..ead1612 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -7,8 +7,8 @@ use std::fs::read_to_string; use crate::{ cache::cacher::RedisCache, config_parser::parser::Config, + handler::public_path_handler::handle_different_public_path, search_results_handler::{aggregation_models::SearchResults, aggregator::aggregate}, - theme_handler::theme_path_handler::handle_different_theme_path, }; use actix_web::{get, web, HttpRequest, HttpResponse}; use handlebars::Handlebars; @@ -148,7 +148,7 @@ pub async fn search( #[get("/robots.txt")] pub async fn robots_data(_req: HttpRequest) -> Result> { let page_content: String = - read_to_string(format!("{}/robots.txt", handle_different_theme_path()?))?; + read_to_string(format!("{}/robots.txt", handle_different_public_path()?))?; Ok(HttpResponse::Ok() .content_type("text/plain; charset=ascii") .body(page_content)) diff --git a/src/theme_handler/mod.rs b/src/theme_handler/mod.rs deleted file mode 100644 index 3bbca9d..0000000 --- a/src/theme_handler/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod theme_path_handler; From de3d88c476c8b1d883749d850cdbfb468d6ad540 Mon Sep 17 00:00:00 2001 From: sathiyaIbe Date: Fri, 26 May 2023 11:38:53 +0530 Subject: [PATCH 23/52] fix issue: #56 removed the meta seach engine link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ea56f7..5e3dd4e 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ At present, we only support x86_64 architecture systems, but we would love to ha ## Why Websurfx? -The primary purpose of the Websurfx project is to create a fast, secure, and privacy-focused [meta-search engine](https://en.wikipedia.org/wiki/Metasearch_engine). While there are numerous meta-search engines available, not all of them guarantee the security of their search engine, which is critical for maintaining privacy. Memory flaws, for example, can expose private or sensitive information, which is never a good thing. Also, there is the added problem of Spam, ads, and unorganic results which most engines don't have the full-proof answer to it till now but with Websurfx I finally put a full stop to this problem, also, Rust is used to write Websurfx, which ensures memory safety and removes such issues. Many meta-search engines also lack important features like advanced picture search, which is required by many graphic designers, content providers, and others. Websurfx attempts to improve the user experience by providing these and other features, such as proper NSFW blocking and Micro-apps or Quick results (like providing a calculator, currency exchanges, etc in the search results). +The primary purpose of the Websurfx project is to create a fast, secure, and privacy-focused meta-search engine. While there are numerous meta-search engines available, not all of them guarantee the security of their search engine, which is critical for maintaining privacy. Memory flaws, for example, can expose private or sensitive information, which is never a good thing. Also, there is the added problem of Spam, ads, and unorganic results which most engines don't have the full-proof answer to it till now but with Websurfx I finally put a full stop to this problem, also, Rust is used to write Websurfx, which ensures memory safety and removes such issues. Many meta-search engines also lack important features like advanced picture search, which is required by many graphic designers, content providers, and others. Websurfx attempts to improve the user experience by providing these and other features, such as proper NSFW blocking and Micro-apps or Quick results (like providing a calculator, currency exchanges, etc in the search results). ## Why AGPLv3? From eee06b92d7fd4e6accd53122361de7a94b73adc3 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Fri, 26 May 2023 12:50:50 +0300 Subject: [PATCH 24/52] docs: revise and improve the documentation --- docs/configuration.md | 14 ++++++++++-- docs/faq.md | 4 ++-- docs/installation.md | 53 ++++++++++++++++++++++++++++++++++++------- docs/introduction.md | 2 +- docs/theming.md | 43 ++++++++++++++++++++++++++++++++++- 5 files changed, 102 insertions(+), 14 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index be0325a..bb10ba6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,6 +1,15 @@ # Configuration -Everything in websurfx can be configured through the config file located at `websurfx/config.lua`. +## Installed From Source + +If you have built `websurfx` from source then the configuration file will be located under project directory (codebase) at `websurfx/` + +> **Note** +> If you have built websurfx with unstable/rolling/edge branch then you can copy the configuration file from `websurfx/config.lua` located under project directory (codebase) to `~/.config/websurfx/` and make the changes there and rerun the websurfx server. _This is only available from unstable/rolling/edge version_. + +## Installed From Package + +If you have installed `websurfx` using the package manager of your Linux distro then the default configuration file will be located at `/etc/xdg/websurfx/`. You can copy the default config to `~/.config/websurfx/` and make the changes there and rerun the websurfx server. Some of the configuration options provided in the file are stated below. These are subdivided into three categories: @@ -12,6 +21,7 @@ Some of the configuration options provided in the file are stated below. These a - **port:** Port number on which server should be launched. - **binding_ip_addr:** IP address on the which server should be launched. +- **production_use:** Whether to use production mode or not (in other words this option should be used if it is to be used to host it on the server to provide a service to a large number of users). If production_use is set to true. There will be a random delay before sending the request to the search engines, this is to prevent DDoSing the upstream search engines from a large number of simultaneous requests. This is newly added option and hence is only available in the **edge version**. ## Website @@ -39,4 +49,4 @@ Some of the configuration options provided in the file are stated below. These a - **redis_connection_url:** Redis connection url address on which the client should connect on. -[⬅️ Go back to Home](https://github.com/neon-mmd/websurfx/wiki). +[⬅️ Go back to Home](./README.md) diff --git a/docs/faq.md b/docs/faq.md index 1805487..cbd3582 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -2,7 +2,7 @@ ## Why Websurfx? -The main goal of the Websurfx project is to provide a fast, secure, and privacy-focused [meta search engine](https://en.wikipedia.org/wiki/Metasearch_engine). While there are many meta search engines available, they do not always guarantee the security of their search engine, which is essential for ensuring privacy. For example, memory vulnerabilities can leak private or sensitive information, which is never good. Websurfx is written in Rust, which guarantees memory safety and eliminates such problems. Many meta search engines also lack key features such as advanced image search, which is required by many graphic designers, content creators, and others. Websurfx aims to provide these features and others, such as proper NSFW blocking, to improve the user experience. +The primary purpose of the Websurfx project is to create a fast, secure, and privacy-focused [meta-search engine](https://en.wikipedia.org/wiki/Metasearch_engine). While there are numerous meta-search engines available, not all of them guarantee the security of their search engine, which is critical for maintaining privacy. Memory flaws, for example, can expose private or sensitive information, which is never a good thing. Also, there is the added problem of Spam, ads, and unorganic results which most engines don't have the full-proof answer to it till now but with Websurfx I finally put a full stop to this problem, also, Rust is used to write Websurfx, which ensures memory safety and removes such issues. Many meta-search engines also lack important features like advanced picture search, which is required by many graphic designers, content providers, and others. Websurfx attempts to improve the user experience by providing these and other features, such as proper NSFW blocking and Micro-apps or Quick results (like providing a calculator, currency exchanges, etc in the search results). ## Why AGPLv3? @@ -12,4 +12,4 @@ Websurfx is released under the AGPLv3 license to ensure that the source code rem Rust was chosen as the programming language for Websurfx due to its memory safety features, which can help prevent vulnerabilities and make the codebase more secure. Rust is also faster than C++, which helps to make Websurfx fast and responsive. In addition, Rust's ownership and borrowing system allows for safe concurrency and thread safety in the codebase. -[⬅️ Go back to Home](https://github.com/neon-mmd/websurfx/wiki). +[⬅️ Go back to Home](./README.md) diff --git a/docs/installation.md b/docs/installation.md index c9aa6f1..050be70 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,16 +1,47 @@ -# Stable +# Install From Package -To get started with Websurfx, clone the repository, edit the config file which is located in the `websurfx` directory and install redis server by following the instructions located [here](https://redis.io/docs/getting-started/) and then run the websurfx server and redis server using the following commands: +## Arch Linux + +You can install `Websurfx` through the [Aur](https://aur.archlinux.org/packages/websurfx-git), Currently we only support `Rolling/Edge` version. You can install the rolling/edge version by running the following command (using [paru](https://github.com/Morganamilo/paru)): + +```bash +paru -S websurfx-edge-git +``` + +After installing it you can run the websurfx server by running the following commands: + +``` bash +redis-server --port 8082 & +websurfx +``` + +Once you have started the server, open your preferred web browser and navigate to http://127.0.0.1:8080/ to start using Websurfx. + +If you want to change the port or the ip or any other configuration setting checkout the [configuration docs](./configuration.md). + +## Other Distros + +The package is currently not available on other Linux distros. With contribution and support it can be made available on other distros as well 🙂. + +# Install From Source + +## Stable + +To get started with Websurfx, clone the repository, edit the config file which is located in the `websurfx` directory and install redis server by following the instructions located [here](https://redis.io/docs/getting-started/) and then build and run the websurfx server by running the following commands: ```shell git clone https://github.com/neon-mmd/websurfx.git cd websurfx -cargo build +cargo build -r redis-server --port 8082 & ./target/debug/websurfx ``` -# Rolling/Edge/Unstable +Once you have started the server, open your preferred web browser and navigate to http://127.0.0.1:8080/ to start using Websurfx. + +If you want to change the port or the ip or any other configuration setting checkout the [configuration docs](./configuration.md). + +## Rolling/Edge/Unstable If you want to use the rolling/edge branch, run the following commands instead: @@ -18,13 +49,15 @@ If you want to use the rolling/edge branch, run the following commands instead: git clone https://github.com/neon-mmd/websurfx.git cd websurfx git checkout rolling -cargo build +cargo build -r redis-server --port 8082 & ./target/debug/websurfx ``` Once you have started the server, open your preferred web browser and navigate to http://127.0.0.1:8080/ to start using Websurfx. +If you want to change the port or the ip or any other configuration setting checkout the [configuration docs](./configuration.md). + # Docker Deployment Before you start, you will need [Docker](https://docs.docker.com/get-docker/) installed on your system first. @@ -61,7 +94,11 @@ colorscheme = "catppuccin-mocha" -- the colorscheme name which should be used fo theme = "simple" -- the theme name which should be used for the website -- Caching -redis_connection_url = "redis://redis:6379" -- redis connection url address on which the client should connect on. +redis_connection_url = "redis://127.0.0.1:8082" -- redis connection url address on which the client should connect on. + +production_use = false -- whether to use production mode or not (in other words this option should be used if it is to be used to host it on the server to provide a service to a large number of users) +-- if production_use is set to true + -- There will be a random delay before sending the request to the search engines, this is to prevent DDoSing the upstream search engines from a large number of simultaneous requests. ``` After this run the following command to deploy the app: @@ -74,7 +111,7 @@ This will take around 5-10 mins for first deployment, afterwards the docker buil ## Unstable/Edge/Rolling -For the unstable/rolling/edge version, follow the same steps as above with an addition of one command for cloning the repository which makes the cloning step as follows: +For the unstable/rolling/edge version, follow the same steps as above (as mentioned for the stable version) with an addition of one command which has to be performed after cloning and changing directory into the repository which makes the cloning step as follows: ```bash git clone https://github.com/neon-mmd/websurfx.git @@ -82,4 +119,4 @@ cd websurfx git checkout rolling ``` -[⬅️ Go back to Home](https://github.com/neon-mmd/websurfx/wiki). +[⬅️ Go back to Home](./README.md) diff --git a/docs/introduction.md b/docs/introduction.md index 476f509..7b540fb 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -10,4 +10,4 @@ Most meta search engines tend to be slow, lack high level of customization and m Websurfx is a project which seeks to provide privacy, security, speed and all the features which the user wants. -[⬅️ Go back to Home](https://github.com/neon-mmd/websurfx/wiki). +[⬅️ Go back to Home](./README.md) diff --git a/docs/theming.md b/docs/theming.md index 95ff7ff..49f3f22 100644 --- a/docs/theming.md +++ b/docs/theming.md @@ -321,4 +321,45 @@ footer { } ``` -[⬅️ Go back to Home](https://github.com/neon-mmd/websurfx/wiki). +### Styles for the about page + +This part is only available right now in the **rolling/edge/unstable** version + +```css +.about-container article{ + font-size: 1.5rem; + color:var(--fg); + padding-bottom: 10px; + } + +.about-container article h1{ + color: var(--2); + font-size: 2.8rem; + } + +.about-container article div{ + padding-bottom: 15px; + } + +.about-container a{ + color:var(--3); +} + +.about-container article h2{ + color: var(--3); + font-size: 1.8rem; + padding-bottom: 10px; +} + +.about-container p{ + color:var(--fg); + font-size: 1.6rem; + padding-bottom: 10px; +} + +.about-container h3{ + font-size: 1.5rem; +} +``` + +[⬅️ Go back to Home](./README.md) From 34ae87e4a43c6849cd986f94b0498166d7fbec4f Mon Sep 17 00:00:00 2001 From: neon_arch Date: Fri, 26 May 2023 13:15:39 +0300 Subject: [PATCH 25/52] chore: revise and improve the readme --- README.md | 82 +++++++++++-------------------------------- images/main_page.png | Bin 36381 -> 37287 bytes 2 files changed, 20 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 5e3dd4e..a7483a6 100644 --- a/README.md +++ b/README.md @@ -5,68 +5,26 @@ Readme | Discord | GitHub | - Documentation + Documentation

- - GitHub - - - GitHub Repo stars - - - GitHub forks - GitHub code size in bytes - - GitHub issues - - - GitHub pull requests - GitHub Workflow Status - - GitHub release (latest by date including pre-releases) - Maintenance - - GitHub contributors - Gitpod -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Features 🚀 @@ -136,11 +94,11 @@ - 💨 Ad-free and clean results - 🌟 and lots more... -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Installation and Testing 🛠️ -> For full setup instructions, see: [**Installation**](https://github.com/neon-mmd/websurfx/wiki/installation) +> For full setup instructions, see: [**Installation**](./docs/installation.md) To get started with Websurfx, clone the repository, edit the config file, which is located in the `websurfx`{.verbatim} directory, and install the Redis server by following the instructions located [here](https://redis.io/docs/getting-started/) and then run the websurfx server and redis server using the following commands: @@ -157,36 +115,36 @@ Once you have started the server, open your preferred web browser and navigate t > **Warning** > Please be aware that the project is still in the testing phase and is not ready for production use. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Configuration 🔧 -> For full configuration instructions, see: [**Configuration**](https://github.com/neon-mmd/websurfx/wiki/configuration) +> For full configuration instructions, see: [**Configuration**](./docs/configuration.md) Websurfx is configured through the config.lua file, located at `websurfx/config.lua`. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Theming 🎨 -> For full theming and customization instructions, see: [**Theming**](https://github.com/neon-mmd/websurfx/wiki/theming) +> For full theming and customization instructions, see: [**Theming**](./docs/theming.md) Websurfx comes with several themes and color schemes by default, which you can apply and edit through the config file. Supports custom themes and color schemes using CSS, allowing you to develop your own unique-looking website. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Multi-Language Support 🌍 > **Note** > Currently, we do not support other languages, but in the future, we will start accepting contributions regarding language support because we believe that language should not be a barrier to entry. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # System Requirements 📊 At present, we only support x86_64 architecture systems, but we would love to have contributions that extend to other architectures as well. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # FAQ (Frequently Asked Questions) 🗨️ @@ -202,13 +160,13 @@ Websurfx is distributed under the **AGPLv3** license to keep the source code ope Rust was chosen as the programming language for Websurfx because of its memory safety features, which can help prevent vulnerabilities and make the codebase more secure. Rust is also faster than C++, which contributes to Websurfx's speed and responsiveness. Furthermore, the Rust ownership and borrowing system enables secure concurrency and thread safety in the program. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # More Contributers Wanted 📣 We are looking for more willing contributors to help grow this project. For more information on how you can contribute, check out the [project board](https://github.com/neon-mmd/websurfx/projects?query=is%3Aopen) and the [CONTRIBUTING.md](CONTRIBUTING.md) file for guidelines and rules for making contributions. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Supporting Websurfx 💖 @@ -224,20 +182,20 @@ Several areas that we need a bit of help with at the moment are: - Submit a PR to add a new feature, fix a bug, update the docs, add a theme, widget, or something else. - Star Websurfx on GitHub. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Documentation 📘 > **Note** -> We welcome any contributions to the [documentation](https://github.com/neon-mmd/websurfx/wiki) as this will benefit everyone who uses this project. +> We welcome any contributions to the [documentation](./docs/) as this will benefit everyone who uses this project. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Roadmap 🛣️ > Coming soon!! 🙂. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Contributing 🙋 @@ -251,13 +209,13 @@ Check out this [video](https://youtu.be/FccdqCucVSI) by Mr. Nick on how to contr If you are a developer, have a look at the [CONTRIBUTING.org](CONTRIBUTING.md) document for more information. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # License 📜 Websurfx is licensed under the [AGPLv3](LICENSE) license. -**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** # Credits 🤝 @@ -271,7 +229,7 @@ We would like to thank the following people for their contributions and support:

-**[⬆️ Back to Top](#websurfx)** +**[⬆️ Back to Top](#--)** --- diff --git a/images/main_page.png b/images/main_page.png index 0db122276d62253adb3fa0c081ddf0766f88fb5e..337eac53e8d38050e9e29e1aeccdaa4d4a8e5a45 100644 GIT binary patch literal 37287 zcmeFZXHb)GyDu7hLE(=yr79>&7im(X0@6Xcw16PJOHY8Ph#*x&KswTE5GjE`2uhXS zLrX$03B839k{x{Cwf31=`<&T(W`8&zR%V!xhdcLkU;THLhfgoGRjyxUy$S#TuB)jk z=>Y&23;}?%%a_kmuMlb8_fX%ic&M6q0RXfur$1*B1Zdd+fZG5yrKbk|X{(rkK!ZIb zWvfqGEdKS+FVUZ`-%vgKA^pb(t?{_l3+J5Z9h}YF&CFVbh1bf=%&O6rEY-+rH#GkQ z|Fqt?`Pl2&RgJfI@810!x_YenCD|(&dhO#s);Ioq_}olbX?`T_wV2kIe8V1#TYGR4 z7R^j=fwrJT1kc=`#_KcE>oy*#=rZQj3!EMn5b`iG97aIER#Mi%!^2nmG1W6*FHs^P zBD*jmT%F-`37|Iguw=7501OV@r`_AyH)5==FZsQvfv%oFAZD{?kHGbX&;Da2KLX~A zC@3)2)C5{`S^fqhlCldM6&giFPvqp0<~DjCRvw&g+3#2^j93OcY`pjagmFYx&F*Na&Z!U)*m(Sfhuy{3DC4M-mgn_H*c26)gIE?c%rsOcJ5eDHa2hI*w* z$iSlD0szgA@exob2cHu4#9nlX>vT0>j)(GhL#x1f=-&%bu_U_FU*2xTQBJ=Nc&M-q zJbeeWsgT27DXS>^_+2^u=uzfypAu`jf8dUipHOj}uv&+9HR}LtUgr{9wVXDJfC1a} zbEJe(+S}au!8^g^gY=Ldx59nB#jIB}>xYL>AUX9?lGZh`x|7Z270#gfxDN*h>#)Bp zpX%%D6S;kRdVB56nKQw`!DWrP=>{1I!A5p%N~v^dE{yc_`YlcVz!90-o^RW~=j?HF zXCJh+d}OxEfDOnR9!uq)kEvVRUrs}lckL?hd1L9u#MR}(OY4-C;t}WVot@MgB_$<6 z(ARAejfk%eRWkvADd(dqN67wqSxJfWo{78r#=Pg8lso24LJ1~8swUR_Il8$a`f%A6ddGEk+< z%3yf-Wppe(J$+ZAuthaki)eI#dd?=~m-zPbT1qhWh+Uc6`}-hI%E=#wHp`RZD0M?a zWy9m=D!{D+8?79G`3%b4yDGc5ctU;5y?|mV(AOcDDtepuiM(0;am5sZ-@9kST`S50p=S!O_AwVoqVc|%4u zY(Cr31;92%B1j8|EQpE*=k|pYl4~rDgQ2bM0)vji;ek!;9$}K`rz5{L#-QVvva{75 zJR~I}0|ajTDF{XfzIYP9Z?_;D`A8eB8MS7Q(KQli^xV25eO&4Mv)d$5`W%l|vb47T z23a(JRi{r{sfAH;VO{oO=HYY?&~}`3u@CeHZLtT1+CnPA!)J4tVUQq;3RY1kY_@XO zS3D{>Ew8n^!P%&zF#!rWHqX&{`TB`s5%1urc(DG|^&uw(6H0lR;eN_aUVY@6K;m&J z#BM|_EZjd=DhPcLi0{ zUA`V#A?l#d{IP#Z!AP>VX^qcB(~oHB3*?H5Gxn%%M@D*m)Ycq0o#Zj}=gY-71W)Gr z&6CK1tzg+mXC4_y|tL}aA(Q_o({JF_7dg*cX zN(iRFT!6mHfzP1>v%U51cs(P@JlJh`b5Mu!^a!_5D zL@L}IEfzy1?JaC5`^pog%M^>^pFg)h-OqeOWr6DCjHS$HN^4wdK$~0{^c&x#NTa*% z(S(eJx7p&SsY%|u=iT{ZmvOQ{u}N6u1JJKK!Dmj^{U3h+wf8J?#2|4+eFf2cIC4G+ zDSYhx&ep}@ZAxMW*aQD%0T`|ay0Zz(l6Dk8%4>zAMQ8(4YBzPPJgQqt1?&Z(z!7;N|# z2|DOKnnSdUQ_uu7et!q$*46pgk5D)^-S|$FDcP(#+Snjk!q9a< zh#oPNv=EHGPCH1c&fz1~KY|XK0xX8l_mj4=zka12?;-g#Fw~}`qySENTjKZ&HC1V^ z+#*4r6@3S=R!R}!&PKnsOQVa_;1tbL;5qsI16(F^q76+ZtzQ z8IGz3bF;o_X_*P>1~spSUPwp@S5;K*omnGb16Epz+6U2Ec=sEgGCn16_~5Sk!gfw| zFQepE&HP8#%*B>oq~i~rFw2j^HU7HlJ5?K|G*;9j)>xi8!K@{!n}r-D+h+zZn*4^M zuUy`AZ=A+a?K(L=by7;^h-%jKH*b#NH6}JFECZc7nXoi5p(5)gU_>K66V0!aE(dg9 z??{m^X9A7oGp*qg;sU!k;0Z|hmg>76u_~y$y^-%HLK~oBuHd@hSiU z6Gv|6V?$Jku%1rg(n8{8{F*!LPtj;=GL#qn2(q0U(rTF)@cbIr5KbRB8mA#e%AH=vaifwK-NlYKIfLto>0fCh5Xevq6c)?~I4x%<823?nET{d35Kd=Hswk?Ncw4{bu70 zC%4nGjXBNh^ZS0MCYIL@fWD;01;GSM&s|7q<`qtJQVR+~2NdvLLc4PA&0VOBT?qX8 zii#&rUsexO@>fzut$(5N7XUt5LsdqJEyhRJIbqTqpA6)g44$A2};3n7MsrpiJjXsmIk}jhDT9!ma_5<$U zIGxk0%Yq5JvCi=@=ZMQQf7eYtV^U^RE-NZqSyz9nF+4iL7okr2yCwVuldh6(L}Y}I z1!3L#EseK@fG|I^vhK~yzYt~J>gqKb7G?IBwv-gp$goyxQGxTq-dq-FCxX+?&NhLt z7E#O}(P^pr_qKAz6UNF3M@L6qb@o0MXk``)rQLPdbu?S+UTg_EbMr6aa(m58Z_MyE z8;@9y5avc`@2mLL{+OV&`T~9fPj{&e8{ca;eyR~iqX8QNymk9-P73+gH`i@oC9u_X z*3(shC+J79Hxq_25`RCvh2{DB{SAA$6adtzkdB%g=C{{2`5aubM;GZ z17%7oD&pw;0RR{SZ)IIYMa5dsfg8X(G={W)#+8SXQ~3>j3DD$|hlvetWCK`yuoU*b z@gE}ouh2Em#3RAq3|XLs^gOC!Q+~aZ=t_`uSzeEzo-|x_`(P_#xt^Hs>vspxZ=xed zKIkfM_>!548@d0}v@DV(?=CN|ovnSjX*Hsup`oO2nRy;+e*Mo}dtatsd@OtqIl|=+ zF=Oej=aUYYI@)7{t(H807D)P;r}6B4h^Y&%+I}NNf@^dfKc)K!06>Rc*jYrFE`@}I zpkXL*+0LC`zr2=u)xu-xuFw{jRC36?dENX`M_pZ`-1H3K+Mlkjp{_0hf11Nqwz82( zd6H#-&uG*wDUp|(i)QW?q4B;MY}-&Pt1OHgeB31+XmBZ6i#LAU+|m-K+zvM_i|5s1 z|MKl7C#Nv?g$ozjhX#Gur)(?7xw*ORdcTnu%>?R~hug&79Bh958mfRD?J=uy#s2JJ z>LsqKr7NtpwMM#SO0KnyI4fxObsRizH*efsr=keB5opkNbNU=G`J0@A4F9%BA0?WX zs#r1)0!Rnd1gVIQsv;>+HHnLf>2Uf4C?q5@SuZ6a&m(q6!R;XYRjdN33y9jBt@8>n zF8CNDri|UhOa`L-9fJ^+^%`e9dQ>&pN!tSDcDA-byl*z>8gZBfZv*=ssFG3(5_mvf zN|oFgt7sOw;G?AK;P6_h7c@39KFhhC>cObHOU569i;pwfeXLT-2RoI@8905vet$K{c|n!~ z=;Glqosm#fR>P{KqFm-b-RM4iewscUiW8J^QFtJ44E^vwy5Hh?K@; zAL|}OS-XCpU%ab-gN#xsAnFMR6dBdd5b2QdE48n4tfMo$+u@7%?(goGb^#GSJ!TYX z^EWG;EZ@$C_0|(&R+^8G9Bs#ooN=J)1x*V9KX1{)>)*V0(rMg10(bkp%u0kOe+}BN zy5drRk_y>Ltww2elz77p_rBt~A4#*aR{QCGy=oCx9vLpNlU8vXf#7WQV|-EVxL>{| z*JwFBwvyyBu^(#$4Xhp8ioSXdup7t|Mn^|WJ5_n#P>H!fkX<_P;5&~B;wYD@oOD>q zP_s%*W8JnZI*}@Ss(1x0!Nd?EWj7fphhBdGXccf-KJaXw<9=UeXCI_x>xumnRKK4& zH+1!_r`*=T90-)*x@rZV%=F(batDuTFF=hCbTl;TQ)VocuF}vTk;qGQtjqhnZ>iFY zWX>zKfHxj8+1lE!jaAGorm{>mST(Zs+4}41#xZWqI6o9VlyG8%!Ft5VD-1+Tz^-9hC+1ax4c8SF!J3hMRN zIUo$WI^GvKXbh~gE}PhGeRjQZ>s?qIr$&z>{o2T9H6Yl*WGv2)vVT0(TlmLM=wwAP zqfdUnTz^0DK9Tj?_D-fwkvVaZ%Ti#6O9A@FFZfoW{MPSL>$O?o2#H6I`?FuA6}v~G zpDw123jgxjoDEy&0OQxtP-sIpyTa^ZUKi*3g8xCQ1rs7%`VICRs&=H|q>KgITiMb> z%@IV5zGVc0EntdD*VD;!nV90h{fQm-v@#;sL)!sAPXGQnzgSf2$k_Ma0D!!us)vV_ z)pV7k)H*gE?<9^x-uIcPVsj?oJG;8-z1hhPby5k5Nfu^QHBFQ;PHo+g_pN|YlJuHRSHD+wmWtH@#NZYhU-O>V1tnKGhg7%XOEZC%6Cw9k| zQe~hpsvpW*i?K%spo#?gC|WZVq+v<u4mi%JSw>w-v#1$BGl`_PoCGnpGAD4uB-SCCU1#E?9 zh%yu?Ee7qbmK^Vy#8P;_CkQ+wvPtl7&O@r`KM;BN^PNwU zsqz8>T^36zqBd>s&RyDH1K#HLt;bY%S_KD_X++2)2_x-yqccQpKALSqS%hBshaRFJ z&8W!9Q~<9|ibLhN8Aq4L&ig}HH9)DwZKK%d(zQ0G)sXk^C)O3iBO+WT>cldF7op~K zH)iL!s2-CeKfcnZEJiyvx1hKjxMD|Wkdp6q$5pt{vTaA#b>1AzKpVA zrL7IsSAe&i&QuGcRxl`FKgSFfsb0^O)9>bWT@D$il$ zl)jVQsP4lZH>ah&ViUuLz(7qsuS1edYo*`p{3jmk;{&r*+i?{?H{dtpl25afQhWi! zS<6^tpj=f-cK5l-8V;dibSq;(GrYj5p0+6Dd5g*svztksLYcPIVS7xfIPaZD9V#V) z-Le&sof&R=-N2*hRQU#|_cxSYJoF8E6mu&fQ1~o5!bHsexzdMngm^OIxi6}Eu!jb| zHVK{Hz8Jb_612NKur8kiu}~wUn17=pA*p~H3=Dqj6C-&2jWScr8p|X@ozbo%Bmni{ zpq5HciP4}`&c%CoKYX>fPqO^7lK`?Qh#k_)1irvn7k-}|xzGLMXtl05vVO8JL%LiW z&)||cVP~nQ`6}*}p2x!t>m)?wW_MlNg;%fa9Hs0C5wI25;$?es4N>YI#lO`(5J>iS z_uM=%<3%?T(L$jq;d~DpVpX6^pKCVx~2IQ4QB1)>ysq%5);^pq9*2^ zQI4!XvZ{lv#1xAi*Q^Q^4W1m`)2e^9{$Vh|Y$uI7`(so}iogF7Y!5HQ>R~^@&Fs8X9KQB43j5JLvTu3W|6MxVgQ}E)VvebY(L( zdO@S6mZO!wAIUD~Fik#pNhSccx#@v^5A{eI9Q;{W-Zl?SFYM?T9Q0kh?9I^X-cq)6 zv=F#Gv7&LrqB$egttm*Jh2IxpyPWNBip-t)aw|LqW5*C#&~7UW=D)trEIZMPZdQ!* z<$X9YggxAY234D8gM3KM37IWZP(nITo!NecOeANd;BIqsgN#J-zJLEdUg2HeBh0Kr zr>w-<=So4N=8OWNy>N!5<>~?;#77?-I{N1{Xf-VgnJLdtb|s#_bfIjr|Hz3#v)Gdk z+{ia{R`6I`^$nxt(&7ZxjD*l}i3;){k)Sgwzt$x-n4{UnWIXX4f9xP?>z|s7iX20I zQYIiBg@v<0Fs;> zV^NQTza!1JxE@Om1bB}u@+_ru>w!!ka9iJ?Um6#IbM*K|sE%jIpWJZ&bdC7v0?LdmY@TZR8XwlH!DCm~LOu1!=^ z0gZT1pojZYp|r=Ioi2~6D-=~7RH-kwb;A_m0_$=Ap>H%n3H*F<_G_r?M*Qc0h>K=8 zt1U`N+Z1G*ZvB=%d21+>2{gF1Mh|o~^>3S4+7agRE|eNZM<&4ynGW&yB3hdj%i-1G zy$$84)CSZD^ zI-qOx=itwUu0(1GGcF52wN^&zyJdcsTjvr%jrvHPeTjNCSI&93Kuv;7r%vn-2kUcq zcr1ett9@g$q`unb2d5-E?O$1w^;j+x9n!OYuMoHtncb8H@EZQQK-5P3$aK=}>ZLYP zVEz~PxMc21J`(Ro)WhVb*8qb zl@|~ve3e2K=IKkA+ju4eitZ;t(PniHy6Q$ozQzq@J=OBXKyhj#=?Z0~Q<7Y&r^jdB7YrmlJ`DvNWxzDkz2K!mt=W7gTzI~M92jmyaYc#O<2R}6?1a3 zmF@})!sWZ7^Z?{C*v{i zacXUG_W)0G{mQ2`9L|E82@DPn@@l2@?<23N#A?fUWIb{u{M7dipg!MHbN|Zf}6?wZ^b?fJ#F*Tryx$c=cpP~5s zNOd-aD$=sr$i+*&XSl;A7Av|gwG{D4EdY*e{r%KrC3@VzkXpX2AEW?TC^ z^zmTNw^2sA2Ct>U0w53c0=7HUg2r>_r!koc4&2!nW6~dw1uvJI(CVHBdZ%hNSFlBp znr@v!Tf5mnUtQiqK$C>X9fjbvBcnEopTmVlZH>MT|D*Ax#U7+%+b$bRH)_QNgsrO# z5J7E&&CRFaNka5-E#cz&7 zN12!-^_@v_@)4HQ5mM>GC4WL1eO9oxJW;(8i}9ooopECx*}|`A=H=dJK!;L*#3L$RfZ&SHYN#*>4r`FZTUFw}!#@1;NI?yK~qibCJJ$foJf zR9#fLD48a$pFd(~?2Nn=9n&Lg&W*Hgi;5DL$Z*{on>dVjY;BIW!@k%bPqOD1cUI+c z_VI0mxQSoSqVW$1sF7D|3_12Dc~f<(n9cpc*hgmvGBiG)7m$is#3nFJGT$8QTBBN= zi)5;^<2eho2vq?GU zyhy_KmE&!(TqT4uIusi)*u`;$sc+!n^>6S%5VS-sAGq1QOEXzD7~LngyQmiSGORb{ zhR3|6tO&=o@)UVFd3HNxB_;O5OnHim$#z+)kz8<+!6GMV{xC`Mb^Y@@#k`TN&CRp; zGPE-t>SW5&c|+UeXftr*MOJMe}43VyRYOP09LAe`N);KL)L1gV8AJ|Q2WJt}O}r9a%` zp)0e1dtyFb&&ylTjf=BLr=Vg4_TdBPvxb=$4C%C0Q)DEY&`xiL6PPlvJ2UG!t+ezN z_U?yPHkkPeeU|8LBR1zQnn7RY`L81*83(gF{VVZyIBC5Sp-u%~?wr22<jp#sdexVXc`PCuB-Jd_$Iw)6ZhUAk0r9R)j8i{< z?r+bW(7w>8y)p0^&4c@ z$L%w)(CH>}x#a~QpQHES@<6QIkpMgmCQy5a!WKK?lrHCJZEc-hQdgLjbz4ZtmFnSk zN$}#i%&nmUEsKX6y!0mZ!8R-yy~_ZAcT2}ibIALU{Z%zrQCSh`0CN*ZlSu-_B9ugz zWjIe+mvCN;x+P{;h16lefSW9+b#6h0xif%T*k{VS^=D+2`#~6Xo4?g`EB61zl*E8Z zM7HqHlFnC+?YsKTGU}6n%rv6Mnlg#$y zrK)IBZ12@8S3JcfH$~|HZ)c=AXjN)hB?R;@}m)eT>SBJn`sIt|IJO_ran-JbPHNO&?9E*ut%5ncpeg0i@-&d{%4z%f;qjbR)o{L%2wCTUo z|J^H+5)HjhBl>9;cz4*d11F|juVYW!rpep0IOGv=`!X^q0MF{HdTHP12DH^d`& zy9w?bgS+Tglk}IDFneB#LWn$}YmM{V@81o%*|2)T%I#J$C-d+(k9>wKV-p^0DbEHp zzbMI6bK#pQRWd+{mW!koZ5-e> zIEn@}PdJbF;raF`S%`*j$b%piAxhu8YNRS@Dl8`Qaj$!w>)yIc*&bL%)xA{6*zRo1>&{C=E&2+|(i{t?{M_dn z{;DZ);xAxZvhwcs+=dn|5Ha&xT9Y9kLyR3uqsZectPC_i3lXdP6atYyKrHmS;C5|@ zZ)f35hM{F(KyL7E)fE=(CHfIco2M72<|@lvUJ_#g>gQU#UnHw3XeItD_;C zY-ervAQ!?q59kvrMLPHeH_Jtg<8>;tmmv!J!s(EAarl?fG!AzCHEFdMJAwCWm}QExG1wBjIB9jqX>Hy6hTR6i`gQkQHtNLMOj zVXpiyzh{17v1#)cb2W5ZUN&A?$>r6nMm_U!jA0N1SZjRC9_V{f2)S0zV@HG&k1WUqE8y+n5bny#Rda=MMb1=wyYDYcxzWd65$FL zSIJljL0QRLCC6eHAR?lyq=`ieCQU`@_{p#-$#wI#imkKIBq>P$s3fwAUx+51^zh+m zq&|gXUwHQN24k_D)FBclHi=e6f$lzRkmT_T#ikF-n?EA&53!}CSW7}8_<~!0OSvb@ z;Y$cU#-U)UMs`0{$cPC4R!Uxs+@XX#vo81`1BceFt89?x!c>Z_!(!?OD$~uF2PuDh z+RJi7Sy<#q%ADC7FIt&|?zh>N`x{~{D&x>s28ap2{^3h5w-S&lLc4yPvgR*DxCi|o zENN;@g{u^dmJ08uNFp*#4;M17YANj=k(zDa;C>_vxU>uWejY2OW>YCf&7Ox`@T=dY z0t@^yCwW3@IEy!?wkg>oBmCd55V4PSViskdJr|_)=9B@$jFfV>rjx}+&V5u6&)Ht{ zdgL}gFP$GUNtE>YDJ#~S>DNMc@T@m?4R5s=7 z!T`u#$Nj|B$+v=+Th9zEsrA0#ZdC2Pn%F$KHIY=f3yg|!z0JVMciU)Fm>4ELCnVk) z6hX`$nA!6Sm-1#Aa+Yu2u20gzu+hTNSwDV+yA0cUkuw#gP-n-pA?m%V>tZ0tXA5?#QIhu+{b?81tnOh#BjR) zGr+H7VES>N?XfIx>75-1I|ohg)(Uv9!DHp}2hxyHF(;$hj?k@>-}s*(3}U4@qOAsZ zG0z=0lMc!J%eE&h4==?;Uy1)xDk8wz@@Tnk11mXyUeYygEeEF_b z6y@ItrIy0=_qP9+flv3jOLS}hiLSE$eUtyQ3Eclp3^MCW?zj^Y1 zF^Tza1N=XIw&1@F@c%akm|R~^O}_S=cSa?+silou#_EoHuTqbnDk)Lybl{c8)oSi* zvAjbCLWtrKYMqXImx^IMlx0})S13vP6TxPt3K$;Tv%D2LW$^Mn03a%i`bf#L_Vdfn zEuq(+*CK?6dQ*pXQmG-fcJwoq=!1M2nQbmtF<*wagKg9~P47#mh9ljM3F860ARt>L%KQxcZUS0 zeJzg@w?R~v=AGt9Sz&n5=ri*9F92`9|E2U>`5zCZ`jWDC)SNu|EVaSPczPhoe?}0| zqByV(hzXEof6A@58If|=0Z&x^N)v!cw%&i(9<{BG7-3IdmdkY1uvqI*$dYActPBg! zmSt7CNy5o9(x0TtQ;}37Gj&UkbiD>rcU(yKKywe$W~Axzh={?~uBb9?jkXE)ChO$q z8fAmZ2fX%9@wFu=Q7P8)STag-MPj7eGEo{ohof1qzzu{PfEC4du$fHb^7O9Pp9M4PJ0mn)6k>^Ct~v z3-^vGp5N0{fmoeCz0saVdAZLpTJofjuhmqm$U(dOlb-En%a3_x` zAMJn?R9DUsz`}KdhV(BwT&{h5>-L03qEbryS%XOK`mSo|qI4vFZ$Wp_vOU=gU&Ye< z_$ofy;}^9Sd!~&lXPC(1v_l`gQ~+)2nmj>)(9M<7e6ecm>DH!^T#z^N@fiIzvHDJ;4>1|44p7ht4t4k%@jNfxYMwtiaFl&oAaWc)4_^h9{B* zA|PI`ud|*Oulnq3j#Mug8U*neVm zy1HV2>mf)$me3)Of6!^rKr+N-eT>3jEL_5drCU86FC8WB^YM(PpdQIT z&gMPh$M%>iTqW#X)WWCD*6zONXBUD~NBz@J?UPDRQmnKfY;Vb+a+bwd zF+6-ZW!;5QMRA9tI%TlUCR4(I(c7n*BX#i}t~Yv?D?FIZ zsLWW6*~GbQjHUo!b=1d5nCFXX8jK8gsVzB4`7U2q3wi*+_%Hu4FAQ|cJsjnbjrlVz z%n&?(+0PE7vQLJu$q(d@%b<353VJ7}LRdXAa+#OO?d?zmiyv z0WUELO%$LFWquM~d4 zj@5tkvy}f-tguC-)eG!7wdYl@%(_&NGsD#eAg}xLXheGPepm$>BjeBR0 z0{FZj0t{fjV7t7Zx;W#!B+2EFz^|dmkty)_%lRmx?lZwoqcG6iSH7qCG^^I^2xn-jgfp?a|zz=?LMyS!#kL%_m&8EA()FE%JDv#WDO zf|24EOj?S=QOcrxZ*oncb7^9o8g*jNqIX^Ht%$@v5{X4@KBn@c+&AX(Luv7%MwdNG zu+ai=sai)pZG<-YMlSZ&t8K%Dz~)xlv&SY0EPdv++|-yTOpS@th#Bu?30vb$nI6!P zzs$(-Vi=Q-rN;0-`Y*n!P%5Iwk6B~feG@Z$jD2iK3HRdiZ#}h^*WmPAi@no zyV71%XBr;90(#-NmsFI&o|SQcBilI&6TQ13Gf@|5coOZUUBX}aKH-c)v4FPD6@#OI zWU}XIKz5Do8O5N5NnJd^U0JD^bq|{66KwLm9x*0wXfmY|B#2#gH}Xw%h8g8&w)2R8Qs%I4KuK|UYUCC!e7G!D? zonSs^;7N`}OcQDU_&jyjFD&5Zu9H03kdEOQ`2eL(oVL$DrfQl}dHGOrFSHWvK#RmT z*p-W3Q2rDSE2KKmx($y$QTXxHb~tf0^W|(?3HD67pbPl(cKR~S02~zGr%{zwK3a18 zQ?Czh=`U9fcht+89TIdQWXmQb)`6e@0B1j^*f%zoJi{5}Q`Sm-v-hn7*PIQ>KnRh; z$}nIFN;*#SBJ6^`eP=nd^4@?i`;6}Jn2p-xx7RkK-)aZGT3Sn{VqRB{Q$Np|W`EMH z5cs64`}9f6S$`8`3psP)lNhgs<8Uh@@nFOuM_&zy^Hm z9n8|8|4^=-c5-Ai2ujvW(o{8cX7jOC68W<>DEn~u{w)=I_AyM-)9^ckt{0kWj7}T^ zNKaxX>=0kehm3ijy95-Cy5U4T%t}s<6}O_b0;#yJ>B>!N(I_xt*`dF9$|iS#m={%M z^GdAbWmF6>#q_IsulGHB*1Bek9J`g8i}iNU1}B{cmsCT`3AE|;{XZlZul@nG)#J0i zhDuyCU62rjB)?58r<}ajnu9(>X5r9njuODR2hPE=eYJ_J78ER(!kfo-64?V@n<6IY zKc^I)k9khwb1d#3^88XbiaG19)P=YR`KA-4J-5%T$B>ZtZM|kZYrsY!*idPrR9Kz` z(>nxvls!2+L0CEXm3D2gm=dq2fi z?QQZhr5^T1gl0V2qA$P*Av%WM>YIr+D*BIE07m@)*`NnEGfS^R1dDM4`E(y!2QfhT zm-1(Sj`KjI+I=4UI)M5~=wc>(RGPNKg(FqRnCsiojKl5To6FJ=viK{?`*3O*9fh;@ zbITBio2I$OEQ?oKnMdex_ZgYgPhO_t?WNP$d{NN$rrNC_{_k^fV`ME~FGI_W7V*J1 zYx#3!to;L4uXieE;2A&62uB87^tWb=72~g2763b*YN&W8%{#3K&(!o!Rt#mV)1%A; zKkcc`FVGjo`arSowXXoj87&KjGZu|lmWsCI6Fa%CjrVwBTpf`1nJRrNp;w4Y8`4U+ zogb1K)-~ZBjagqm?p92JSVmIKylr#Q@9jj6Dex9stq?5B>Lb)Eb%f~st`2VjdNr>< z^9D95CCF++;+VicfVXF&4yiEhof=-PSSu~UHj}`yCsv1^- zvpSSv3IFV5;BVDGl0PG&ci+z?{w?zK#qxQ1Q{wwD(Ez z2THcqet!Wh-K){InLZA=QSCj32O-_SMo)d&0evoy|wpVC3C)hsxKA`owZmYG#mi ziW4vLmigShDKPF}m{1$0y{BFG;-3Ao>WfRMr5~G(3_lqn(N3kq6&}R*HB7P%LLk5X z%{>00oQB}7yxOa6wJO~nOqqOcmVE_!ZkhJOr3W)>8A^wi?Kv}k84A^#BHSS-{Cz|B z3Ym|Glld$-MH9}u{*f`tgo#b+@CHY!>T5nTYJVRx;=5xOnP_oFT7cWc0>a&^ zs*7W_Q!unGbM0TloQIqR>%@xCK2AQQnEK(ebnc~OQpMhj9%N10yABRgeE;-tj%C$R zD@4AdfO+X#yOCZlV)(tLO(8CP?5K>lp7(b@5YXg!nsK~SHxn)SKIK&UgSE5gWTW<@ z_LipUEI;c~#7FO1!?4L!)hF;_)9VYqbFWIA%12&$=E^>C=5VThR@Sa~y-h&56k1v?b{cIc%-Y*i9E%W^L z*)A8cXW2ErLkF1FJWc%o1=Sc+d-!N8LBr;fWL=onj;5*8V)Q@sNjEqmmmO49Le?;6 zd@YJFFFApTmsxY{Gm@1an#&{gHeqnH5eQGJG2*!US&o&h0yGLHtpKT}fh1R-WDFPcpt|s|xXZ zGIL9Y^=EUL4C|olbtA=O!)kOfwq#CMEaxGpPNlSV~BU7Ke3QT!wU2{Wx5+dUM zgV;XEXzPp=myRh|gLq%k0`_z+2O^oKo(?HBWuf1B-Bu3)Dkkkw(h-0g-Ax-Z%2{`) z$d%D-GScgsUo3x=hJ=E9F;l|m;^O+Bu|W*iO28F)mi>}-2F4h_u`A8~zfUe`kHwS_ zR@vc*+$K3+B&Q|I zu2k?;GjHAH)A^G8rR=MNzLs!~)gGXYrL-0{$#5HK~ejcZEI@3-M z5(MAi_{S;6IN_z?aVZ|Tg$NmZ;WV-u8T_MDP>u(*|Fq!^{4|z!R8H!YRQvaS;{p-0 zFnW_{jc})xx*qdHvqzZXt-JTLoGZZMQR9^k$FC4wU*0Z$bBgiFg#I(MZC!@>XDG8r zO69JPPJgR{k7vfMpQV0gG8xV5^i`0H5TS{68NQ}|)4iJ$8v)<=?u*8V4Dyg8i?p2< zp2Vo+CEuuQ#W=dQlxpU1yHGt?#c8?cw0hO_WWjQmsjv3JFP7jOR}H0x_(cD{#wpD% zh9s3)UD+vSkx5olqE*9;$Kat<9Zg?9_j4yV|7M=XN)dQ-+16UgTFpgz*Zf6RJ`?_X zlLeNtTiNpJts)_GL91h{eYt_X>lMzVST8WRi!w5$N7nXT^`+f441y<2!d8hnj zlT~@bm;MRhr=XvN{Yi<|-2C=@u%ob=sI2dStU{Rq)o`!C8>N)YEu^Lh4bRAFf(yn! zi?Pgc-x9A!BktH)SU70oD;Q>$UrXH63hJMzc-CmIx?UI9#B58vnW^)GjB0;%zmAMr zQV74V?@_3epIZb^DHRgh9|SbuDJ^cl?)Cl zbzGD6g zem^ty))IAYGfVG<=tnfq`E2p$yAE}3|5G_R%bzzC6A%*URA`wHs>3hjv?5&&y5CJH z68?iv>0-0i3#uaC=@JTQ;LlT=h|#`3Hl9y0U`Ay(r6r97Ws)`FoxWWa<>!7ty8EQS zr4%@W(CUUQh2mBqQ+Gl+0zJgst9;b+SALX7HbgX;c`wz#J2oAK7<|WoSrh0F$G7g6qZsnbV;`(0Q z4Z6?Cs>TEU99PC>j4-1ful1f7s(CN5&h;O!4gGUeEXSR9N4|0BA>_MpwECC-(cXJT zHQ97+!|_tVLJ^cARVgAMM0zJGy(=xW0MdK!0U{Pas(|#SAiehv(xunXArz?rLJbf? z@`meK_qV=Z-&*fl&-d@1KgpS#WoFL3XCM2RJ$vd>*;1bSL>&~h2iD{bl}3cIE#Ogq z&S8lKI9_;wTA+@0Vn{R>={c)M{g8` zib@bT_yYd(ZQ{h<-7OLNJpnCMjl6b@u8OB|#;E&li#2YoT6ou{L8uCp0>}MbkO9Rv6RaEGFiEB%XTH-Bnvyz;g-$lcUy7cr-BN8?d$T^$D zo!hI8trJ%f#qn_NlUX;kDZ#M>lVfm+$>KHNl{0Q|4Yl`eU7{L& zrxLBKDH9iwR04+28X7cOjAbC6%m@$`$X;s;$eZXS1;cATmoUZ4ZXOH&E_mv7d^l|K zIELI{Z%Q4k^>B>%BSid8rIdVy35uMFQ%qW4O--P`6CL_1iu;6iRiF`t&s>QeM&6NS z8!B;=vI8&QI+W=9{z4=1n-;jpU2bO1j_;dULIasd}_$=EI*N!bm<&$d1@k zxL!&T3Mdg!1lUp{%;!9G|C|5y3PQ+DkvG}?NkXHcIQjbuuk?gs-}u-!orZa*0x$9m zQ;SE{8eAd*_rC+-g^Oj`Kb>yx)rvRyWhR6A|2%)me{X2_saNO9pWMyeMj2(!bqygS zV~Q9b(MG6Du|;;W{uZ5Z_uvc4fy&gPl0wR&jSo6C61ufRrAtNgbh~K$XHg;Cg;@7B^=g2J-KPHtJS z&S%S7$ixNaFYGhO2ISJE7x(0N{Dp_|u)l7pDp~un5?J$Mn$}lvV&ATcxvWy9iOhyv zjo-?OHrZ)iz!LoGqe30O3+Ln1;tk8>J*5Vo(rJ;Ik?EabLq=H#CC`Gp1&r|;!g8|c z+copw8j^cXNV55}7K6F=Cl$Uq6xNpzUS`GTrM-qI#tlukm-&W%2uOR*jNY}5e`FN}*z4hZ$(`_~_g7aacA*0j^zEGxVJ8y1WckmFoGN)eM; zkh9+LnRF`LrEIRLo!{9@xiU*CO?ygE{bZ>bMdfJ58HV`=;aYb`i}}K>sl+TplL!>F zmrPhi)RdTRZ$sI#zN>a{w_V;Y>L`!CRl75l%_(zH@BK7mb-#BPw>Q!>J4UKYz$wVh zcU1?v`zkx?3p*1PcWKFtYb)bRyMgv^(vQY(FYPy-)D=bVSQqZ~a_u^0j~dHFs%x%k zMPl*;tNM(m^S!Hg7@`Tj!VMJ#$H$2;XlRnE_(>>iqqcQC(K1x%pZhH={4-^-YMv&^ z@fQ7G8ssm}DE|7v3FMM*M$Eo0izd@lG*}Ox4`1AQFg;E=9jFzlDz51s{j-OSK9P`i zVKcce7XyuK0kK)x4pq-SJX0e;6LkpVjKroXv=71W$ikQLoQQmLMvH{& zw$SeC>RNGHY$HXoY^6ER3hQdO935Mzoy#t^*plOH$_KhnN4#gus);5g2xSDh+!o{D0-BIAei95Qgf zV*oU%4*-a=6L9^jwu`qHCbA7J`!NDnn*l@dLNjEwUF0n^ftN~*ck2~~PgGlf5AsS^ zW+1|5d4#-vJT-2eD3!8-??z8260AUV$%1kG_n#zM$xMgm-+|qO&jtC3ll8l~#IzQq zI}@`c1J{-85Kad^#Ys`OcBc%AtY97k;kp3@D@p_!O4eg{l$!Cbe-iiAcVx}_=~wa# zSutIeYbh})Cq&Je{ur-NbU+x2&+MkxE(myKKu=z{yFn)69*h~elyA24K1t78i*NeAEgUQ0I6q#&Yr^s& z&V%wgn^fAPYnKo(QK7hdK|wb$+wP(UVxRD5ej;V9=R_^YH|?;T^b*JY&y zd)8bN`2y3rlJ1g4{CB6nB!>|o5n~-niE^b?zIVaTWdu!F330a=(rbwHd$ty?XG=V# zXE{Ig@g0HAfyi(`ts(0f<)VQ;Q0y{vjM3g=lWtu}v-MH@ciUf9+?_e&Zr`^n43TV1 zR1`%&ReM>)DZlCI8S*ibZ7IGotS~pM4fnV}I8{^GXX1h5geBCp^6UHcAV`ChS-0m4 z)pPuF(&}Wu&5~9Cp!b?aO?##AiQvuZYRNVGhY&iFI?|mgg73b3Lx}p+*tbP(Tf&(9 zNlkpg3eGrLTe3qI#@`jTgO<8reSP?hvkq+UC^Efeb1?HYI`I-}KJQho|8dByF>3ch z;~d1UN`TADf-Kihk?GCWHU9$FqbQT2Rhj$I%-Nr6VMR{Ssf`n4ZFv=&O&RT_zNTxR zPF5HCeojrt>qYTieUw6D`l%w#E9l1V82#u#=bkkxpvj-WSVYqhI&b-vIAwX1Qv;Io&$b2L_B0BOy}h-eyyV4-d~e3B!p@xUx#X(++I00e=R^b zoV!L`qK{Q?oLh{x;LJ@&`JWV#0$gqpBm@v3>wg(4Ru+`*El1$)LjSc^H+dfM-Tu)= zdeROfygn*I4L-E8LIW*q2&|?w3qd0R>Kv;`h3*@l@Gl7MKH2sY!Jf0AkBpe08qG=It;j%^1}_LSi+wb4^8T|60XRX z3khNpPU!023LkhsFiA@h6!wG0GeX}iKm7evzsy;pRqSt;hB|X6{&#K@HuDoN2|{Ga7h z7uPaED5C#KQup7R{Qm!`Pux$vZv&Psu2zSkn5KIK8gjQvW%IP(J+cysv*n#l_D7d)(GG{Y$Re(J;#>n34i~*dPMTOv=JEIprmLn(lo9vO|vG zkHt<_{`qZdX~kQAd0%A$(RSHLSmTaq;s>}i5~N48YZr*MsSTa+Oa(7!i5%CmvuYe) zrY@dufQ;{@d9JU%IX=mtCDi>~^rhD=07q|Fbq!GouJk%5ql+D3LUP%{YtcR$WE?P+ zSVp&}#p1OW+ytJbF%fb?2mmKZ`t7-SO75jJunrps4uAHq3*E9=MAJ+=a@j`EZnILq zFcRhI4LFglNH5AXGNk_wTWIPOSdB%31g5CU<}Z7~QgD>_QWMMij$C$=Cayao|^{N1kkyy)HSz>Mx(3QnH zuIGmYbk~|1C@GM>Zv=?4V2f^iKNfqRcyrTlcPb(FGBe<$LEca{=kLgQ54OSmcp}nt zw#c~{yH+|E8hS+5>VdmRB;nywKkPA3F$p+sKsc5~g@y9{O*O&HVLO4Pf*i*DlE{N# z&;lm#6OUDUsGP`9nxq&Wc-^~_4%z^11OZ9Mgowi=t{f&K{yIVzHXjUcdeQ}Yj+l`^om2Tu)%f09> zJ;1er+Sq*$br8I0!9Bmjk+NnjpY^otxU0pr;TE&kivm2yt$l!QCH^O{ouH=Cevn=BKZfWISe+{F%F0yk04=Pn4&vNX7L(of?XQ!eWovkWH6Tb zd#)b?tsvg(w9d-=`En|oPrJKWi<_QJ)@ zK+}y}WQ${MX#TIec+Bj`@cm{eB1MG1ho^P_<4BF*!f76zN^fMbppM`25cnp}_Mvqk zx_N+`8x>gJPEA3PZPQT+tVwX>ov&&roTWZ|lyNq&em~sMyJVr7JvMfBlCE5C4sp`* zcs3(l!k8@DP}*&Ue3PNx3ZC&6RC@!ECQL9JQC1ewOsSW+rK=dewM9<}vJ~r#OmoFg ziv6KutZvQ0iigd~<_KubFEc0CrJs9E0?!tWzFUM^L}o~Cl#pH;SW{WCF@WpH_U6{b zkE#C) zlVQ(GDtjXS@G_-7c zknN)6J5q>ZPS_FdlJeVi!54X|84!#H!=D4FWUy=vW9bV-n-%osGnOoV1$C2ekNg}@ zk4JW+ACo>lE=>lRyI?*Ek=A-{;qvyKffpX;{Z%xPsoKi{^(!_$(GC}9#NcLXM|_C= zT-Re(?TZ#}JZ7`e$-c?scz+Xi(!ZY%g^hz-%h}4FBWB!3aY?+i0BL1HR}SZDDrodC zRv)`~I2iOXoh21jl5C4dPN)tjhUGuqgP>$Y4hhn+?LwQ(MH$WBx&$>wn!o9vim z4Y(;U@6^a}N3Pmu?tXr?QeqmtkMD6+o4(_t2yy$qX3kHLpoH2DND-6RvXo}o?urw; zxOR)?3l-@Ie_6ac%;`_XZ2IatkeLD`o2A)VI1GLSsxpC| zatKVUp~KPjM#@pmsNPh2l{E#8;@Eo=SN(I)ADrzyyg@d4;h|IxU&Ee%x~&UHBTx&! zSG14n`7V%W%v@?xTg)|*$UmFEO%2Z#&1&Zj=3+G`NaDYz{Z(gnUDv5PQa@MHXo&Nd zH#d)CzsL>UdZjh0s&VMK!{f3ZA-(CIz1clS=Ip_}{ z<5c>h)PG7``~1%0@fX7h8^bq`OR;hw!`jiR<1s^gZA;_wcpfly4(aPz%wzU7S%j<8 zXgYv^Y0|=QssQ!8*x*Q>Qvc&GElLmNbD1Kybhk?#J02nQ3qyyfV4MdKp9@RuG{#sxn4vg}Ap zIM2J1g+AX;RsOn?yz)z3e75Y)C5TxD8VW|zYWbQiA4#Wfo|0~|$?pjq2F7+4B+PLJ zjVtLgCAC{Vh7kAAm_R@#%f=t2#07EahS#2S>{6sl zi|&}7UOG3|G(9a=6A*(gbZ?Rg%TZ-`j#;ATYDT0E$oJf!0=c|Kf$Hs}?i*x&J8)v0 z%B6c)@ULIbFu&|JMohen|JDe3<2hM)o%hd=OQo6)vK@E;=eOSNYs2Qw4<9D}I@hjt z?VYlQwbcw$#{8bb`}HsS3}e5z^O|tQG-4LjB$k%uOnbSe@cWA$u;iBn8$^oQn{DIa zZ#dIJVirgIL1MVb0&`HEscL?XnI|Od-RyY<qntedV=3UVBEsUV!DUBs}@=LysSS zuXZ}_$^G$iC`nR34rB^h*LZuP2EzX1%n%;G?_&fMgsF5a*YiPx<};~o9C=A1{=1uoBT$+s7WOfMYnh=f#wzVs(~ zA$BsGUFZK8^Dd^rE*+t|CNSTWowegMws?u-=8z2RN^PQ3z!6j{_zZS=*3+_!fN39L z+TxpWYYJt9yO`ddG^_@`c{`aqag(9#>!7X3B6fg^o=@vrj za!2(IXOieEN8lo6rmmMJqu*q1!YwEO+7n$WM8t&eYBI)Q)L0wa+_<3QsEjL|J6?No zzKPWD@DMS=9HyM=hZqnE%sDs5eH%nQ`4D~cg87w+J`%qvGLd*?*SAM+xB){aCR(2f zsh`~}!q%Bwbf1jiRyH<^RbU={RK5XFWEFi%Vb&-qXIXFA?oK~7GCP0gZbNu0 zcCSHTkqX$%oawSMo@y0fCIK)5;(K8lZOh&usK{%H?l`0Y;! zAG3?Pr3hYq|EtG0m%*~qe87H=6h?a|62agXiwLS9)|@6gz0lq~%i377f6he-9BrC7x82wG zv@BV%)<)2Fa$aTuaVg`9(@zK-CVq3ExE&mL=v-Bsc3GB6UmY3>T^*-^Z8WU)$Cvd+ zF{Ql+qvl*k(t%ROlw&L#h5)w^m&K-z@eq9qdQqkKTG_u21-$q`*Fqp5M zW>h0sTr%Eh-r}qBV~H#Lq9h7iQIPTKs;8}_aSa!%JV229k~5xyb6gHN2yUj@w4EAl zJcc<&GW(Y=pa&aIPVpJlNFZ<*1RZ1lGBk2^G?rOv@0yplxz2VOZ&TLx+pqz7h1tR6 zzZ1P`CFV`hsX_PCn-m$itl#&Ju=hP0p~0g~4?5d^FBS~;xd*x(7hkZ(Mkb_qYP6l8 z$Qkpu&1*d)jZYQ=?)N5T(F@}zsJN$@ZA(jm`LOLxBy+=Z={<^fRz0^74TmPcKknfD z*5jy6U53!F)`P%|7W9!IyW44PHw$GTx|WdVo&NB1UDz+Rma~FwD9#(TRb-VG|8V|r z0pZjDbxv0|B83mMuMW3v872mvVLSd}uFgQ(E$0$nqK$C}T0AY@ew=(Hmh&v)nzfe) zhbhB~>1Tv3C)#|v{s=btO-F%nm@mC&^3ayw(l7HCJth`?Q&A+*ZLWb%Zi~1}*y%!x z;hUDL1a=3~>6v33E_I=)%=pluikgq(>R5z{wi4aU?BIA}VRC-DUgw`%|A(e*reg1` z&G>XTC_mIEM74QOBAhoP$w^qZrE&EO-e<=pZhyczIW*M%FuE0Lh*W_MrCp3z=S`JC zSLoZYKL#mL-@eubK*!|b#sf-D>G8EY9OU~Ym6RfjG2nyJEA!GMVIGdw&2_L7evvrD zYE^%V?<8*2ss53IXEznZu3w(*r zIdB_yNjA??DhI+2lczGZESFa5WzLCFj1;R(FTOK^rx`HdmV?xMr+HOo4~mG}>KeP% zXNFrAN0z!o#%*mPjfWSInMq7))3`KS>*1EmwvC~oyUxDoEyLG9N}X)yv*7&+2~FUc z03eNokef(Uu5|b3G!M@UL}2~vqGGv$KyS7FBK!qx)A(|f*-qhVQ)4sAdlqha8Wb^^ zmhCKHrEcdZ=V)tW$zy7q)wKzodLhh>*axAW_&vkxHj# zE7g<}w{rW@$T}X{hT|OjvbN1yk;>t8uh=5jp^y63CP{{kfrdtGxTT&e^yIrZDV8j^ z+-Rm2*hpievDsHLohkY5O-AwO@O2I5@0*8nJXAFXk}_?lRpF&flzLa^NR53y>wx`A z6JswAq0iQTj%F+1BPcGl$9|pOBaoyQt8@fStlOI(DK?y=aKeYnDc z%hgOoZo0R$#}?}yJWIw(-2xwQ?bI6BwmQ5H@*DB&qpHhXLn7b6&s(RrST^f2&)t`73 zg@(pRz${J~O>poIXGh(EM1TBV;2gb!^79);WnFP%+5ZX@tZ#qX?~X=cD& zw*7C<;$ZsCSZ{pg(>?mSOo45^Y%e^I$^zYC06WrJB?hENgYFt#fX(RInUj z+VlMz^u;8wBydFx9KqkMa}Lim61Bt^BFkFcFQP@df%QiqpsI+Uy*LG*+a{S5fw8}` z+XtHzB}2!^sq^xU5%QE%v%Juqkt!gh;hFYTFAP_H9B%5-RU zaUs6xqK{@gceo&MzlVcGg_kZp$Io`N>&zYauX3$rH1uXB8K({pioxV}m*)2ycQ>1~ zfD%WoF?wZc(;?7o4U}T6P{}C6j05@+tXDQq5uZD zj^twU|G1wu`_5)R92qvOD=IF1!OA@id5Ppu2{-ZC1&VRTR5sepCwZdFf7?fw&dkw1 z^gSIxIkfsvV?%xy&s;Rg-SY$y)Lvr57uEixre^whk9qf6rrHl&CaCS{8QQ;~toFzw zvtccprkR{;SzkJZ4;kPv%L(={DTl1hz0UXC3)E!tHBkzN1|2ckn@LGqy0eonvQoiq z>j{BXEEG3hXh?BDGGModosLf2}yE?mQVr1l!COp@&8lz(J z95+{%m^Q+4Rbwj^f^x)APDjzSicBvV zn_q`e5NTiK(uy3G6=(fb8acCd`=v0v*@h{qF`!~0<~WSo*k2;QyA-zPoY*$y_k*`k zZc4K5YFVy(4O=PVcrGTx&4gL1P4_e?oW^1LI*Qyi)xMsr*X`b^L4NA>3dyz`Aa8re zrBfRNa&U5;Wv$!gwH?!}yTA!m;hZ&Fp_cAIHIA&*spk4R@!T8_qzsZ8Yo!@<*?sda zDso77RormQ#{CK1LkY?|B6S|WDwd|Iy1X3%+`uyl2SpQ z5*Et6(%!$W6#Lfwhg5M-s-e1I*;HxZ0W?}lcW;ZBF9pC9=We2TR!>=K*hBgpXuxKzx|XmSl* zOCCD^GuVoUWr*~(VGhTIY*q*pv~l$#F!OTK++3s>QM+29Ru-=y7X?zx<1RFCU|hPw zG&RjL&uAUFS&maBMC401`z@B5GY@$Vw1Tj{_;FN}GVlC(k#)5D(_XzMu%z4eaXPj7 zmQBF2YzvWY{SwpRDKjLn{nze`vXw($y9`0~0eN`;{QUjG&Y|{lYKk$QAS(f2Up8A> zc}5EYEIv2x^>@%Q$R`%z7<#eBHzR*AEns8I zfA9N>g%{ZXMknp|I7m!VW^zKp-~L_?75ico`{b7Y7^C4!^NCuLHSyw^0aZKhcmsf` zM~*KQ;J52a_<0ZtX`n{R+}LsNu&JCnmftyNryL)209w^W3f)DSPdWh=Rc?>zM&AH-9<(VdtQ z`7M(K?aHo>yy%G5_R;9;#Lx8<)FTJ5^z0b90)CH>i(jD<2xZz7n zaS6Xpnay*~92Mp0woU4CZ`H(+@k%7EqhBNT>fMc2FvF#-JI%VjqAIOUjwU<$&J!xA zM#s4x)L89jN401=>|nW2aN;%{#AG;wLD*!b+0tz3L*hedH%C+`^VDga7|3auxE2YS znB&Zi)bQl*xjo+~x)lWs)kt>=3E|Ue$YU)Vl3ubB=$!JmWtWq;bxO=^{Cy*dRT4 zA$^>eMg$mlAFM(?dn{Z$d*x~zx5TqrH1c9F7*K8o6!?ikbq0Tgjo^6n5t_b{2E-dO zz0%;-7zX*d)v*A=YO9;6LF{xdUNDf&(ODz)L~9Y9{ZSTjf-lM%O49Mt)O8N2Z_aF- z66nHh+|wxDY#EWbuXI0gDjw#tbvbqY@u;7Rjq=6L)(abAsx2_fWw@67j6)^w_QLo1=E5B%EGu zPXMB1WLd;bZ`dq?+;fSQ1;tx55MPwkqqp7N8N5+%FJt#WX`nbmEu&K517>}(Dd)Gj z$ys-KLvH>)yo>)kF>@zF=c>PP&USLBuBlG@MO9#l!_S9eVnm8Ho6)~Yu%^fL?BIoG za-@&Sg+{BnVnR$h03sn%<{Eb_&DM~Q6~8Lp^Ml`%RQ$oK*lHv4vJmW0&ULEFa~tr= z3%T|#)6H#7$=69Al1vmK_tLLrBZ_AR)-wrTOBVy^?pa##`Lz&z_Lq@S(uXMN-#qtV zp6d)Yf9mn;PpjqqK8rVMaT)I=BFd*8f5;*c?AxROV1ooqur5jII$)KAOLzLZAG1W2 zvTLQh%6^{%YrTAmAJDcK%hbqzTArOXm@AoCbG z&)6epOrk%#^hX-e51{p5ncZ&}H`5^u5K1dHUi!U$conHuvPqKeBWup)+`-+&PB}VS z#`MV&xC--|=M*!_?12H<)EXX*e$U#1ZvcK2xoL(6JR_mXR0GyZZYjejxqbYdd?8A< z5UETR-ggUo z%Fr_iMPH7XoSVw;;-#4XD)HCUs0ofXO!ueOGYR10&o|QU9%uWIdrfN!dB*l~X=AOgnTFRggHyMInJ$o4DdkgSD zvQ_oj_pf5N`lwVs^V2gCFAtN_Jz#_flPV9CfeWE$3=eG(-X3l5&@#;L0RRe4CE3^7 z>Z&&#b=vq%NNX!g(-T!z&8=ib8|!_g5+{eoFajJZTZ(!06_-;HO!I0RTYn!Bwv&PH z803~B5U&VqtKT5bf9?#Q(ZJGr%J5}E%EIq^TzGiz44AdENO>4s5%r)_{?k})W`cKs z(}Ag{v2v^HRz^Xot=k?m+4I45R0IjW*bt-;u67t zCsljUR(h%>dA~0JI_wZ_RsdSp5EN!?0K_wC$;|9!2^*3XGD^|D^`VOAa$0E zb=Q+f*)?Z0(4{%r`4x($$0tmPE+q$)T2}Q1w=l(H(;D<*><92l=XZFxuh_y;_o6#? zaE1b#J8lICm~BWMcLmCQu2;I5Wgw6t9CzgpC~vZ4YXz)49-c< zx-7$SVsbs&kT&dg<=+=m?_Sq_83;U=6k6UJYw~(4LdGoi4K4|HyDgS+EZi&*{gaNH zTOC`8ypj^)0bh7>;0leG!Ko>WbM?P;^`{hd5~d0U6dQslxV{Slw!(FR(oghWo+lsj z-GtZV)uHrT+oFV}$IF1y-+CfbmpV;uV+&_TNZ3%p-%ElMn#h~iSpCjqUk_&|`6CSC< zRw6>8x03#WcRT)$J|&1xrjz<2%0z1Cz76-wSWrbHdjd174{|hbzi?{#f5nr4oT| z8GIqrO-@LY-u7}oWG`DbC1nDHf_Nz^-Ap1+Cs-G0FJr+?P?>_nHZT5S9@?8i3rOe; z{USb%b#_$l8doCD6j%`Ta4~Kq^D*AQ2&jaU>|QmL7=9~pPKuU?>@eSNeu%g<9hRh* z+3r3@1)hMJZUa0ez|8l2fw*4B3K7CSeBW#jMf)hN?e)ZK5!0ER9S#b9kH%gi2+}KeetrwIE&k;5XxtmGWb{s{^k#5dy8f3=4vh!X z&+Jk^Px-U6;-C#}=)UxT?P0~|O zKWE$%#WO!WdBnPBMkERmivxe^!^g>qx0HKe5`nid;>y@;v%D|%!&XzZsrSv^jEe+L z6pkq^TBw(1Jmes5G8$?-=#rlog*;-54 zz{Iwk_-)d=+G*!qbGD^h?z{kO4%28C+e8$?qbFDi*Ej}^;0d2Q=Xc)Q z{0Z$|fi&IA59=>N5tni+n(16AT;SG2g&huQyDX6pnqtteu0>m1nZ(6Qt~-nl;ftoGW%^uK6NmROv{s! zC*Y-zLygSon>}R5=WCEOG+P-SHT$pPVJ*i4q`xL2?#5xOS`Bp-g+!2Z`us!N8_X6! zP`s;zL&VVruA<)>yu1 zY)oZ#aBMZ|n4a@6>RSRz-1{n}vZDO&;GFvxyCBj{rRg1~YV|V5QKY9JElDF$iLP2r z)k&rY!!E}V*9+~XLl{X8*cKiyB+@#->v3>&YL8e15Z($pHXmeClscwOy35UjT zq|v>t+%zEtcc&{gQ-po{a+39erKBUgFT7XRifWn<@G6)TvkC6VzN_Hw31DdY!_0B9 zw^WI==D7)A2-#vBfijBgGSV~7G4_k#8=M0g$N(Q6D10WzgI(T!E7v#n^L4cAA0yhy z(7e?+*H+445))%$>x#b7zJBl3yiH2FIz$qW?4E}SBv8__{p#;8^N)+gDzvnp6H7$j z7+7P;&e0x@{EpZkba1|s?Rw5t<}B*!;0#}5DB}1vb|wE}caP@DFRFNvsT^EG-Q3Be zk28E0W8Z>0Ar}7x3?&crf<#lnaD!@nnO@^Cie6rua@E!>tx@3%hr11r=&l)drk(j4@o6AF6!nx;0?1kNbJ~cDj;%zSXyCG*Dje8wub; z`F)03E>(|{KRxdx&<=2~D<3@&>`0fhQ^qbz1A!U(EHfL-q{Qv_hv@{XJVQ*1=O27_ zv9&=lA81f^Pfwb^Fr?to+2cdL8}Yrlj)=O3<|R>V8z`{UMPHOl z80)&UL~}`Y@k?a0u9H3(=Z);WH!XMf>ZY2I2UY=FKAN&N0mItuqGmnHy6UjEONzs# zJc@IY9vHX2ZjBeS-57^yE@O;Xku&jgD)UJeQR@R zzd21Z09mA+18LHiAJeghr97Rq1pxjmNe2d}nbiJ4p1iF?sTwFYXG`3@E%;3{(`J4= z{nFj7hD6ZPxo__*GUPrg>?kNhk^_2qzT=K|eo+9wiA~9f5zMg$Da{G7%P2Q@u;t8; zM>>i@e}Mnmdt+te>#V)?0|Z{V$?NKt9lX7ptdFl>g8g1QzGy5g?#I~O{Phc!!p8n6 zmm!T~MJp%%h(YIJcE3Sm-rHQ~^}Wy3Z+eXhIWHd6^4%Dob~`FWDdX?zPyd<(EFWK3 z$evOs(Z@kV9-fr$9v^9%}XS~I{?ZAnKCDpY&*8|^W$i=np4S%rX!mON;wq2f> zP=XGj?ZeyF%5cD~5a6wn%60Ywu5@*qUi*o2(4t;x){P(fT2LKxEbvX&W+757GbKAd zF=0=HN5$p*O({OM;69EJ@Xr>aK`nW(9sl5{e&<EB6X|1=b(&GW%?lbJ4O6BjkkKPp2lZbm=(EqkiXoUO(-+JVkz zP070c$7g9BSyRSs&QA%lL7P~8H`HB|joGpJ@)>b9m*~-I0gL?B14eO=^{pFayBck; z^|?&0>uH!(qQ&hDpT_);d@yg|3GEjrmC--kz8!L_saKv{s%`T_w==vZVUTYsGGjun z=!`*`uNqsVe|6UCmBHEIXX@ppqms^PIkAR44{G(5xr1I~}`iQ_%9KRV_7^8#*WfB)J(xvm`lTTO9(QHwzd$XY{;4QF)xQxT@BHBItz3mg%XaSGUh>tB63z2! z&C=pTZu;M?Dj$nxjsTM8FSne)5f7>P-ur4O5W+mN9a|yy+G!MDl?fBJ5TrdxnFp=( zf3ADR|B|ldb%%N3_ft2^fCAk|OWh-h^SSzDe0}|rUS9J=cRW2*rDmRy(qfC7(yO}ITTNu^3)zZd zhyaZh=N>JW;W1KBMYh(Z82oOB7+7ICFLgr>8Ws(b|p*i}P zmFG7rHXzv}Cr`dsIAB9a9$T@coqqf`fAm2?*8r>8JO4p|D>tG)TZcV4(rM&uZwbP6 zeD*bie!qJ{_+74M*sa%N6U_{1>`o)H=shiy??24|A9VYwbeMqh=w03zqVrQ`q+3zX zNqj8J9fp&}w(P1%ccZ_5yrK0jq~st?wR`7p45dw8{gcRDPIa%F!TjrI^U_7My9p6U^L$_vBZale#JKXP|?3laE zLqB9_m3>|v*C-|M+>2Jnr80#G@S|U#=$APrm`EiD*BWD!dCna+IS^r@pm+b>eR= z-Rb%Q0$apSCdcZe2EAKbLanjea@B8kI{%O9bwV^>{+5b6zw6o-`cCD|KiG3^+l%fR zPR zMX|z49de84-d0$cihW!h`4SFiG8tBn8{^;EIQ@?By&DJTVXk29TKV_9+jqC^x@(-{ zqIZjYw-Vv5l86*Z&)~(9&q>N+jT@)-Jpi$1WDIJu6qXko;wtdNF}De@2zB&9lM1KaFfxV{L&`cuigel?A`UXmQDVG#kLuhKsAI z_9@TltH^DM(0_VI*E@+hX2!(MK1Zz`sH(1hbaGNfIroV}__sFU4(z{p zl<^KIaK_%*7R{CuFMXm$_QniJ{b~|YIL!|*N_=`5yW2K0{YcuXj&P|-tam@ zZ)}IFRD#*_a`F#|2z@1Jth>(r_Rk90$?Vy)XP$ZF_sAwlK~4he8ObvM0DvX=SxgB4c%ljbJlw{3 zh-!gagpi^RPrrTEum=FJyYK%V#4%!{8s7jU#Xf#NE8Ti)-^9MNd%ZM5?I zD0(2<`zQCOEq)AsG1kz~n0A)_E?ik#%ekq1-~3%O3qMxFg<3M&!Sv_gjmU#03i5*@vlYv%{|=#01>=E0Qp-JuNWb1 z?)<9!cF5n!xxB`EAizx>U}K23%aSHPHR~)*PWNn7q*2B4XjI7I))008=L*s{Nyq=Kk zppwzpMekGL_x4A8*V8ASTAZ9ik{{ZyOXR&iWN7&L{V8#d#Z5*lLzDM%m0=ChsgS>= zDVD0M8_ep-3>w3EZnNA`O~-ZfJD$tZNpCQQ(b~UvvnYx+6x;l0-zYxA!3l|@R|X-~ z^Kegz8|z5OkJz1`k{oRH_&SO7Y|lCOHBMRJbZ{AxP7w}aXa~I*Y;c6cR~gd!Qar6V z^1okV$J?w4T|l&KOnZ$Q!gAovzE+XHu+_K=j;C>~)`l}kK8@4sW+Kg>{ERsCgoDGH zL;KD|btiIMRMtCPqmq}NXYa0VP}<5K{1nsFQ3k?x)MWdDn5>o**5LXmjq#{Zp)7~G z<-6(f-F5-UDISzdIt2Mewb~THU3z;nLXI_*Dm_iN5#}5KIndy<-mo8QzuSG1L7dP! zGp|})`pRO39dpH{*=z{%q7Tdaa0CRZy&j4VVjhu&R_?OF%Mz0H5a*jgIW!f`zl{d@ zS)HdOVRbX@XEi=dmmXl4Nt3mw?}&%1#bkcikkDkU`T90(cv;2e--R0*oyJN!IW?nO z*VRnQCJPkpnU>Tl#fOCX$C6RVWL%tpPQ01^T+DJ0dqdM4`wT&wMtNd38eo{edrG}c zgFGGS`MVyPckxhBw_+SCp;(pOFxR01AR4DY4I%_?>-vs?hoZ$pG=);$U2Ud!kL+DS zV74VGk`H>M=UWi3rYfze2kyn@4ttmq9|o9`ee_654tmGTGE0|`D`9gBjdnC#`BW^G zOu2if>9WMv3RkzwQesK zVA<;*(E3E_+uPu(>}Yk~Lq$37;8ET;Qqe9(>s^Mxy%_O+}TK9^5K_ufFhBRdt#kQ)R^aK9~m!O@Q>3 zUwe#|xj*w9DBnNUO@>3TbJfh9geZL@eFy8865Gv%ZGt9;>{M_{mKD9z2dhQ`pF+>L zJ+HO`NMRYRCWP;AN5)4=rS~t;xkT3|jE6D6-A6>N7Xw?O+e##YXAMp8)?uj#B}s;Y z<@E(^b=WP|dRtjSEmQ)hPPkIv`P6Xk$*TUd!`H9fp?13&lcsXdD2bR{N)BRT3hshF zzQ3RRFt!nIn{)RfWGSoM8?$o($Vd7iDtFI)vGKg}b1z_ifz!Sd^61FM&_fEG~# z%cnahhrKYG}yY=ispC z8XZmhbjh-OBPUZ;SwF2oXlz8V+>||NxEeUhQ$Hef(&+R6*SYteyB<-BEjd2M5XKjB zI`Exfee~!NYL%Ajy|ViHDN-4s!J(xW`}d|uM28~}us>U&)!$)n zTlEPT#=e_yKTTlSTo$Y{qIk*YxaXTr9?vCMtQ2jCoF5_@aYwdQ{mA1DGTJ;SWghKs zeetyaNsy#@w4tbkir+}&L2BBFJqO28X`tD#oJ{}k4_uWAzQ6U_Tn1K!ZJJ@f90NFv z^_PdiMIP^N2GfobWg$^rB(Ik%8F#Co4;7s5yysmX?5%13k?530mR|2!Qi`e1)FbEjI4@1O}ji)-h#*kh^jgeSXV z*&3YcdGk5ewIOQE@!OgmDq>p`zr-rT7MBwL>fv`Kl=DTC*jOpaOQc(qXx!W*NitN?-`nd7z z+@#)>+upvgj#{0|X3D!PW3}NI;^@oXf7(3rS@tbfPKMMjLS5jSbqR>Z#7tZu#@Uu3 z5exZt(mDJVR0dXe%H!vN*(mFhA{|2fw|GzbxVRCOmW&k=H4ItKK za!}#CqKWmkM}t|WXi_nFW3JkC1<6(M6O@398e?cG9MyXV7`|eAm#O+dlR^3&q^|fGLDENy@8) zyGAI(`sCVj2xn8M9Zy77>{GgG(U<7l=-fS-!th9L z6KtW8gNdASW5ybfGWIyjoi*P9P@?Y=Aak#^E;S#TeGyY!8{{@Jls@?VWbG-4SJdJSr-$uqS z`BWvDnVIcc5AQze>rB>v?j}674fbl=bo9XnK{4mT|g9sRJtSk&j zIs_C-Go_ z_5@^NBo8`2*bDuY$;!YqMJiUOP@#^};T zh{MsG811yPs6qfX`NI0qk=m?U6m^l~qk!?^HPm|s>os+ejd!5~A0$GRh2L}QDnZY4 z>+n#uV76E%8RfSqM4<*8NroqT2Y{(?<{C$R>{_d(mxdD1V%%*UoRsNz>M;TJy=$($Y$bE}T@GPIq?4cB=3@)wtJMSg$4z59(g1RbSU3x+g5^ z>g($rZMQyQrPh+v^=3A(laQF^20sEPZ8=)8q=Cq%){1lN)1}JPEbT7*W3|ld+;^Q< zbc{-B(zqSBLX#%9#xnR#M_U&Jy_bsoFgli&m}zNg`S}aB3W}*XP=x5otTA0dVd9z^`#U&1e=PAPf%j~GXM&Cpe*y`80-B%SohiM( z+2>kG+&c@?C#9A3vi+0YaDNzxhIK{wB8%)<^x8QE1UwLTvc?(OU_^^z&L=c9v~W`X z_C5OVQh9FXH`4aoqwTI77wNK|H|M&|2NX!{_O-bxLj=MLlbAV@+I)9nGrvq2@v`0< z={0GnL8P27XE9Dy$e=c5#;I3!ecBsF`c@+J6z3SZ>H||&R(3v^({M&#nBQG?H6352 z^m)%wQ#{eBG?L6k#`bM>l#D+*CPq*|0PXo}1tlfBKX*?iX9_aB78=KZe_8@g=zz(}zYwq!+xw z=GJv_?u3{{Ox3Q^2;$UvFn}n!^}aqVh{Z3HUXNc2kRgq0Ga4z<&hPFs?CI?_Sce0KL3}kJ;t0fxKp0yx(aCLj@d9rDm z;eFZTyi!&Yho<5e5#cP7i9~p!qqfl!zR~56lg0zGv9UQ^IGSPALqy?rj#XS=JvHo; ze|bA!fJ|pUd#9ykU8Y9>Q%8*Dy_E>R+S&)HmTT+OGmQ-n>RylUh3TiD#Jl42>r)PEPTg+G5;i!EG z4h_WzrV6@`4h>l@URCAciF~?$`R`VJ%Gn*y=_^*DP}>YfL4%8nizGJ0bqbF%2S?46 z#q@B3>6g6dipw7r?UzzDTO&ZxfU$HH#1&?o)O3q8tIw}W(27^nFp#fIvmrbvC_FTj z0BB@la>IRTy}UT~WdJfaS8FwGHx$qO^yDO(`qgv)8EZ`nK8M20%t{*chX4guAn>N8 zrN#O=gw9vJabp;ztokKlxCqtI_Nmi zaSKKU0ed^U7UzAPFpgQehiubG_sauMl<$JOHjy{v3L(w$YDg*eB=mTNdH#+wEEb#v`gXhu<6_#4;KN zAETi$sb4wmf+mCEh}(28Pjn+Aqt@fjZg=ii&(W0OplA=lo?pK{<|(}jgCTIZzKR5f zg80%Gh&(m5FE*>@50OsE}L zPtdC$P3I`7#^GR~q?Wd1l-yV>zqx4Qy?GB|*5St@2U-)1yOYF>;TEnRh$hcx6o8ffo3fc2pj+GBg&U2>1CKFw*q;nmtCySqAC z5ln5G`A?$$ZA2dU9xG zX3PBdn>kra1%xL$M7lCu2tjGqFb zWKi7QAxfGEfIAM&B)W7A@0-t0`lH?!yTmdLC>H-Z#6ZKnxH?Ml(MfO5?9Jo~!PSoS&ahr4*Tazt$ooBqJms zn97&cs?%IQJUrarx4)Z%B43cbCObVnm68hf!zJT$`rxtiO;@+Q%}4ZJBd-3zc)IJo zbx<^CnE<1hyM@CneSSXd>a@XOdyWYqARxFxwV+OrqHrw=M4*IjR-E+VqlaDG@xt^I zUHF69$miVtMOuCC!+jzwmMEYweFD1P?I$Q zLg=F%8Rv2Gd#gf~75VKt0kTGlorutOhd^i}Yr;Jc4LA+mNjz2@Yk7EBhF({*{*&TQ zuKgMwJ+wqd*_)hOCRW0S2#17pZy{X!TO(;l%fYd!ZlSxTq}O11A@$1QYtg%_?a9S9?t6}ko{9Q zzeG)x%l*L=2oA!>v(0WZQw#BY&>KOKl9Hlj6XEZAww=871Q)omwKa36S@_-jc}h!w zM9)(GNgdiHLf7dVm=6@?&>*KWl4iqoWO^F^5RVF;Li--TXA9#rX&u6A~Mn=rV>L zcl`EGnPxp9(8bNI(cJ}QGz}&;i1!V&MMN^aH=+yec>Dq=QUqJ7H)A#q0+Hph9G`^G z&bxWgLM7Wg_EszSVd+g8)TlTRblmDzLxpmrpV^%SW9^yfBtvzp9JUD!_rrVn@xB*-+@@S|Am(90 zAinx5V%Rco4Yv!|79Af%WPm=T(PBn<>}Xre0*Kw?=nDOQVqKVR4Y6KdbLll6<4k84 zja@8)rxv;`dQZ_RUrI@}?@i>LEjG0+yKWZ{>v{aPnLay4`(YBz-iD~e=14?5L3b{7sRysFhD$_{yPL@tr_XM~ z#rsba^h%q&C%d<4Ukj7ty*Q(t;FpYMVrCA&!Xe``N=!>j!_7XxxNH7U=_Vi`kZu8S z+Mg+lrWU-IQbt*PNTaPX(8FWi6BYb$*f_jpoIMr+0La5paC0nOaNq2z>X}d;H8nLF zIy!8B7BpSVmqf;f0)T96nTu$T(VdwfZ6`m1mE^4MuBM!b!Q5ngj{78hHP#SlM(KiG zo`~u^m-UvC!*zjWPd-`Le3hCK^sd#hm~rJJ~c+7rhrt_12jzfayW_8^{z zo(I3$s>FeT_A3bJ&#G=Z-^kMB$1cSNU8BZAnZ*fb6O%SDV%$$TOeJ5Kv=NEYQc~%B z#=R&PfyS3k_JPa=GF$uzfw)~>XpXFE9jld4Eo~$ubTsM-rVqeTtJLB`iAAyr0#ajo zlvBYC28cfpt#z4Xse8?H9kYHW|KXX z(Tkdzh6V*fRa@o1e*J1-?DJ%Aw&UX?T^Ic|-;)u1qY$%*L(5&%&juRoZrMpF79;n!d+ zG*NxUsHCJMdr?z+%(L8FF-l)QKUYOXMOkc=7R}N)o1O&*<_!rs*gI?0Ro^}H9@R4$ zNf$%~{$R5Fv(2dei+IhOy%+;Knnmu67ndg(4TJFct>UO$;!pnXjXe zwMpkhdZwP6K~z&tXuK_2OrkF~9{>!@%JM;RGn3}|;Z}xMc~8lPhI+C^&s2ZEKQn6B z;Oc6=u{3woUX0pr_gXD$H*1w?+YHyNFD)+m;&PbCxx<#k9h-5#E{!}+9Ex zyYkHF$B}i`kjo6D_9YD5=6Nt`c3J%?oJ2)Iq0;j@RLEtUdOSV<2L z4e0v0pJmxuO;u?;LY>uasSubv)2V(M7n`J~aHp?*-)D`G_fA3nw*vy`Gj*owg-@LnfNGaywk&4?{ z^kZ^!NX-{FjFgA_<@2XcPq=vR_sME|R0rio)G>n$$h6XIX3Lixn>oJ%fosyNBX=;c zFxKhnAcc`b_j~b)cL&qHHPWyNx?WwdkHn=0}ba;U-ZJ=%me` zRa(slHy6H^e*3+j!aMZtr0<#23ynIqtdy3Pl#-GXT!Wj?B3ilB((9-D;#>ufm}DPF zQ3!ho2`xhxgjKZe!P`-K+j_6C+R4L!tS*0>d2QheHO1=c>RFU)jdHU60s>Zq=`&HG z3kc@2X3du6B#FQUuuRq6&Gi}O>(|g}i@1o22wW;&`liOlxseg5FcR)`v<#=EqSCCh zFkcYnzSJ}aCmt@fTwl3V=;@8V{sF{LQ@am>U{HPv_sF+;2e#ZkWK=6}Zf>qO!y~}O zWxJUluQ3@ZihI-o+gYwQ#-tQWDA)0tuWvhdB_$=@_8$deFj_L^{91*s8*;wH$H$j) z{@j+7oStsO_Hx1|FF`0NCdQt9%V11b5Tyk*HIqX^q$AP=S+pA!6e3xD`$tAlj#q0! zLP0=50d){6;E={^pO13W5}Eoe|3@vry~}od`~)36fgg7jWyCaU^h)+i0w|tR2$=00 z@YdwZBypOKmKOH!^cVKOnlwe3H&&g?EZnt^Jc_=!++{$$w7m=x#O)6b+gI;Y<-#DB zP>M+JwUR*29Nf;xO7FgTmKXW5Tvpd`ZKpIKXcwyr=7PEs9s_5wG-j~+}>%HNuT6>WBU7_2%$-=_IIEv{30)CaLO8qWD zcQ0o6#JS7r_g^S%3WYRSPW2mK9smB*B`WQVLB@Bt*mRcP_v%#=1p=IRa`H4=0EGl^ zFQK5N=IQ$P(~Y>midp$|&P_PZGAbr#=;pTIE-f^N7z)?qJwE>P*4FmKtqn0pQJ{7} zF#+lc-ptdxJe=f5`S;c-Eg_8rL`1PIR2}u!kY>lDnTDfD)tQ;5rltb9G$Fey8}G0c zFL<4NhS1wj0&jFIGyR$uI&J`K9}9ouQUd~pd20Imfy6<68LpO3=3XmRRmaIejuMzsj7wC*oLA!ogz zIVdC1u~|B7C#mczh&!EBj!442*N_aYs~;=8F5Qyi-nT`@S) z7ZtrD#4)H?6HS^UD9C1NfU=;m4j}1bxhOpvx2u~@quP_3nBKu<0+hUV9gX;4uZq#i~+P5hdaNs;KX`f3;B)#3(W>Ph31dn`0h*= zsL9D4b`1b!QqxEilagp@XGi6S1^uxo_`DH|sBmiCN?Alu6P@qznWd0dr+V6GefXzJ zI#m^~HdI_Po>_09NVy=6QElI$K89AF&+UBY&K2|pgdy^6dv$XtAvwPrtf!=O+KOsy z#iv9?_EB-Y8EY;47cr<9_}Mmm`U^C`_gt_3jzU9Yo}Bzp6fGe6P*>n{+9wo9LfJ@W z^()nqcxy`+@;u6ig@j~$wcgGHRBE%Ia269+st8bS^wwlSf zor?qXW#TEKu06chb@s@Wjq{{+EpAZRn_rp1fPKD)A{V$11P)1fzFDcoG7g;DVp>~iLXrH*yk~j49Qi7(V>v6rxe!OF! z@S9v!%TnvwizQTT)OQKYj3~eq9@^go5-JVzH|O!+=ljOIuKr>P?eFXrwmHMY+yCdU zm;W*%|1FF2zg+&mCVKw2yL=Cp)O0`cLRkAZFDQs2=ouJczqz4q{K=^7iOo9nZz}1F z%qDaNnE^+WIjb*gAyLY!vNAI?*EQX)V5tkMEC11S{=F=^$*(?Y+K0izv0xRC!U0EP zzCv_eBIjym>c7%a5omE|!=|+0y;36oxtj7mDki~+as7`cD7hEt-$ zfG^QEA9)r^6w`a>3qFiH!|Mv|)hqb1l6$VG>2AWi; zurR#ePuCeH6`TdFPUVjhxeh=&y*1p}+pb25!orSnZ3NRVY^D@+QXSrIfdgP38A{(; z4!AHixg6E?@Hmh|Vc=K{`=ej({`K{e3$IQmgGj4!Nsxq-pL`Q7loOV<^mdtj*$t3L zS-u#Z$z=dTAFj7^T5iM~ax<1A$&K<0(Ws|qT>tKpP3Sg9i_(YQeFtu0;N%s8rQBT8SR!}kJ>vzW4i9;H)$PhM?T zq}^VMb^j>6y`^7-F&F)5_?x6XrjD%D@mL(j;)zIYd#OlgDVS2<;;h|1SRxKiNPR{H z+SHnJ4TJKZyY}%D=Jl@E>E~>7I&%#LFQuef9?fi({f-*rFD`M=F}zvkkU-kgzf&XX zZS|Eci14!C`>bxD%N&Xpi6xFEi7_xUqsoX{b`_nYn!~{ee?h#}9kDQnM{vVsZ{4Ku zI|3K3{fmLf@{fD`BT~Guk)oJ@8e__HwQ_Rg*3>u`Z4S#4?@Z*2+pZ!*VV$uUzf{k& zPH#Cf_|}*1AHyvwUWl?nWGdec)UPoGrxgi8I8;>GFFhaUc^}M_D%yPUbb9&FHglrx z=G)ckc3bHh3mF2;p@#oloIOf7>}o7RI1!EQb9|edKufOU`X_NoNKOv6Y2l+sKl>Ur z)bd&ji2n+J$me(=K^-pt(#F8j?(_W{y!Q4s?GdjCM*dEnQRyqkJJtgHP^U5f_S*iE z@$WQpE4c+Ez8iD3XX>=Fwu478-2QzeBMTRar;e6m17&UAbM|$W6PTnR8{RvJ6U@sq zg}ZvVt#wNQI`ZU=>7B=EXALDYd?9@0@C6LAnYcupgOj(t(xg_7Z8q;2sj4mbiu**t zAj^nw8JR~ovLJuXdpXM}4(u;Fkx-+a3w5$s5-$LM(;urA9)0q)Klu9mcODH{tAC@W zDNUNX?U6RX&gpc3Z~$mLTNMXxu)l`JoHt<0E_q!2`~|%@VU?-3w=$p&($>HjXp`J8 zkEh}=nJoeLZ9J=?3sDosetm3lFb(b@Lb!jI+lwn3^Ml__Pfy{e9dVGM-K{hxAc;?7!9~vP zMv&1ZNoL|yaFn%Wj${2y_lne{G|@*EEb^H$yY;Z{683k%{wKSB)wmOBuISW^92}B? zKRY|AD1F(s5_bHI#uY4WTVlSa+FqLcVA@S5yIKRgIgsz!m=2GYt~vOe|1&#@4QD6y zgzqF`%88#|f3jQT$}xRWLGxp;adLB5n0A|xcnE05xkUsdcosL)3B;!=DC~E5tI5JJ zOxU?RtfY0zaR=A1+ZwTFtWVRj-kocgY*FKH06|(;PE$$WV$%{z$79C>KXYe2(!*k| z0nc>aWuX&S-v#hr^)}}E63q9MnfINjon7v>^FCql8u=JPTa9%mKUVd+96TIuJc$)kP;^yMk z=*k@(y|&poOhqa7=htxtxaF24uQPRjllcgyK=|$`#k+JoAuV~tJAdAT(wEZmD67m; z>8KsgPI0i;(~^h0`s55F^>p%novn1HEP^rr5 zRetzc6$)`OPjd6n0XjwD0*#?ZrOKF!+Fv3WeIxDVsEuE0lX*I>0lTLiG%(`wTEae$ z(zlXI^xw4N=ir)zIm|FbS$`=S@yoihY1#O>hOdFaua#CuU2PQCw4knCBYt~Wt9=`5 zDmoMz13CJ$|l%vZP&tFZ}bywwt zTq1~eCdp+6{Dz~X=W5usMdnP5#Uw;Xkpan-?6YCD zIUQ1j?5%apwh|@T(>{&_QR_Ap!k$~acUeyi-`%>r9Dsa6It|oXWz?wkZMW5uoP9cE zpiF8JhHUO0`q%2<6^s!iK<0#%cyD-!vq;J5wK(NG6QrMVa$@mD@ISpLu8UHkb~==3@mIBrd^d>yy-mW> z^}G5utt-xIRh7n7)0A{`GF9DVA4 zc#B57ad+Iiz|6R7_SD%+Gf-n`jAh}mx15?Aoe|hx+k=nS%aXQi>Rz+lxapdcZlq4m zo{@gwvRYeRHBfcfb-SzT&fOTCZK?>YdgE$pWl`l<*3xFrA>oc5<;}%=8qx+4l5K2T z%hZl;MlLYd%@j#Kf&tJiqhgLHi;hPIc#YNA``hBaX>9HsZEWP!yx-Clj(h3MS(eF} z9En*jVWh=r>vUPyFu6B5rX3-ioS4q&i)$edj>K8Gt+O@*y?vTB!)?7W-Yf2TdEnQN zj|wqoNk9}2XOadAc&N8X-VJd-fVM2er$z|1uW&kbCdMe3tu#kj4t*+rFv{|SMRzH= z;m|tjPTIpH3fE3i)2RO7>-OTrbd8^nimmEmd=8jNC?#6Y?7sf7nOPl+})}NY9)+9D>R4!zqJ331`v?ih~2jh zB5BFTYHM-1u6MSbAS^iKhe03#+0hp5pC8))SE1MA{~G%LxYIxa{!a8iU6Y-E3-~{N zm;Y_=<$rPc0RNfGUsm~ly2AgV%RdSF4_)r*@E;-hkB|WVD@gVqX84b00Q?_d29cy- zJC16py%xNPw}$#|PFYp$S|~J9?1S>*j>YID7n~0);+c$cbU_5bcE^LOJkDzbJhWjg zyJ9P@CQI|Yp*(Hb@nGjL@P+Bbd7Z;3WTP`Q_dtTKBoebCqcvGI04us?lpISqMJK1B zH<7RfY1DoB2wl!(W=88dpyS2;6Q##u zh`*R>R|a1~HTlggV2l34S7$|j@(z@Y`yppG`NqUa?a@{#XlUHyGdqIH^VgRydqwfs zdwZNHZAq)n>@D{IkeRNrP#A)F{-mi>Nk!o+9TQWP0~;|gBjuX_4e#um5{LF*UM$?v zxSfef1g>wmXccoSEV;NQ>yMrx0sfo}N}>%hP(OGIA?u z{y=Lp?Ww;{MFaag_II<@j-&EojVVXXf(XkqbO4iZOlP(u#yCyo(c&{AktNQ6INouhz7W%bE1BIRW zc;EKn*6~0V^KAD;_$B-2$G2H%h;~E5h}scl4-W>*>^2uk$NSdpp9AAZbQbE5%`;iH z`4wC^Za#ZB1?g5)gC=@bdNeWCJu60)jr(PSgFpAP7k-(+g7e+ZmH0(UPrPN#HQC&Z z`)~!b*fLVp#XM|DWv4%#Q>kl&U(xK61rV6w?DGbYF zk(i+L;LtYXNI%z{f}b8FX5DbC%E&W=oVTo7uZ;DVnAi#>RmQLY9ftSM6&#C2F{&IojetKUro>3$pJT387`l<=NSxeyWe_6xQOVPDGtL_afuZ z?sjB6f!f+~5$J7LDJzRooHwzi@eyS7V(aK>lMVz8?tOX4FA(ge*Ky@+;vBPdzD)V_ z9pw+-<&SO>Pw*6fEk{7-B4DpC=G;FD5)rr)e?(=mbKmy-#((3B4+Of6+`58mEo~MB= zx0U*X?eU2`@VAwP!clBxEtX1^V2mKowrVrg{^e0g$S(K${yFv3syz`E7k*^NOwl93 zdX_S4j>fX1EH%YDzTC^5H*3X%njV?Co>JYm+?$%#a&p#REGoomK3H+H2fjANemSg9 z=I}XTH6Re@uHJb2{;iW0v9=>rz#07*DXpPwhYl3@@Cu zPC6Si9Z;P*uyt8AFzA`IClPsih-qSePNZSFE6%F@_A@E zG_*%LLR7Ox$5dW5SZ?h~l`JabC5M+2NZ-*{8oai71fnalj?C<+JnkKqwY2Coe4CT) zDJSqm_O8>gQ%3iXjyOLd_W!5_h?YCY_0jVvo^2*X7e#}e3XUK37Y}rajuYezD60^R zbC#7iX4jY6^ddoEH^ zSc-*l#uFH*ryyc&>qlgGT~k5z0I({9`T&eF2PgC>sF`!2iQggN3Ra~MFKUO!4s5J^$QC(qBssSkk?enb=knPGoBF6scCM8^dDJe3+U1+WjZeu zRi-x`f&z2e5k`lE1sXUeWasiE6U*+%L!UZkk7$FZ7Y&<)GatmY!|K2YJU~w-A6d8_ z2z{rPpFmzd26bKg$4R+wDIyZG);WnDRN01xGBd$wP#61--%w9AufEPn z9w}bhvsP@g_WzVn&>$&xA}JHB0k-b~_IzbSD{!(fWe-Bt>#-S{%ZcWYEOPb8<4MS# zq>uPr7~rz|<@F{L;u(GwQ_$U7NLwaHlbF2NDjz(k{kdS#g^D4{>2wK1c*l8*{@U`e zFF5o{N3);!rN>R|e;M%s@z$H?`1jRDKlD||ObOaF2RHllSZ;72Wu?mgVp<4yAq}|k z2U#bxe%af4=#_cR{J|z^(NyeQ-gK2(XUkqlwew;5bZD^2F=!GZ!Mpq#!)%t%bZJY^ zPH^M_!mBP$mAONWe`|@}>qM}t0i+G?%_C{+dU4Z>UT-$`2Sv<8^e0zpQ1#m`U7ufF z4JsbM01=#`v6V^=aB+G4Or@)ah7l~+Y|JoY>(#Vixtr(00vVdmfN;Bf_WZus8OM7j z)Wa|aIeNf?a9a~Y83?x@#9JelxtO=uy*h!)?f}r5jlXa>cfI~eR?!1L`t1m_YYhN! z7e@E?la5z?9}2HJNR+VB**t%a!xmyvvD_e_ygOYJhD^GfhL_@?01HP1sz0DZBlBhL zUK=CM2NiL#=Rc|>+fA>IZ~t2dRG;5ZY|#G(*}tn)pWy%d(k${XZy-Ya`Cr4% z!@uE106^#Oe;7gKzcH!*opJc_FZBJNLH_@z$@)Aw%9Q=)U>*Aa5k+yuFPiW}=lX!- z0%@5&hxz~jps!Ek|I>bb2bUZU2${NLp!8f?Hi_)uJo#h5o&Mj=@2DckU?&!6J-96C zbsb0Dp99sLsZ~B;slNFoPPA)8_ zqVjM2IIBHBupN3(Wq#pmE==SXcCftQK|=%Uv)90M+PXOxfOMgz-th{EDy`$;KF<#b z2o4nVL})Sku(svN@4OPKDXMZ152$mL*qRq>$nteHt}cmC?1jmG-)l zVH(u*BL8p{V1Ynp>ZeQ6dN<+V3Nwk~YJ?A1$+YR%5l7q$nI8E4)@&hZweZeD;6iU3p@_2N2%p746fqosVE#UTki zJhk2ChV9trjRqdU^KmUV>rcwdgJwd@dZrzv%*H4U1L|y=dzDKB6YIZT#Cvi%P2**dY>UG`>>LFGrWZj~C)d@xrErezvh#?`23pL5u$5~?+| z>f303t3}Hs<#HK6c5|k4X$4jGv?&wZ;*YLn$*%-wW<7+Vs-n2{)tn`*0|z5jd2*|4 z$gK5}&Uj(b@;KBz0=h!keY`(K%+$|NT4;|({k+ZLtCpS}+V>jiup_4d?`Da(1D$J= za^??A`d|0I4f#LE!&9W31!C&fI*;{4kBT?O5zR?g$+Cptd+ zb_vE-pkvF)8kIs<_;^=P$^?X$M{p$WeWvp^-uk4or^4WcG62zz;^k36i?0R+k$Ux} zTJHH*3~LMn%gRg5^6vJNS!E@3{0+B_1J1sMd0JboH4d_iwRljOY?Zt*&BRxH2NUk= zt)!SUUN>D4hynS0Yd9DP-#Vf0#V=gG{&2tJoPZ5UI5l>@o`*FrE)a4h2LE}ia z2EDy6L!CpQRKXt!x5xXg%CpDXZ@+%Znwej$GF4l_WmWM-3DHpq>f?3pm9rH^v)x$x zo?IHd?sT}#@u{Z)j$V0%x@MjO)`@}`kk27hr@>3FsYItS7AiM}weMzI8u784G21=j zchW2Ly_RPjp&>mb~y$it$OA@4yxwn|6-t{`;F6C5_Hm8fLOXI zOmFSsEaV~6LRArslS~60NTr*<9E85&3?p}_H@75UzkZAs92h8}kW!DZv@gSs(xc7P z2(vD@2)!iAXcv71d``7CI3~jyyyL225E(#afGruw|K5=+Qxv&@TSK+>0@tjPYmT$r z0`M)KcVcqZO8WJZ{ckdR_YKfuo4M1%jboe>9-gSnt%wTOWr~*;xC>{76Qrjil}Z)d zH0_IcOH&^bbn-rhKt*LQPI6%Z8x0RibEoe)9~5Fj2wdJ&M`l->eT1B8GA0j2lQ zL$4vBCzOzh|6I)6&c)2dJpaB(_Qn35Z-2YIYrpH+>s{GFHG)9Mdi1r57^|Nm$nf~* zbkb4IzH%nBKLs&CjkQ}(uW5&Bmv&0NXEoJbm^9uxkG`wLrtMH9whFJ_V4oM&WMd)| z8!!3!m&?m)GJ}F8u<)xyh_kr4XAi_Im|21$Pb71E;pqox{LDk|X>6N*PFd;(lNn-LjQ6xGoAwhdC z@``ooG-Jrmiu}+0r^PDiGyRROP+iaq3&l*E zd=J$5xh>IW8jmFZE_{USh>L;wdEVZI`Owo{KY{i2m3l-8J0{nRxT7^S<2Jb*4DQ1F zXFj)~zBK{_qMaqo*A!z2#tIQ(UA_#`ZX&+X91=pX1)SSu6xANwCmf$kPvu0hly1C6 zt;)c8Yi+})s|K_q=63s+$O%7Pz^~cN+@0BCjnAU_Gz~iOk}oZ4;T^?Mj@5HnR_}n9 zw0tP+u0yG)q}#Y=oy86|GxB|uepI9TY%P3LBopb=*~pa_R%qhR@&R_wyEFHFg$B!r zWtD)DT-bfzlWDk@hF+0I*Tm~qsLd0~D$9g@TUcAd@03MPzD>+>@>S&0gNMp#-uI*X zjcM{XbwTQQkFz=9epjz;NK!$K!$05Hz#Jaei{ZEBoz2OfX+7qwkl(ppC6SSJ?|!b& zPlQi#-na6`e@Fz!BG&oXmC#ti$f(jPhhN(n8#glmUA>E|}rf<#fy3k-NR z_N9vGZFc#4HC8(X`gGoG5>wg6Wtukfr>P~+bVGuA=j%%7bd?4(?5I547saWlHiS`P zRT{I#hmRn~Ef2Aq8Xl;3mGdW^w3s*3v6n#Y*llj$EhYo%7E6_xHje>$DM@et^x#fA zM4TJj*4UirC>I85iOUD6hjdm2($sTH17BP4qDpp#_b2*HThA{IOI#TM%EVeV19z~X zTuGmGt=&?V`b5*KT*vCqt4jibL=nolW$%gIvlbIr&<5%5z$zQZr2D(qmW3txG$rxd z<_|!F{j$jsrp|_V9`2CAL2>+)#M{hE{>Q;EY4R~Ou*Xtbc4?1D{|zb0Ef_O76c7+l z;CjPtqEY*Kwtw9fs=c(;%8P)p?bU_(h~wu+Dc$+Y5+L%0#+WKut3GtgW)2pQgh5Jb zR9Ap<*EnSw9j0ZOm|$+W+G{TaB68A{?v?wXv8Q9Jg}NKJZw zVSdLm2!!zs$^2H= z8tgDd7AT#hQn^RdQd+1|d>abvciy+eMk@|NO+U^YDdA%i{#@84>MUNorGlE`K>y)D zi(m?x{3-uOY{{Xkv~TEy<3A7n$cz8O-YDh2RE+As%<{i%o9e$Fi2p(X#pm^3C)0l& zZ~xyx!Iw#x(f@VJ|4wC=n(Bj5F|nu1C;H}fFq?#>g(bLA`%iSw1uBt>ipx=!HULpx z;TB(~`uVoZN&D9JmPYJJ{V4#=hHf4lw^zLyVfpYN-V@0DQP2=#U8ehq_Q(?)=gPi`w%j7w|v(1PbFuT}|hO@Jq0GuH2pi~+qobI{4#_3PG zrr+9_zikPaI76%T{wh~S5!OYkC4FBMF5B)OWF72rC-@k7sbvNHq|pZ%XBQcxpben_ zjlIQ7J|6zb2232Oz5Z&6h{Et|18Af6gx6p`x+(xG$JF;-gcGm$(@s`h zCIOK1`*c{|Z}eZF zYs2eQzo?tbh%L$N_E+Uy$>w6F+S~9HhitFSrpaaok(6@ei6gXCTbsux4c@(E*NFO( z?!<Pj9A0o9`Bx#7YvUG=f8lnZP~sB2-;Gi7{OZK zH~8EI<@SZ7ktys=(U2v+hxFa*e(V#*^(#@de%Z^(Y@sML-1mHvx}c){EChOUCVTXe zVz1r##WccoTg$cfK+m&98~Ih_!2`9*pGRp^Ahf8wB*K^C_eVAVAoT>AADTT(52B`K zHk=WX#}ZdJw%aj*Yt@gBBO~eQq{X7IM-)RpuYefz03^Ca{byIHE>$x7TtM~HoPE8M z0~zFJ)eQRdK;DPo;5Hpr%w`!pzGc02^Z8JB=pE&S5a52L>Z6CK%kwcYW;N*XwxTv~ z0tc%%gbg9tA9R1$D6j0I*=k!A>sM4tWZ&cX!X)n~(e0L#_C+%U= zl7npWLUxu}^6m}4HnN|%_rrewAnv-?I{WxF+S6yJW_0|=4ihPvGl3VVJeAKJSl3^_ zMe9FlGqeyd+<~f+%{v>a5m0-XB03^S+o@pe-F_U$VM0vB337ip{25AqKQT?{6`est z_sqwaatfk>UG|t6ScZkkWD9BdE~EXbBP~3haI>j%fFgSTKXU|Z%el-A+gdTJXm**s zdArN1k%zcEUAos^Ja*Sk$Od6o8!13W0Tu$p5VmU&o!j*3vO=W;Y#R|$y_<^7uqSsJ zT1kFqc>x#I;m5pZT@5)(@Pk9SnZNxU27?@yHV}G;_t`ZPl<`C#uMeX9@u5!+! zWK`0k%W-eos_T3D>RG6Pgq zny@fE)DObtiXhrZYTswIxJg$-C493?=MGo9tsXHk36`Gso3Ya!-D0YdJZl|V$!IsZ zZg=qOR6hW!fUG5;qJW`6Pw9#zOFBXDB{xPN3&dB@_WH^E8V zsAy&yn{Dt$OLHtl9iqx#qV~YioUq3MO|EOPCw1w{fRC z*4G-4kcsVw=jIXi2WfOQV;>SiJdS-~6B5-(Kf=F~3G9A`9hlH;l@(tk|q9PxjEihJXsS%(??NuI8#Dq4V zQ__vwJE@!{?vbs#7f`zB*gbLo%jgXJdUIyhoF^?__4HKv8TPG-y#3x|Of6`^(n8*G zH6^NcZAA)nD&B6O*(G3mG<;rCd=z<5pSDWc+sfZqXL~EhB)8YQMfU$%@N?7lGcB&K zNx!RxT;`G&G~-ijCev4!wUq6Ag$1mWnDx7v)EF&%88we?aR~=d4@6>pEOmtY-^$2C^B;HP*z7#S*+7;+dLtbL}!%b96)aTJo)8J&O z5ckcTz7w!2d0@wGfa2*^A|9^UIkshO%ZxSoyseq3tQdL<=G;Pv6Zg2qx(eL{pyg$S;0D}Fk17NS5A76 z|GgW!82ni@)Ayvanl6+03Vn!a+ikDQHJg~b466$|IjmFv?H9$-61O#~B(;md+fT%p zSX!>I*4$9o49^ScKA5hNXg~M526gAJ*1K^7@e7E~`biPfA!4LgM) z4*_imY$iFb$yUpyeF@IsY`&l+rjPL36xgLz2|3JPxyLB?VC{@=5>A%0yKtz!^oEfq z;76}yqa#bd<>Uq1zTJtd>#?E?-$N-(?eOiwJ<^A7`gBkr)NY}rtbk`n;V6o)1bhMAj5{xx^ZT|FLxwbLbP*Or zfrr)FG+@BpVgdXo7k!LuyIKn-J*}Exv)5%oPPZ_2Q1#){Sm`yhqEQ(Q`32#%4)$7=7Q6e{`lb#Y*%5dYvs z&Y@o*BR8wJ^GVsioit%iQnPJ!&2|#t3I)op{WiwNu0B(7FrjR{t#mLwLJ&8%lnfW( zg=czgEe_5?)1{ZDYxEtj*~l)nM_@i?rND$!4{=S~4W8kr`t7QV7h6WTdVRN(*O^^# zcB)H3x0wu7&W^Im-CNF!<+W{2meO3&oi@CvYVs5T2SlDv+@bDPn_uf7V5Ig9CL~r_V7k!coP+#U?4pZx_j2ce9MuN}pvBVajEu!aM4er7xIMC+}rqBEa%{=G7Y|vUBZ|QJy>V^x%jNLHlaL<`}IkmgKI6gTv z5ck&)-l*!^dmBco<^*0Jp#BS+hLT@`;Y7)?K-r+f$zJ1AdS7Ef^;Tq1l+&m~Xb|f_ zYD2Z?J)vQpheE#BB}D55@6p_$Tr66OLlBIcyM}>=?RpkzB=E^)c5nD7mRqW|UF@A^ zFNpC}rKLMfo!sA2|9+=UA|vaj9Mk^Rtdr~TASLh2yy06L<4pC9RCe3V6TtlYGg+Z2%SKS9jsOD1Gi|hVkW;a(RkiYU7ylq&5L5hT>K2x z5E4{=RM{`0T*k|aJ(c0fBLf{BYz=bI-a z>Sb_B4?rV`3_rm_QhHTxRZ=Xw+Q508)FWTkb=ZP|iKShIiU&1f{RvAnebarbJ+#lQfvka=#u#bB_y zm|QPh(NbP~kfx{};`PA2gDS66sys!?=Hy_=_z{zn+0S@G4gd5aEznQ~VadWp+0~N2 zF(*UNJQA8NN&)e)mO7_}kJqjl>oHjz_f7<)F1%0;%7ivcfZB4UkIJCp*bSN0(!>tP`i(lV&^HULn(a^9&jhCwvip&Z?@xDqYi4Z;e2p(z3b6pj`{~ z6jHM(3GugDZd>5Q&+zcxiy`$nuLqU$pD}M#1@mL@nHw7e)5aF{Qjh@0x)L=7@MU_N zvYLxMz*w`3Rqjj$Pagw*#6~3#vW#6yv&wMJk|%$|dofOqvt#EEr)Mit(^@n&Esb?j zSFauGZ(~LH^Pk;|b+(a)nt8?;O?#Sn;?nqSc(&ZK|F0d#g>e)cAq7ofwzZ+O=fLte_IPFb@+Z(v~n$HUcBF^KP3xFICKAygI6 z16GDjmd^x&>Js?hU(fI{JI@~4K-N_i7Pk12&y1xc>KS<_8c#vZS!>fU7O8jc^3wzQ zxF(E=QJ&5jSnA@`rn&?q1(T8zetU*WN@(O(>{s&^TUviai_3mTnwxu0b&=R~i;8&2 zLA&6M?p8*St1B)FmdVVl75mL?2dgz67(ErghQYDH2kym>N+Ro?*=% zt#VyTFlKLHBrK+qq>sOOqn3TQUopj|ocmmU?rbrfI{z%J=T*zn z$LidhP22zanmuB&7`#Ynkcqe#9@1X(i&Z&4K^*FCBSW}8d^cK$Qx3Jtxx%|#&-2T@ z@|ez*#lfV@&TJBkfR<)gYFoghbqSDgk(g{w3>$55Ndfy@my4Xb8GX{Q z_t!HNpd%TqGP$$KINGoVgIDEFT;$!^i**H0j4ucnhEmhz2l#8fNIcuvm6ThBEv&cL zzIhomlZvG=n*GMDEVqhmA(RrF;k?c2xy4cWa*#xXh@|KU^V}K=Qp^>SKhl}9frs^e z+sU@l9z=j=xbo|dLQFILh#HO4Ir-1W#;^!NRUJjTUg`Zv+BM_i54IY1si1H|K>66>McMB_=`(&!SReV=;EAF#bVbUA?M^dlNmg{Zw%-;4; zWaN!eVn|(gRu#}-`>k>?)Oa*dccP$akA`E^7CxqV^GvCM&_8ZQgtg^Z*+1V_m;+(N zDj20E?}w~J>%S=xMh`M3Wc{$bCN>6bc33PeL~%AcKcr4l!VdcXQ?h2-$AyUYZf8|Q zLyzXqAFf!F%k6NJNQ$m5+0kGUmr21nB}OS*a}7Of*o@*o3syy&F$4+fIJweoJ8tEJkC+psIR5?c0yEM3|Gub2+x$2?)hoSGDm zx-4pNe0zwy-#x0!$M>ifhgK}fgZ)q`kaJ~qb-hx^d^q=vkz#H*wuAbcEleX{i6%9u zrnnWeSIPk68j%x(h+69Emzzri_QoK3L9E}5-%OA~?8=0zF6hxVrz?#ZyliP^ag>gC z?#%ozw_~kOY|VO!p$_xx`S+Um9mz=g82#YA-lI?Ycz0WB50kh0+v{=Rn>eukb-Ag# zu3gxyQF5;Bth>$JM@}e!UdKASX4>nh=c}Aa!@H6mX7Z1|H2Pj5F4bbJuH347HBr5l zCz!cY)ok!UKQ9{tSZ`un;C7aYgeee^tq2tIgGI1N-%)j_#}(e=^jm|He>Kfb^SKYfXaR|1h0Bf-MH)RWYgr~ ziHP4PofpkrJSA7Oo%(FgDwa%hnZGo6vqm6XN0)Ew;qay{qPHa#{m-xczQLOk$hfsg zI?QK_2wCzu?>08jw7j4G*(6sH+V^Xgrbh(<3*7q}xvR6Wn%ng`p0cpvtco#px#W#p zc>#XNiL<=d+^Kglk3Vs;+KCsR7=5;rIlbF!V*I68U{I!`#dAcxy$u(t?apD0H_WDo zgycdF`?JUBU&J{aT4y(VJoDIa2M%(M9;PImk@of=jMX)+%Z`wd{+^ku^lZjGD$@h2 zdKt@>hrJc@5=v!;OP4X&!6^0z@;U}FLf|=2h3M#oE$M|~L&_co>P@xDwSlIB@(h?* zS-mzi3K`#TkDT(3CW!sK;Th2$ygnTE9NmU=U|@0z8R3DvL$p2IWn{JI5uVv$Sx{6| zIC?z7gNUqfMDtYWds#03w!-eJd@m_gYxPZ7v3$KzuJG1icL^g(^g&Zs(O86*hIeX> zw21}VdR8QoE+7oQy0%TBRZH}==ec-{z0Z8s#;f!(bN2$_$m&zavo+vCIX+C7)cVxK;qSncSq~UxxDvvA--Kj z)$s_sK}1%i1jcAgQ9=dGH<1=gP z**I-Nuw$muSB2u^2+W=cr1QGnL_MbRUvs~f)Qvlt6}o8c?5;1yZtQ zzxCgd+nBH4Yv6P|CRvyJ(dN3ETqxy(t2A^`URVinSMlGyjJ#?JOFL4Z@tj#-E)r$~yEZ^%+n%KY5$%zWdA*2uu8;uU zo}@f4i@nek6Jv8DspTyfFXOj5qLph5$ta`xv+b)DLdWNh{c~2uBA2S+(8Kvqml(=C z1YZa+#&fKLS78++^G-pBKf3k1^EN6XVS9Z6v~KS=6^`@oS8*TX(#SIk1e_ek+SfOh z;$2y*4VL2{T+XjF*X^>KYR50gZe(&QbNQ-$;oHnVm(09f9UbX}{)ul>S!*dw?Po<* zqZbjhr@|*4Qf>W~m&Y^5$NA6vkmS+Q72azkrfjXEbIxD{A^J#Oczut!Q}r^+K;qv^ ziTPl!FD7aJ;RHQ;x+4OBeFxxrc_-TDYnsz*k8_W_f1py(m?e9^@$B>3zW$t~@E*uH z?X_aRsOyH519;ILyi_@_f8VO|U`!<49&oGx-AN$mogF%6EZ^a9{yXwU+>HZs847g3yNqFDY{KUwg({)E!0smJn+~bt69k|&SM8S5Y~fht5!W2t;fw4ncuJid=+m|mJ_t+@ zRmQ1J8Z9odVOQ?V3*8g{p*%c<4ZzO)8eLcCorBvBHpt(v_c-274BG#sZXY82P*)@+V@a@F#nBy>pGPe6!Jtc+N3O(s#9K zLkfU?G^N}MT&5?)WpD(Kzsp{OoB&=>D+|(EeB{qR^VyS$l&w=iEV*Ctu4B#FUhQi1 zn+)%tx*S?aoe}JnQj&C>T3wPqI#S9J#Qxc=b&5p0KbzHqkIJLFS+vdn$op_tfENOO z7v^M#YXmaRxBF;~-B_vGu5{b|_vS}a31L44Aj0blr28*erp=5`e4!orY!)|$YcIlZ z^2Y6#!e$WO1oRFRc?Xim=){1>*-6g@_N4CA=CvNwN$D_>D~HqNNo_-}AkLGaG@SoS zSl?_K!d?$Kc_g2>bAluecSPWGnieauYS|i#3?|x%;=)EmYhyU9Ouq-IL-m9X zRSxgj5=pr_7|SmPLAYOQyCd|0Pb16U&8jC`nVbbi$!Wb1VKR-w*lak3;NP=imI5G7 zEYY`~W|<{CV8bZd|DfN)ro#3h@j~?I6$Z>GB~`JNK>>A%j>^WXztzvja<%Vlx+$3C z9uxF|>Ve)%69Jl@aAMlL_T-x|N$5{c?Mn%b?i&D^st^y4?(-~DiFNo~bHIKa!JT#c zI$!o80ZkGM(`Je;F54iqwuf&r!?jwuM9?f&Cs8`u)SZ4>H2We?BlSEH9-ywW$iJu` zjSHN$hW4m8(w`s3H{>O*D>sYqk{YB14(GqS!Qi?R}7lB6=HwC z+q3^0J~X%~Y*<#eV@xBmO)X$6JJ}SH>yw|Bcfl7j+MTgca^OsPk5N+g1uFHX6Hets z*xqXL(vJK+=WIij^HD{LB6>ybRA)R198@xGPqO?5k`x>K)?JBV#tN@(-d&xJLYrV? z+b4=@WJS`@!RouDIFRInN%XwL^r2ayc%5DKUsV~+A2htPb6FmCE&e=*H8jUnL1*u* zyX3bgr?#Hd5gP{>6#M{fkTv7`YI&If0;1Ttb%~w#%I+D`S!X3;JG2Mazd2``!ykdU zN4mJUn?(wM9ak$_xQv@z>fjeYnkBsh16w?w9-(?DbW1-7jLT-JINjc!sVqDK9p^l} zS|P5IaqDE@-i{9Mx-sV@d3r3biKk5qR*rq;u!qe^+|hj%*;rmEyM0KqvBDFBzejfj z#_R<+(dY#9_8yXzh%S~EC2ovRw;Qwm>%5Rn)BDK%1pokbHdEV68S0k7*MUEJ&c6GF z+;YGT<^?s1LrF7A;kP=pC3wAh2R2VZ{8p+54ThSxg)9B}i+pX~V8 z2Wpv&9r<3xukNK%^_f+pm(ea__R)J8J z{-X!Cf}=P8y=kr7@CAN;ylb<1_lUCv&e63HpuT%5<+Q5C)-6y>Zb>{J=_oKz1+gEf z`;bjef>|ZL+~st+3&0}EVdl&i{$FZe z?Dq$Cf0+);*zkLmv1~8C`p{C+)LvYgZL~bR*uAj|=ljJYJ zj=@C%cR786FSL97DOpCyZhF|ZPCQpxz{kEH>NGhm%`E`&dG>}btXjbG?n5T^h?z*m zLM@}E?5@<>F!HGtK zr*(HiOAMC2Q1z=Ww8ml+|Hjx4-UzC`qyz%*`Fs_i#N?kb^p1B!jlV*_$7OsOnVd{R zt#{%3g+-w!@T_8DYBK5B02q8Ad;9g>fO7HutgdlZW19t~(AxbRs9&}Kyzg6g>#v%P zo3cogqMpZQkiQ1_x5N%+hTKvLhQM_d1hE|zFU*-1pJyx8rAR}@?-e0JX;;;>8|iQzR7D7sU)XwuR7T| zG9Q_o@4B^He*6LUOXXI&meEs8peIJD5Cz0j0?;vVY_dX zaUdR1Q4p8S^~^o@mV3!;gQ)3g=?kjNrK~84Ana}c*gd-f-#5)g>6zYh%8)#^;rs5j z=YYGgd3vTRN0A#5l1dnAC)3UNhhe%V+NkH_Hfgl>qrz@7ee&IXBC@tfIH-97C;R*( zq^*D5_8D#Uj4P|$I$C@J34a+*R*>?)ZUk5MvZwGVpEBUK;?mU&rgZIS$U6=BALoYVJOQJ^JXgmkK9%*G7%c(xQ@C9w@$ydFw z2`@UBQ|YPV-rfaupdT%$=5Zkf5&8R3M=m?Zck@ep0#*4c^-4w>7Rb_eyAQlb*D;Cf z@A)d)EUbK#B>cd(RuBMl+qgGs)4*uAQapW9Nz2U5{o-WY!U4D|lKyZPHW8PYEIIGa z7dA|7GGwtyiANQ4IXHQqnKVU&@yMxknRkH75EWV}pC92@;CVxcWNh%_mGRJh5&h4>WW z=kmK`tR(;j<1*TLvhs>Gt=iO;zMQ>B>cPd$w9#Yj_9&C>uGD{RbSc+26cLD5fY*Og z^B!G!%W#W=7JuhZ%;`#+^sAnr_RZZfXm+!0WCUk>pENF(WN8C1Ge2sp4e!2fY@&CB zlTOYUQog|pyS4DH?o6tH#prI9d)it_W6xgwl+)HfKZ`2vL&afffV&`!Zo>0llDnHp zw*w_l#<`=SqRLG~We-+kb!b@`#&S?Js+ulQp*JiC)oj%O=OV9rm4d&7T8%-4OVx#(qC^R0Of343c;6;@ot!Uc-t{#y*gvlJ zwg^?VjOB&t^3bA|?#O7O%U#AB%jFJYJHo84`C1uLsXR=W+-ZoDkjR`YUasx868SU{ zUM!f-*Yn`mPAp`H)E@9~I)@3pp|1D=?2S!K(35 z$SK0KIDi$!LnL>i-qZ|l_Q)+(j^nDnB`k%ELp zO`UbLj%P`P-8$V$H{#ZAUZ+-hG0^x@7j7VmcKe`=?gw}GD(*_j&_PW9Df|u6P6vba zRYA|Rl`Yc8{+`}Fd2V1~WA!S?sz|nMjO8gM^HUVyLMT%5@~4%Sic>uDf1I9OZ|_2 zWTvFazD_P=4wqGJ(n#M8oUekTm{Y%3Rz)Zm`JnCms``V^4hJl1W%LIJkqX1zo?ns) zqb~p692Hk8j<&_(!G!9pUpH78e*zt|Pd2Xo_ zEM@t^YWF$hk_%y2$LmylVfC)Y4)k6Ud|*~N-mE4r#ywuox}%QH^PS^q`2=7?aKNE> z4~?pA!vQB+puG(=h|&tdMg^&IwkOB&fG>&V0|IA6=wsh5PwI>(RWKtZ}5o?n?yyO z@8L~mpL6$M1E7Rhjh8#`+Mry6&%K6IpjdyM*C)&04{M;Wf5VKMeZRnAIhzkfPc-Yx z?ZLGKYt@!VT1)F|s_D&SV-pLj;2q7;W_hW?3SiLvEO1+Yt(6S-crfqn*>uwa=4pi{ z^15p{`~0K7{;5ImQMFH00v$xcU8*1Jvk8RREwQ*uo-h80|Bh5H=22-Ji{X}_<x z4K|70^K@ZcI4Z~H9b|?+LpF7wdb@v3O^0mSe2fUVtMpkfFUJe#)PTM}c7F(5>zn%A zs?usB;d~{++A#dq)2Zl=LT6-8bYd=b9MQ0BCpuBBBdO44*7Pg-%Z6r|n-inwXTva$ z{-+VA0hlzwGQ~{8$B?kg`5~0ny?SY|g|wP|`05SSIhV{K4oh!0@^&XMvi$sODi;hdrGv zYaai@_5#U8{pf6ZqOX?Og1(I7+co|h+RJXDk7Sr%o~jH6-}o3|LPs&X1Oo` z0LZ7;zg?p)KBXP>^z@N=D9taiCWqQEwDY_Drb6kX@Ql6N<6jmFgH_Ko4Qwv(I|j2c zt2uyXZ*j-CytYy6uW#gxjh*r){Xt(AI55p3?|$I+_Cr({3ec|gs61SPN`8yF!b*Dk zEd|@Mh=Q2MrX{6qX1CfU%D&e36@Os4D%7^MCi}U%8d%z5_IXbiEkVs2zHFg?%zFp7 zzAAEiSb~09a0{`rA|--D<$S4GTLkySUav{L?%Vsy?4rcfs8)$x@N1Vz2%cp7=JRW# z$1a8J4WPt!Kj_@{l6rHT{9Y7AfrEeB@2;5nN~AMPKdmeppQ~DWMv= zyYa4X!^7p-kCiNr8^p?T+?EvTI;CyXAA&=9*R3x_8pGj_F^_N7eEDW>{-$U`tHkI% zR5%HKC6{*?b0)ebVX1z1XokXk^AeW9Xyp{1u;_4M7x F{{cG|*GT{X From 1bf2e0e6f90a84ae5c9b9d65677bd3214287917c Mon Sep 17 00:00:00 2001 From: neon_arch Date: Fri, 26 May 2023 13:29:17 +0300 Subject: [PATCH 26/52] docs: add instructions on how to install cargo --- docs/installation.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/installation.md b/docs/installation.md index 050be70..1e23aec 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -25,6 +25,8 @@ The package is currently not available on other Linux distros. With contribution # Install From Source +Before you can start building `websurfx`, you will need to have `Cargo` installed on your system. You can find the installation instructions [here](https://doc.rust-lang.org/cargo/getting-started/installation.html). + ## Stable To get started with Websurfx, clone the repository, edit the config file which is located in the `websurfx` directory and install redis server by following the instructions located [here](https://redis.io/docs/getting-started/) and then build and run the websurfx server by running the following commands: From 995b9ae42f838c8ad5e59c000de998f358834f2e Mon Sep 17 00:00:00 2001 From: neon_arch Date: Fri, 26 May 2023 13:34:14 +0300 Subject: [PATCH 27/52] chore: add installation intructions on how to install cargo --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a7483a6..055d5c2 100644 --- a/README.md +++ b/README.md @@ -100,12 +100,14 @@ > For full setup instructions, see: [**Installation**](./docs/installation.md) -To get started with Websurfx, clone the repository, edit the config file, which is located in the `websurfx`{.verbatim} directory, and install the Redis server by following the instructions located [here](https://redis.io/docs/getting-started/) and then run the websurfx server and redis server using the following commands: +Before you can start building `websurfx`, you will need to have `Cargo` installed on your system. You can find the installation instructions [here](https://doc.rust-lang.org/cargo/getting-started/installation.html). + +To get started with Websurfx, clone the repository, edit the config file, which is located in the `websurfx/` directory, and install the Redis server by following the instructions located [here](https://redis.io/docs/getting-started/) and then run the websurfx server and redis server using the following commands: ``` shell git clone https://github.com/neon-mmd/websurfx.git cd websurfx -cargo build +cargo build -r redis-server --port 8082 & ./target/debug/websurfx ``` From 5003c8e61f9fbf1ab2c7551d7794731a6d3e2bd7 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Fri, 26 May 2023 19:27:15 +0300 Subject: [PATCH 28/52] chore: reorder config file options under appropriate headings and make headings standout --- websurfx/config.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/websurfx/config.lua b/websurfx/config.lua index c30f376..595627e 100644 --- a/websurfx/config.lua +++ b/websurfx/config.lua @@ -1,8 +1,11 @@ --- Server +-- ### Server ### port = "8080" -- port on which server should be launched binding_ip_addr = "127.0.0.1" --ip address on the which server should be launched. +production_use = false -- whether to use production mode or not (in other words this option should be used if it is to be used to host it on the server to provide a service to a large number of users) +-- if production_use is set to true +-- There will be a random delay before sending the request to the search engines, this is to prevent DDoSing the upstream search engines from a large number of simultaneous requests. --- Website +-- ### Website ### -- The different colorschemes provided are: -- {{ -- catppuccin-mocha @@ -17,9 +20,5 @@ binding_ip_addr = "127.0.0.1" --ip address on the which server should be launche colorscheme = "catppuccin-mocha" -- the colorscheme name which should be used for the website theme theme = "simple" -- the theme name which should be used for the website --- Caching +-- ### Caching ### redis_connection_url = "redis://127.0.0.1:8082" -- redis connection url address on which the client should connect on. - -production_use = false -- whether to use production mode or not (in other words this option should be used if it is to be used to host it on the server to provide a service to a large number of users) --- if production_use is set to true - -- There will be a random delay before sending the request to the search engines, this is to prevent DDoSing the upstream search engines from a large number of simultaneous requests. \ No newline at end of file From 175e0c25b3aa57e111c064cfc9dc7cc040778724 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sat, 27 May 2023 07:06:03 +0000 Subject: [PATCH 29/52] docs: fix the installation instructions under install from source Co-authored-by: zhou fan <1247714429@qq.com> --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 1e23aec..44d5c74 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -36,7 +36,7 @@ git clone https://github.com/neon-mmd/websurfx.git cd websurfx cargo build -r redis-server --port 8082 & -./target/debug/websurfx +./target/release/websurfx ``` Once you have started the server, open your preferred web browser and navigate to http://127.0.0.1:8080/ to start using Websurfx. From be453e665346dc03210165687f9112b792b568fc Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sat, 27 May 2023 07:06:45 +0000 Subject: [PATCH 30/52] docs: fix the installation instructions under install from source for rolling subsection Co-authored-by: zhou fan <1247714429@qq.com> --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 44d5c74..4719ddc 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -53,7 +53,7 @@ cd websurfx git checkout rolling cargo build -r redis-server --port 8082 & -./target/debug/websurfx +./target/release/websurfx ``` Once you have started the server, open your preferred web browser and navigate to http://127.0.0.1:8080/ to start using Websurfx. From 5b706701d03d99170ea7be892671f5a6902d05b2 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sat, 27 May 2023 10:11:42 +0300 Subject: [PATCH 31/52] chore: fix the installation instructions under installation section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 055d5c2..95d4d21 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ git clone https://github.com/neon-mmd/websurfx.git cd websurfx cargo build -r redis-server --port 8082 & -./target/debug/websurfx +./target/release/websurfx ``` Once you have started the server, open your preferred web browser and navigate to to start using Websurfx. From f7c1df268fd74196da561ed9613a344b475adda7 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sat, 27 May 2023 17:01:47 +0300 Subject: [PATCH 32/52] chore: fix the docs link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be44535..324dfbf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Documentation/Wiki -Found a typo, or something that isn't as clear as it could be? Maybe I've missed something off altogether, or you hit a roadblock that took you a while to figure out. Edit the [wiki](https://github.com/neon-mmd/websurfx/wiki) to add to or improve the documentation. This will help future users get Websurfx up and running more easily. +Found a typo, or something that isn't as clear as it could be? Maybe I've missed something off altogether, or you hit a roadblock that took you a while to figure out. Edit the [docs](./docs/) to add to or improve the documentation. This will help future users get Websurfx up and running more easily. ## Readme From 87ac0b7cfe90b941a9b1758766c8498358459177 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sat, 27 May 2023 17:06:45 +0300 Subject: [PATCH 33/52] docs: fix the installation instructions --- docs/installation.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 4719ddc..d8f301b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -34,6 +34,7 @@ To get started with Websurfx, clone the repository, edit the config file which i ```shell git clone https://github.com/neon-mmd/websurfx.git cd websurfx +git checkout stable cargo build -r redis-server --port 8082 & ./target/release/websurfx @@ -50,7 +51,6 @@ If you want to use the rolling/edge branch, run the following commands instead: ```shell git clone https://github.com/neon-mmd/websurfx.git cd websurfx -git checkout rolling cargo build -r redis-server --port 8082 & ./target/release/websurfx @@ -64,7 +64,7 @@ If you want to change the port or the ip or any other configuration setting chec Before you start, you will need [Docker](https://docs.docker.com/get-docker/) installed on your system first. -## Stable +## Unstable/Edge/Rolling First clone the the repository by running the following command: @@ -111,14 +111,14 @@ docker compose up -d --build This will take around 5-10 mins for first deployment, afterwards the docker build stages will be cached so it will be faster to be build from next time onwards. After the above step finishes launch your preferred browser and then navigate to `http://:`. -## Unstable/Edge/Rolling +## Stable -For the unstable/rolling/edge version, follow the same steps as above (as mentioned for the stable version) with an addition of one command which has to be performed after cloning and changing directory into the repository which makes the cloning step as follows: +For the stable version, follow the same steps as above (as mentioned for the unstable/rolling/edge version) with an addition of one command which has to be performed after cloning and changing directory into the repository which makes the cloning step as follows: ```bash git clone https://github.com/neon-mmd/websurfx.git cd websurfx -git checkout rolling +git checkout stable ``` [⬅️ Go back to Home](./README.md) From 1d638ffeea75d7d1a86a9c07c04d1df5006d48d6 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sat, 27 May 2023 17:07:26 +0300 Subject: [PATCH 34/52] chore: fix the installation instructions under installation section --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 95d4d21..36b358b 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ To get started with Websurfx, clone the repository, edit the config file, which ``` shell git clone https://github.com/neon-mmd/websurfx.git cd websurfx +git checkout stable cargo build -r redis-server --port 8082 & ./target/release/websurfx From 294dfe74a9d21cfeb9a1cf6a8c86b9f0a45bf150 Mon Sep 17 00:00:00 2001 From: Sam sunder Date: Sat, 27 May 2023 15:01:52 +0000 Subject: [PATCH 35/52] Centered About page content --- public/static/themes/simple.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/static/themes/simple.css b/public/static/themes/simple.css index b9390e7..4ff3355 100644 --- a/public/static/themes/simple.css +++ b/public/static/themes/simple.css @@ -296,4 +296,5 @@ footer { .about-container h3{ font-size: 1.5rem; + width: 80%; } From 6006a983b331af9634c69c7d73407ae54dbb8454 Mon Sep 17 00:00:00 2001 From: Sam sunder Date: Sat, 27 May 2023 15:38:47 +0000 Subject: [PATCH 36/52] Centered about div 2nd commit --- public/static/themes/simple.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/static/themes/simple.css b/public/static/themes/simple.css index 4ff3355..17962d0 100644 --- a/public/static/themes/simple.css +++ b/public/static/themes/simple.css @@ -296,5 +296,8 @@ footer { .about-container h3{ font-size: 1.5rem; + } + + .about-container { width: 80%; } From 8e7dc68d2da3d7d2f79ed652b67d44e7ad018564 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sat, 27 May 2023 19:50:20 +0300 Subject: [PATCH 37/52] feat: add an option to enable or disable logs --- src/bin/websurfx.rs | 6 ++++-- src/config_parser/parser.rs | 2 ++ websurfx/config.lua | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bin/websurfx.rs b/src/bin/websurfx.rs index fa21486..ca05713 100644 --- a/src/bin/websurfx.rs +++ b/src/bin/websurfx.rs @@ -5,7 +5,6 @@ use std::net::TcpListener; -use env_logger::Env; use websurfx::{config_parser::parser::Config, run}; /// The function that launches the main server and registers all the routes of the website. @@ -20,7 +19,10 @@ async fn main() -> std::io::Result<()> { let config = Config::parse().unwrap(); // Initializing logging middleware with level set to default or info. - env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + if config.logging { + use env_logger::Env; + env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + } log::info!("started server on port {}", config.port); diff --git a/src/config_parser/parser.rs b/src/config_parser/parser.rs index 55d4bec..dd92f1b 100644 --- a/src/config_parser/parser.rs +++ b/src/config_parser/parser.rs @@ -25,6 +25,7 @@ pub struct Config { pub style: Style, pub redis_connection_url: String, pub aggregator: AggreatorConfig, + pub logging: bool, } /// Configuration options for the aggregator. @@ -71,6 +72,7 @@ impl Config { ), redis_connection_url: globals.get::<_, String>("redis_connection_url")?, aggregator: aggregator_config, + logging: globals.get::<_, bool>("logging")?, }) }) } diff --git a/websurfx/config.lua b/websurfx/config.lua index 595627e..29c4fff 100644 --- a/websurfx/config.lua +++ b/websurfx/config.lua @@ -1,3 +1,6 @@ +-- ### General ### +logging = true -- an option to enable or disable logs. + -- ### Server ### port = "8080" -- port on which server should be launched binding_ip_addr = "127.0.0.1" --ip address on the which server should be launched. From 473ada2871fb41a6c5a36de0dcfcd5863b548ed0 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sun, 28 May 2023 11:23:11 +0300 Subject: [PATCH 38/52] docs: update docs to explain about the new option logging --- docs/configuration.md | 5 +++++ docs/installation.md | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index bb10ba6..f700389 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -13,10 +13,15 @@ If you have installed `websurfx` using the package manager of your Linux distro Some of the configuration options provided in the file are stated below. These are subdivided into three categories: +- General - Server - Website - Cache +# General + +- **logging:** An option to enable or disable logs. + ## Server - **port:** Port number on which server should be launched. diff --git a/docs/installation.md b/docs/installation.md index d8f301b..1a04254 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -76,11 +76,17 @@ cd websurfx After that edit the config.lua file located under `websurfx` directory. In the config file you will specifically need to change to values which is `binding_ip_addr` and `redis_connection_url` which should make the config look something like this: ```lua --- Server +-- ### General ### +logging = true -- an option to enable or disable logs. + +-- ### Server ### port = "8080" -- port on which server should be launched binding_ip_addr = "0.0.0.0" --ip address on the which server should be launched. +production_use = false -- whether to use production mode or not (in other words this option should be used if it is to be used to host it on the server to provide a service to a large number of users) +-- if production_use is set to true +-- There will be a random delay before sending the request to the search engines, this is to prevent DDoSing the upstream search engines from a large number of simultaneous requests. --- Website +-- ### Website ### -- The different colorschemes provided are: -- {{ -- catppuccin-mocha @@ -95,12 +101,8 @@ binding_ip_addr = "0.0.0.0" --ip address on the which server should be launched. colorscheme = "catppuccin-mocha" -- the colorscheme name which should be used for the website theme theme = "simple" -- the theme name which should be used for the website --- Caching -redis_connection_url = "redis://127.0.0.1:8082" -- redis connection url address on which the client should connect on. - -production_use = false -- whether to use production mode or not (in other words this option should be used if it is to be used to host it on the server to provide a service to a large number of users) --- if production_use is set to true - -- There will be a random delay before sending the request to the search engines, this is to prevent DDoSing the upstream search engines from a large number of simultaneous requests. +-- ### Caching ### +redis_connection_url = "redis://redis:6379" -- redis connection url address on which the client should connect on. ``` After this run the following command to deploy the app: From 68da0d854aed612041dc2f183d19b7e2d8b9a1ed Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sun, 28 May 2023 11:24:28 +0300 Subject: [PATCH 39/52] docs: improve the wording of the configuration page --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index f700389..a5391a3 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -11,7 +11,7 @@ If you have built `websurfx` from source then the configuration file will be loc If you have installed `websurfx` using the package manager of your Linux distro then the default configuration file will be located at `/etc/xdg/websurfx/`. You can copy the default config to `~/.config/websurfx/` and make the changes there and rerun the websurfx server. -Some of the configuration options provided in the file are stated below. These are subdivided into three categories: +Some of the configuration options provided in the file are stated below. These are subdivided into the following categories: - General - Server From 7aa1394e7c6ebec20cc9f33660d6009311d719fc Mon Sep 17 00:00:00 2001 From: neon_arch Date: Sun, 28 May 2023 11:30:08 +0300 Subject: [PATCH 40/52] chore: bump version to v0.10.0 --- Cargo.lock | 157 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 78 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef32619..e35e94c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ "futures-sink", "memchr", "pin-project-lite", - "tokio 1.28.1", + "tokio 1.28.2", "tokio-util", "tracing", ] @@ -53,7 +53,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash 0.8.3", - "base64 0.21.1", + "base64 0.21.2", "bitflags", "brotli", "bytes 1.4.0", @@ -75,7 +75,7 @@ dependencies = [ "rand 0.8.5", "sha1", "smallvec 1.10.0", - "tokio 1.28.1", + "tokio 1.28.2", "tokio-util", "tracing", "zstd", @@ -87,7 +87,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ - "quote 1.0.27", + "quote 1.0.28", "syn 1.0.109", ] @@ -111,7 +111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" dependencies = [ "futures-core", - "tokio 1.28.1", + "tokio 1.28.2", ] [[package]] @@ -128,7 +128,7 @@ dependencies = [ "mio 0.8.6", "num_cpus", "socket2", - "tokio 1.28.1", + "tokio 1.28.2", "tracing", ] @@ -201,8 +201,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" dependencies = [ "actix-router", - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "syn 1.0.109", ] @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bit-set" @@ -605,8 +605,8 @@ dependencies = [ "itoa 1.0.6", "matches", "phf 0.10.1", - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "smallvec 1.10.0", "syn 1.0.109", ] @@ -617,7 +617,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" dependencies = [ - "quote 1.0.27", + "quote 1.0.28", "syn 1.0.109", ] @@ -628,8 +628,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "rustc_version 0.4.0", "syn 1.0.109", ] @@ -730,8 +730,8 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "syn 1.0.109", "synstructure", ] @@ -971,7 +971,7 @@ dependencies = [ "http 0.2.9", "indexmap", "slab", - "tokio 1.28.1", + "tokio 1.28.2", "tokio-util", "tracing", ] @@ -1035,8 +1035,8 @@ dependencies = [ "log", "mac", "markup5ever 0.11.0", - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "syn 1.0.109", ] @@ -1157,7 +1157,7 @@ dependencies = [ "itoa 1.0.6", "pin-project-lite", "socket2", - "tokio 1.28.1", + "tokio 1.28.2", "tower-service", "tracing", "want 0.3.0", @@ -1185,7 +1185,7 @@ dependencies = [ "bytes 1.4.0", "hyper 0.14.26", "native-tls", - "tokio 1.28.1", + "tokio 1.28.2", "tokio-native-tls", ] @@ -1381,12 +1381,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "mac" @@ -1631,9 +1628,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", ] [[package]] @@ -1749,9 +1746,9 @@ checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", ] [[package]] @@ -1863,8 +1860,8 @@ dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", "proc-macro-hack", - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "syn 1.0.109", ] @@ -1942,9 +1939,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] @@ -1970,11 +1967,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ - "proc-macro2 1.0.58", + "proc-macro2 1.0.59", ] [[package]] @@ -2213,9 +2210,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" dependencies = [ "aho-corasick", "memchr", @@ -2268,7 +2265,7 @@ version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64 0.21.1", + "base64 0.21.2", "bytes 1.4.0", "encoding_rs", "futures-core", @@ -2289,7 +2286,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded 0.7.1", - "tokio 1.28.1", + "tokio 1.28.2", "tokio-native-tls", "tower-service", "url 2.3.1", @@ -2495,9 +2492,9 @@ version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", ] [[package]] @@ -2680,8 +2677,8 @@ checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6" dependencies = [ "phf_generator 0.7.24", "phf_shared 0.7.24", - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "string_cache_shared", ] @@ -2693,8 +2690,8 @@ checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", ] [[package]] @@ -2720,19 +2717,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "unicode-ident", ] @@ -2742,8 +2739,8 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", + "proc-macro2 1.0.59", + "quote 1.0.28", "syn 1.0.109", "unicode-xid 0.2.4", ] @@ -2796,9 +2793,9 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", ] [[package]] @@ -2875,9 +2872,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg 1.1.0", "bytes 1.4.0", @@ -2940,9 +2937,9 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", ] [[package]] @@ -2952,7 +2949,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio 1.28.1", + "tokio 1.28.2", ] [[package]] @@ -3037,7 +3034,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", - "tokio 1.28.1", + "tokio 1.28.2", "tracing", ] @@ -3112,9 +3109,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -3260,9 +3257,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", "wasm-bindgen-shared", ] @@ -3284,7 +3281,7 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ - "quote 1.0.27", + "quote 1.0.28", "wasm-bindgen-macro-support", ] @@ -3294,9 +3291,9 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ - "proc-macro2 1.0.58", - "quote 1.0.27", - "syn 2.0.16", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3319,7 +3316,7 @@ dependencies = [ [[package]] name = "websurfx" -version = "0.9.0" +version = "0.10.0" dependencies = [ "actix-files", "actix-web", @@ -3336,7 +3333,7 @@ dependencies = [ "scraper", "serde", "serde_json", - "tokio 1.28.1", + "tokio 1.28.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 76335f8..8d8d452 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "websurfx" -version = "0.9.0" +version = "0.10.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 6ef6b323256220a5a84b6bc3ad7d089ea4654af4 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Mon, 29 May 2023 19:45:00 +0300 Subject: [PATCH 41/52] ci: add CI to automate the generation of contributors list --- .github/workflows/contributors.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/contributors.yml diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml new file mode 100644 index 0000000..bed59af --- /dev/null +++ b/.github/workflows/contributors.yml @@ -0,0 +1,16 @@ +name: Contributors +on: + schedule: + - cron: '0 1 * * *' # At 01:00 on every day. + push: + branches: + - rolling +jobs: + contributors: + runs-on: ubuntu-latest + steps: + - uses: wow-actions/contributors-list@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + round: true + svgPath: ../../images/contributors_list.svg From d4df90160d276b50a7b9ebf2728407574ae5d639 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Mon, 29 May 2023 21:09:07 +0300 Subject: [PATCH 42/52] feat: add an option to enable/disable debug mode --- src/bin/websurfx.rs | 2 +- src/config_parser/parser.rs | 2 ++ websurfx/config.lua | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bin/websurfx.rs b/src/bin/websurfx.rs index ca05713..91708aa 100644 --- a/src/bin/websurfx.rs +++ b/src/bin/websurfx.rs @@ -19,7 +19,7 @@ async fn main() -> std::io::Result<()> { let config = Config::parse().unwrap(); // Initializing logging middleware with level set to default or info. - if config.logging { + if config.logging || config.debug{ use env_logger::Env; env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); } diff --git a/src/config_parser/parser.rs b/src/config_parser/parser.rs index dd92f1b..ac200cd 100644 --- a/src/config_parser/parser.rs +++ b/src/config_parser/parser.rs @@ -26,6 +26,7 @@ pub struct Config { pub redis_connection_url: String, pub aggregator: AggreatorConfig, pub logging: bool, + pub debug: bool, } /// Configuration options for the aggregator. @@ -73,6 +74,7 @@ impl Config { redis_connection_url: globals.get::<_, String>("redis_connection_url")?, aggregator: aggregator_config, logging: globals.get::<_, bool>("logging")?, + debug: globals.get::<_, bool>("debug")?, }) }) } diff --git a/websurfx/config.lua b/websurfx/config.lua index 29c4fff..3daaa91 100644 --- a/websurfx/config.lua +++ b/websurfx/config.lua @@ -1,5 +1,6 @@ -- ### General ### logging = true -- an option to enable or disable logs. +debug = false -- an option to enable or disable debug mode. -- ### Server ### port = "8080" -- port on which server should be launched From 60317a3b75cbd256d3dd2b1723a31aa82bd051ef Mon Sep 17 00:00:00 2001 From: neon_arch Date: Mon, 29 May 2023 21:13:07 +0300 Subject: [PATCH 43/52] chore: make format ci happy --- src/bin/websurfx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/websurfx.rs b/src/bin/websurfx.rs index 91708aa..8661725 100644 --- a/src/bin/websurfx.rs +++ b/src/bin/websurfx.rs @@ -19,7 +19,7 @@ async fn main() -> std::io::Result<()> { let config = Config::parse().unwrap(); // Initializing logging middleware with level set to default or info. - if config.logging || config.debug{ + if config.logging || config.debug { use env_logger::Env; env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); } From eb44ff7cfa3a2736720052c64cd2f8fd2baca40c Mon Sep 17 00:00:00 2001 From: neon_arch Date: Mon, 29 May 2023 21:17:00 +0300 Subject: [PATCH 44/52] chore: Bump version to v0.11.0 --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e35e94c..9af7c18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,7 +125,7 @@ dependencies = [ "actix-utils", "futures-core", "futures-util", - "mio 0.8.6", + "mio 0.8.7", "num_cpus", "socket2", "tokio 1.28.2", @@ -1510,14 +1510,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "eebffdb73fe72e917997fad08bdbf31ac50b0fa91cec93e69a0662e4264d454c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1603,9 +1603,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "openssl" @@ -2879,7 +2879,7 @@ dependencies = [ "autocfg 1.1.0", "bytes 1.4.0", "libc", - "mio 0.8.6", + "mio 0.8.7", "num_cpus", "parking_lot 0.12.1", "pin-project-lite", @@ -3316,7 +3316,7 @@ dependencies = [ [[package]] name = "websurfx" -version = "0.10.0" +version = "0.11.0" dependencies = [ "actix-files", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index 8d8d452..17aa0a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "websurfx" -version = "0.10.0" +version = "0.11.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 13632f1f99bbabdbff503729a3238798d000c2bd Mon Sep 17 00:00:00 2001 From: neon_arch Date: Mon, 29 May 2023 21:28:09 +0300 Subject: [PATCH 45/52] feat: remove random delays when debug is set to true --- src/search_results_handler/aggregator.rs | 3 ++- src/server/routes.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/search_results_handler/aggregator.rs b/src/search_results_handler/aggregator.rs index 8b86972..8b6bae3 100644 --- a/src/search_results_handler/aggregator.rs +++ b/src/search_results_handler/aggregator.rs @@ -40,12 +40,13 @@ pub async fn aggregate( query: &str, page: u32, random_delay: bool, + debug: bool, ) -> Result> { let user_agent: String = random_user_agent(); let mut result_map: HashMap = HashMap::new(); // Add a random delay before making the request. - if random_delay { + if random_delay || !debug { let mut rng = rand::thread_rng(); let delay_secs = rng.gen_range(1..10); std::thread::sleep(Duration::from_secs(delay_secs)); diff --git a/src/server/routes.rs b/src/server/routes.rs index ead1612..9234d8d 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -128,7 +128,7 @@ pub async fn search( } Err(_) => { let mut results_json: crate::search_results_handler::aggregation_models::SearchResults = - aggregate(query, page, config.aggregator.random_delay).await?; + aggregate(query, page, config.aggregator.random_delay, config.debug).await?; results_json.add_style(config.style.clone()); redis_cache .cache_results(serde_json::to_string(&results_json)?, &page_url)?; From af8b3ce71b0b5d3388fe0ca009f22271aff19877 Mon Sep 17 00:00:00 2001 From: XFFXFF <1247714429@qq.com> Date: Tue, 30 May 2023 09:23:42 +0000 Subject: [PATCH 46/52] fix the contributor list action --- .github/workflows/contributors.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index bed59af..3d8580e 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -13,4 +13,4 @@ jobs: with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} round: true - svgPath: ../../images/contributors_list.svg + svgPath: images/contributors_list.svg From aeb2510de8c07f46ef09c09eb9f3ec8dfebc6806 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Tue, 30 May 2023 13:00:08 +0300 Subject: [PATCH 47/52] ci: fix contributors list autogeneration by appropriate permissions --- .github/workflows/contributors.yml | 45 +++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index bed59af..7d990f5 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -1,16 +1,47 @@ -name: Contributors +name: Contributors List + on: + workflow_dispatch: + schedule: - - cron: '0 1 * * *' # At 01:00 on every day. - push: - branches: - - rolling + - cron: "0 1 * * *" + jobs: contributors: + permissions: + contents: write + pull-requests: write + runs-on: ubuntu-latest + steps: - - uses: wow-actions/contributors-list@v1 + - name: Checkout code + uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + with: + fetch-depth: 0 + ref: ${{ github.event.repository.default_branch }} + + - name: Update contributors list + uses: wow-actions/contributors-list@b9e91f91a51a55460fdcae64daad0cb8122cdd53 # v1.1.0 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + svgPath: images/contributors_list.svg round: true - svgPath: ../../images/contributors_list.svg + includeBots: false + noCommit: true + + - name: Commit & PR + uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v4.2.4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + add-paths: .github/assets/CONTRIBUTORS.svg + commit-message: 'chore: update contributors-list' + committer: GitHub + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + signoff: false + branch: workflow/update-contributors-list + base: main + delete-branch: true + title: 'chore: update contributors-list' + body: | + Automated update to `images/contributors_list.svg` From af145e9d85249df3f89f76dd48f4b6a6255f8c24 Mon Sep 17 00:00:00 2001 From: neon_arch Date: Tue, 30 May 2023 14:55:11 +0300 Subject: [PATCH 48/52] docs: update docs to explain about the new option debug --- docs/configuration.md | 1 + docs/installation.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index a5391a3..0d54fd9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -21,6 +21,7 @@ Some of the configuration options provided in the file are stated below. These a # General - **logging:** An option to enable or disable logs. +- **debug:** An option to enable or disable debug mode. ## Server diff --git a/docs/installation.md b/docs/installation.md index 1a04254..fbb0d16 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -78,6 +78,7 @@ After that edit the config.lua file located under `websurfx` directory. In the c ```lua -- ### General ### logging = true -- an option to enable or disable logs. +debug = false -- an option to enable or disable debug mode. -- ### Server ### port = "8080" -- port on which server should be launched From 8c4d359e26aac0c8690c993362423794e20ae52c Mon Sep 17 00:00:00 2001 From: MD AL AMIN TALUKDAR <129589283+alamin655@users.noreply.github.com> Date: Wed, 31 May 2023 16:48:50 +0530 Subject: [PATCH 49/52] Create tokyo-night.css --- public/static/colorschemes/tokyo-night.css | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 public/static/colorschemes/tokyo-night.css diff --git a/public/static/colorschemes/tokyo-night.css b/public/static/colorschemes/tokyo-night.css new file mode 100644 index 0000000..b7a30cf --- /dev/null +++ b/public/static/colorschemes/tokyo-night.css @@ -0,0 +1,11 @@ +:root { + --bg: #1a1b26; + --fg: #c0caf5; + --1: #32364a; + --2: #a9b1d6; + --3: #5a5bb8; + --4: #6b7089; + --5: #e2afff; + --6: #a9a1e1; + --7: #988bc7; +} From bc43e15467af3917067085dd451a3fd15c4a3379 Mon Sep 17 00:00:00 2001 From: MD AL AMIN TALUKDAR <129589283+alamin655@users.noreply.github.com> Date: Wed, 31 May 2023 16:50:13 +0530 Subject: [PATCH 50/52] Create one-dark.css --- public/static/colorschemes/one-dark.css | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 public/static/colorschemes/one-dark.css diff --git a/public/static/colorschemes/one-dark.css b/public/static/colorschemes/one-dark.css new file mode 100644 index 0000000..0afb05e --- /dev/null +++ b/public/static/colorschemes/one-dark.css @@ -0,0 +1,11 @@ +:root { + --bg: #282c34; + --fg: #abb2bf; + --1: #3b4048; + --2: #a3be8c; + --3: #b48ead; + --4: #c8ccd4; + --5: #e06c75; + --6: #61afef; + --7: #be5046; +} From 59013c83e4fe6595651da5c77a4a6aeeeaab4003 Mon Sep 17 00:00:00 2001 From: MD AL AMIN TALUKDAR <129589283+alamin655@users.noreply.github.com> Date: Wed, 31 May 2023 16:51:00 +0530 Subject: [PATCH 51/52] Create dark-chocolate.css --- public/static/colorschemes/dark-chocolate.css | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 public/static/colorschemes/dark-chocolate.css diff --git a/public/static/colorschemes/dark-chocolate.css b/public/static/colorschemes/dark-chocolate.css new file mode 100644 index 0000000..f1d6848 --- /dev/null +++ b/public/static/colorschemes/dark-chocolate.css @@ -0,0 +1,11 @@ +:root { + --bg: #000000; + --fg: #ffffff; + --1: #121212; + --2: #808080; + --3: #999999; + --4: #666666; + --5: #bfbfbf; + --6: #e0e0e0; + --7: #555555; + } From 8dd18ebed885d94c2d6528ca42ca2a8a5ce47dcc Mon Sep 17 00:00:00 2001 From: neon_arch Date: Thu, 1 Jun 2023 12:25:36 +0300 Subject: [PATCH 52/52] chore: add pre-commit checks for writting better code --- .gitignore | 6 ++-- .rusty-hook.toml | 5 ++++ .stylelintrc.json | 13 +++++++++ Cargo.lock | 71 +++++++++++++++++++++++++++++++++++++++++------ Cargo.toml | 5 +++- 5 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 .rusty-hook.toml create mode 100644 .stylelintrc.json diff --git a/.gitignore b/.gitignore index c39800b..5e79d6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /target - -dump.rdb \ No newline at end of file +package.json +package-lock.json +dump.rdb +.vscode diff --git a/.rusty-hook.toml b/.rusty-hook.toml new file mode 100644 index 0000000..105b318 --- /dev/null +++ b/.rusty-hook.toml @@ -0,0 +1,5 @@ +[hooks] +pre-commit = "cargo test && cargo fmt -- --check && cargo clippy && stylelint ./public/static/themes/*.css ./public/static/colorschemes/*.css ./public/static/*.js" + +[logging] +verbose = true diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..9019f4f --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,13 @@ +{ + "extends": "stylelint-config-standard", + "rules": { + "alpha-value-notation": "number", + "selector-class-pattern": null + }, +"overrides": [ + { + "files": ["*.js"], + "customSyntax": "postcss-lit" + } + ] +} diff --git a/Cargo.lock b/Cargo.lock index 9af7c18..c3b4f93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,7 +125,7 @@ dependencies = [ "actix-utils", "futures-core", "futures-util", - "mio 0.8.7", + "mio 0.8.8", "num_cpus", "socket2", "tokio 1.28.2", @@ -438,6 +438,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ci_info" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f638c70e8c5753795cc9a8c07c44da91554a09e4cf11a7326e8161b0a3c45e" +dependencies = [ + "envmnt", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -693,6 +702,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "envmnt" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d328fc287c61314c4a61af7cfdcbd7e678e39778488c7cb13ec133ce0f4059" +dependencies = [ + "fsio", + "indexmap", +] + [[package]] name = "errno" version = "0.3.1" @@ -796,6 +815,12 @@ dependencies = [ "percent-encoding 2.2.0", ] +[[package]] +name = "fsio" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd087255f739f4f1aeea69f11b72f8080e9c2e7645cd06955dad4a178a49e3" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1510,9 +1535,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebffdb73fe72e917997fad08bdbf31ac50b0fa91cec93e69a0662e4264d454c" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", @@ -1567,6 +1592,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nias" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab250442c86f1850815b5d268639dff018c0627022bc1940eb2d642ca1ce12f0" + [[package]] name = "nodrop" version = "0.1.14" @@ -1609,9 +1640,9 @@ checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "openssl" -version = "0.10.52" +version = "0.10.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" +checksum = "12df40a956736488b7b44fe79fe12d4f245bb5b3f5a1f6095e499760015be392" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -1641,9 +1672,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.87" +version = "0.9.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" +checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" dependencies = [ "cc", "libc", @@ -2358,6 +2389,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rusty-hook" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cee9be61be7e1cbadd851e58ed7449c29c620f00b23df937cb9cbc04ac21a3" +dependencies = [ + "ci_info", + "getopts", + "nias", + "toml", +] + [[package]] name = "ryu" version = "1.0.13" @@ -2879,7 +2922,7 @@ dependencies = [ "autocfg 1.1.0", "bytes 1.4.0", "libc", - "mio 0.8.7", + "mio 0.8.8", "num_cpus", "parking_lot 0.12.1", "pin-project-lite", @@ -3038,6 +3081,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -3316,7 +3368,7 @@ dependencies = [ [[package]] name = "websurfx" -version = "0.11.0" +version = "0.12.0" dependencies = [ "actix-files", "actix-web", @@ -3330,6 +3382,7 @@ dependencies = [ "redis", "reqwest 0.11.18", "rlua", + "rusty-hook", "scraper", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 17aa0a0..b8f2755 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "websurfx" -version = "0.11.0" +version = "0.12.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -22,3 +22,6 @@ redis = {version="*"} md5 = {version="*"} rand={version="*"} once_cell = {version="*"} + +[dev-dependencies] +rusty-hook = "^0.11.2"