().applicationContext
+ val file = DocumentFile.fromTreeUri(ctx, uri)!!
+ return Game.checkIfGamedir(file)
+ }
+
+ fun setPageNumber(pos: Int) {
+ _pageNumber.value = pos
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/su/xash/engine/ui/setup/pages/LocationPageFragment.kt b/app/src/main/java/su/xash/engine/ui/setup/pages/LocationPageFragment.kt
new file mode 100644
index 00000000..9f069d9b
--- /dev/null
+++ b/app/src/main/java/su/xash/engine/ui/setup/pages/LocationPageFragment.kt
@@ -0,0 +1,62 @@
+package su.xash.engine.ui.setup.pages
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.navigation.fragment.findNavController
+import androidx.viewbinding.ViewBinding
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import su.xash.engine.R
+import su.xash.engine.databinding.PageLocationBinding
+import su.xash.engine.databinding.PageWelcomeBinding
+import su.xash.engine.ui.library.LibraryViewModel
+import su.xash.engine.ui.setup.SetupFragment
+import su.xash.engine.ui.setup.SetupViewModel
+
+class LocationPageFragment : Fragment() {
+ private var _binding: PageLocationBinding? = null
+ private val binding get() = _binding!!
+ private val setupViewModel: SetupViewModel by activityViewModels()
+ private val libraryViewModel: LibraryViewModel by activityViewModels()
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ _binding = PageLocationBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ binding.pageButton.setOnClickListener {
+ getGamesDirectory.launch(null)
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+ private val getGamesDirectory =
+ registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
+ it?.let {
+ if (!setupViewModel.checkIfGameDir(it)) {
+ MaterialAlertDialogBuilder(requireContext()).apply {
+ setTitle(R.string.error)
+ setMessage(R.string.setup_location_empty)
+ setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
+ show()
+ }
+ } else {
+ requireContext().contentResolver.takePersistableUriPermission(it, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ libraryViewModel.installGame(it)
+ findNavController().navigate(R.id.action_setupFragment_to_libraryFragment)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/su/xash/engine/ui/setup/pages/WelcomePageFragment.kt b/app/src/main/java/su/xash/engine/ui/setup/pages/WelcomePageFragment.kt
new file mode 100644
index 00000000..de87bf95
--- /dev/null
+++ b/app/src/main/java/su/xash/engine/ui/setup/pages/WelcomePageFragment.kt
@@ -0,0 +1,38 @@
+package su.xash.engine.ui.setup.pages
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.viewbinding.ViewBinding
+import su.xash.engine.databinding.PageLocationBinding
+import su.xash.engine.databinding.PageWelcomeBinding
+import su.xash.engine.ui.setup.SetupFragment
+import su.xash.engine.ui.setup.SetupViewModel
+
+class WelcomePageFragment : Fragment() {
+ private var _binding: PageWelcomeBinding? = null
+ private val binding get() = _binding!!
+ private val setupViewModel: SetupViewModel by activityViewModels()
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ _binding = PageWelcomeBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ binding.pageButton.setOnClickListener {
+ setupViewModel.setPageNumber(1)
+ }
+ setupViewModel.setPageNumber(0)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/su/xash/engine/util/TGAReader.java b/app/src/main/java/su/xash/engine/util/TGAReader.java
new file mode 100644
index 00000000..1e9f7d3f
--- /dev/null
+++ b/app/src/main/java/su/xash/engine/util/TGAReader.java
@@ -0,0 +1,589 @@
+/**
+ * TGAReader.java
+ *
+ * Copyright (c) 2014 Kenji Sasaki
+ * Released under the MIT license.
+ * https://github.com/npedotnet/TGAReader/blob/master/LICENSE
+ *
+ * English document
+ * https://github.com/npedotnet/TGAReader/blob/master/README.md
+ *
+ * Japanese document
+ * http://3dtech.jp/wiki/index.php?TGAReader
+ */
+
+package su.xash.engine.util;
+
+import java.io.IOException;
+
+public final class TGAReader {
+
+ public static final Order ARGB = new Order(16, 8, 0, 24);
+ public static final Order ABGR = new Order(0, 8, 16, 24);
+
+ public static int getWidth(byte[] buffer) {
+ return (buffer[12] & 0xFF) | (buffer[13] & 0xFF) << 8;
+ }
+
+ public static int getHeight(byte[] buffer) {
+ return (buffer[14] & 0xFF) | (buffer[15] & 0xFF) << 8;
+ }
+
+ public static int[] read(byte[] buffer, Order order) throws IOException {
+
+ // header
+// int idFieldLength = buffer[0] & 0xFF;
+// int colormapType = buffer[1] & 0xFF;
+ int type = buffer[2] & 0xFF;
+ int colormapOrigin = (buffer[3] & 0xFF) | (buffer[4] & 0xFF) << 8;
+ int colormapLength = (buffer[5] & 0xFF) | (buffer[6] & 0xFF) << 8;
+ int colormapDepth = buffer[7] & 0xFF;
+// int originX = (buffer[8] & 0xFF) | (buffer[9] & 0xFF) << 8; // unsupported
+// int originY = (buffer[10] & 0xFF) | (buffer[11] & 0xFF) << 8; // unsupported
+ int width = getWidth(buffer);
+ int height = getHeight(buffer);
+ int depth = buffer[16] & 0xFF;
+ int descriptor = buffer[17] & 0xFF;
+
+ int[] pixels;
+
+ // data
+ switch (type) {
+ case COLORMAP: {
+ int imageDataOffset = 18 + (colormapDepth / 8) * colormapLength;
+ pixels = createPixelsFromColormap(width, height, colormapDepth, buffer, imageDataOffset, buffer, colormapOrigin, descriptor, order);
+ }
+ break;
+ case RGB:
+ pixels = createPixelsFromRGB(width, height, depth, buffer, 18, descriptor, order);
+ break;
+ case GRAYSCALE:
+ pixels = createPixelsFromGrayscale(width, height, depth, buffer, 18, descriptor, order);
+ break;
+ case COLORMAP_RLE: {
+ int imageDataOffset = 18 + (colormapDepth / 8) * colormapLength;
+ byte[] decodeBuffer = decodeRLE(width, height, depth, buffer, imageDataOffset);
+ pixels = createPixelsFromColormap(width, height, colormapDepth, decodeBuffer, 0, buffer, colormapOrigin, descriptor, order);
+ }
+ break;
+ case RGB_RLE: {
+ byte[] decodeBuffer = decodeRLE(width, height, depth, buffer, 18);
+ pixels = createPixelsFromRGB(width, height, depth, decodeBuffer, 0, descriptor, order);
+ }
+ break;
+ case GRAYSCALE_RLE: {
+ byte[] decodeBuffer = decodeRLE(width, height, depth, buffer, 18);
+ pixels = createPixelsFromGrayscale(width, height, depth, decodeBuffer, 0, descriptor, order);
+ }
+ break;
+ default:
+ throw new IOException("Unsupported image type: " + type);
+ }
+
+ return pixels;
+
+ }
+
+ private static final int COLORMAP = 1;
+ private static final int RGB = 2;
+ private static final int GRAYSCALE = 3;
+ private static final int COLORMAP_RLE = 9;
+ private static final int RGB_RLE = 10;
+ private static final int GRAYSCALE_RLE = 11;
+
+ private static final int RIGHT_ORIGIN = 0x10;
+ private static final int UPPER_ORIGIN = 0x20;
+
+ private static byte[] decodeRLE(int width, int height, int depth, byte[] buffer, int offset) {
+ int elementCount = depth / 8;
+ byte[] elements = new byte[elementCount];
+ int decodeBufferLength = elementCount * width * height;
+ byte[] decodeBuffer = new byte[decodeBufferLength];
+ int decoded = 0;
+ while (decoded < decodeBufferLength) {
+ int packet = buffer[offset++] & 0xFF;
+ if ((packet & 0x80) != 0) { // RLE
+ for (int i = 0; i < elementCount; i++) {
+ elements[i] = buffer[offset++];
+ }
+ int count = (packet & 0x7F) + 1;
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < elementCount; j++) {
+ decodeBuffer[decoded++] = elements[j];
+ }
+ }
+ } else { // RAW
+ int count = (packet + 1) * elementCount;
+ for (int i = 0; i < count; i++) {
+ decodeBuffer[decoded++] = buffer[offset++];
+ }
+ }
+ }
+ return decodeBuffer;
+ }
+
+ private static int[] createPixelsFromColormap(int width, int height, int depth, byte[] bytes, int offset, byte[] palette, int colormapOrigin, int descriptor, Order order) throws IOException {
+ int[] pixels;
+ int rs = order.redShift;
+ int gs = order.greenShift;
+ int bs = order.blueShift;
+ int as = order.alphaShift;
+ switch (depth) {
+ case 24:
+ pixels = new int[width * height];
+ if ((descriptor & RIGHT_ORIGIN) != 0) {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 3 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * i + (width - j - 1)] = color;
+ }
+ }
+ } else {
+ // LowerRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 3 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * (height - i - 1) + (width - j - 1)] = color;
+ }
+ }
+ }
+ } else {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 3 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * i + j] = color;
+ }
+ }
+ } else {
+ // LowerLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 3 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * (height - i - 1) + j] = color;
+ }
+ }
+ }
+ }
+ break;
+ case 32:
+ pixels = new int[width * height];
+ if ((descriptor & RIGHT_ORIGIN) != 0) {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 4 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = palette[index + 3] & 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * i + (width - j - 1)] = color;
+ }
+ }
+ } else {
+ // LowerRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 4 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = palette[index + 3] & 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * (height - i - 1) + (width - j - 1)] = color;
+ }
+ }
+ }
+ } else {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 4 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = palette[index + 3] & 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * i + j] = color;
+ }
+ }
+ } else {
+ // LowerLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int colormapIndex = bytes[offset + width * i + j] &
+ 0xFF - colormapOrigin;
+ int color = 0xFFFFFFFF;
+ if (colormapIndex >= 0) {
+ int index = 4 * colormapIndex + 18;
+ int b = palette[index] & 0xFF;
+ int g = palette[index + 1] & 0xFF;
+ int r = palette[index + 2] & 0xFF;
+ int a = palette[index + 3] & 0xFF;
+ color = (r << rs) | (g << gs) | (b << bs) | (a << as);
+ }
+ pixels[width * (height - i - 1) + j] = color;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ throw new IOException("Unsupported depth:" + depth);
+ }
+ return pixels;
+ }
+
+ private static int[] createPixelsFromRGB(int width, int height, int depth, byte[] bytes, int offset, int descriptor, Order order) throws IOException {
+ int[] pixels;
+ int rs = order.redShift;
+ int gs = order.greenShift;
+ int bs = order.blueShift;
+ int as = order.alphaShift;
+ switch (depth) {
+ case 24:
+ pixels = new int[width * height];
+ if ((descriptor & RIGHT_ORIGIN) != 0) {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 3 * width * i + 3 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = 0xFF;
+ pixels[width * i + (width - j - 1)] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 3 * width * i + 3 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = 0xFF;
+ pixels[width * (height - i - 1) + (width - j - 1)] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ }
+ } else {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 3 * width * i + 3 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = 0xFF;
+ pixels[width * i + j] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 3 * width * i + 3 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = 0xFF;
+ pixels[width * (height - i - 1) + j] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ }
+ }
+ break;
+ case 32:
+ pixels = new int[width * height];
+ if ((descriptor & RIGHT_ORIGIN) != 0) {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 4 * width * i + 4 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = bytes[index + 3] & 0xFF;
+ pixels[width * i + (width - j - 1)] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 4 * width * i + 4 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = bytes[index + 3] & 0xFF;
+ pixels[width * (height - i - 1) + (width - j - 1)] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ }
+ } else {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 4 * width * i + 4 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = bytes[index + 3] & 0xFF;
+ pixels[width * i + j] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int index = offset + 4 * width * i + 4 * j;
+ int b = bytes[index] & 0xFF;
+ int g = bytes[index + 1] & 0xFF;
+ int r = bytes[index + 2] & 0xFF;
+ int a = bytes[index + 3] & 0xFF;
+ pixels[width * (height - i - 1) + j] = (r << rs) |
+ (g << gs) |
+ (b << bs) |
+ (a << as);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ throw new IOException("Unsupported depth:" + depth);
+ }
+ return pixels;
+ }
+
+ private static int[] createPixelsFromGrayscale(int width, int height, int depth, byte[] bytes, int offset, int descriptor, Order order) throws IOException {
+ int[] pixels;
+ int rs = order.redShift;
+ int gs = order.greenShift;
+ int bs = order.blueShift;
+ int as = order.alphaShift;
+ switch (depth) {
+ case 8:
+ pixels = new int[width * height];
+ if ((descriptor & RIGHT_ORIGIN) != 0) {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + width * i + j] & 0xFF;
+ int a = 0xFF;
+ pixels[width * i + (width - j - 1)] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + width * i + j] & 0xFF;
+ int a = 0xFF;
+ pixels[width * (height - i - 1) + (width - j - 1)] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ }
+ } else {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + width * i + j] & 0xFF;
+ int a = 0xFF;
+ pixels[width * i + j] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + width * i + j] & 0xFF;
+ int a = 0xFF;
+ pixels[width * (height - i - 1) + j] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ }
+ }
+ break;
+ case 16:
+ pixels = new int[width * height];
+ if ((descriptor & RIGHT_ORIGIN) != 0) {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
+ int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
+ pixels[width * i + (width - j - 1)] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerRight
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
+ int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
+ pixels[width * (height - i - 1) + (width - j - 1)] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ }
+ } else {
+ if ((descriptor & UPPER_ORIGIN) != 0) {
+ // UpperLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
+ int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
+ pixels[width * i + j] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ } else {
+ // LowerLeft
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
+ int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
+ pixels[width * (height - i - 1) + j] = (e << rs) |
+ (e << gs) |
+ (e << bs) |
+ (a << as);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ throw new IOException("Unsupported depth:" + depth);
+ }
+ return pixels;
+ }
+
+ private TGAReader() {
+ }
+
+ public static final class Order {
+ Order(int redShift, int greenShift, int blueShift, int alphaShift) {
+ this.redShift = redShift;
+ this.greenShift = greenShift;
+ this.blueShift = blueShift;
+ this.alphaShift = alphaShift;
+ }
+
+ public int redShift;
+ public int greenShift;
+ public int blueShift;
+ public int alphaShift;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/su/xash/engine/workers/FileCopyWorker.kt b/app/src/main/java/su/xash/engine/workers/FileCopyWorker.kt
new file mode 100644
index 00000000..7627cb64
--- /dev/null
+++ b/app/src/main/java/su/xash/engine/workers/FileCopyWorker.kt
@@ -0,0 +1,58 @@
+package su.xash.engine.workers
+
+import android.content.Context
+import android.net.Uri
+import android.provider.DocumentsContract
+import android.util.Log
+import androidx.documentfile.provider.DocumentFile
+import androidx.work.CoroutineWorker
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import su.xash.engine.model.Game
+import java.io.FileInputStream
+
+const val KEY_FILE_URI = "KEY_FILE_URI"
+
+class FileCopyWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
+ companion object {
+ const val Input = "Input"
+ }
+
+ override suspend fun doWork(): Result {
+ withContext(Dispatchers.IO) {
+ val fileUri = inputData.getString(KEY_FILE_URI)
+ setProgress(workDataOf(Input to fileUri))
+
+ val target = DocumentFile.fromFile(applicationContext.getExternalFilesDir(null)!!)
+ val source = DocumentFile.fromTreeUri(applicationContext, Uri.parse(fileUri))
+
+ source?.copyDirTo(applicationContext, target) ?: return@withContext Result.failure()
+ }
+ return Result.success()
+ }
+}
+
+fun DocumentFile.copyFileTo(ctx: Context, file: DocumentFile) {
+ val outFile = file.createFile("application", name!!)!!
+
+ ctx.contentResolver.openOutputStream(outFile.uri).use { os ->
+ ctx.contentResolver.openInputStream(uri).use {
+ it?.copyTo(os!!)
+ }
+ }
+}
+
+fun DocumentFile.copyDirTo(ctx: Context, dir: DocumentFile) {
+ val outDir = dir.createDirectory(name!!)!!
+
+ listFiles().forEach {
+ if (it.isDirectory) {
+ it.copyDirTo(ctx, outDir)
+ } else {
+ it.copyFileTo(ctx, outDir)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_baseline_add_24.xml b/app/src/main/res/drawable/ic_baseline_add_24.xml
new file mode 100644
index 00000000..0553ae30
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_add_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_delete_24.xml b/app/src/main/res/drawable/ic_baseline_delete_24.xml
new file mode 100644
index 00000000..79372b1d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_delete_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_folder_open_24.xml b/app/src/main/res/drawable/ic_baseline_folder_open_24.xml
new file mode 100644
index 00000000..76fd9059
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_folder_open_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_key_24.xml b/app/src/main/res/drawable/ic_baseline_key_24.xml
new file mode 100644
index 00000000..f49ad6f0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_key_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_person_24.xml b/app/src/main/res/drawable/ic_baseline_person_24.xml
new file mode 100644
index 00000000..98730cd9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_person_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml b/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml
new file mode 100644
index 00000000..97f9a3c0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_settings_24.xml b/app/src/main/res/drawable/ic_baseline_settings_24.xml
new file mode 100644
index 00000000..a7c7678d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_settings_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_terminal_24.xml b/app/src/main/res/drawable/ic_baseline_terminal_24.xml
new file mode 100644
index 00000000..fa304167
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_terminal_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/steam_button_gradient.xml b/app/src/main/res/drawable/steam_button_gradient.xml
new file mode 100644
index 00000000..6ee97b7b
--- /dev/null
+++ b/app/src/main/res/drawable/steam_button_gradient.xml
@@ -0,0 +1,15 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/steam_icon.xml b/app/src/main/res/drawable/steam_icon.xml
new file mode 100644
index 00000000..92b4ad0f
--- /dev/null
+++ b/app/src/main/res/drawable/steam_icon.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/steam_logo.xml b/app/src/main/res/drawable/steam_logo.xml
new file mode 100644
index 00000000..4fb91059
--- /dev/null
+++ b/app/src/main/res/drawable/steam_logo.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..3879b823
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/card_game.xml b/app/src/main/res/layout/card_game.xml
new file mode 100644
index 00000000..853b30e7
--- /dev/null
+++ b/app/src/main/res/layout/card_game.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/edit_text_preference.xml b/app/src/main/res/layout/edit_text_preference.xml
new file mode 100644
index 00000000..55d2bd17
--- /dev/null
+++ b/app/src/main/res/layout/edit_text_preference.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_app_settings.xml b/app/src/main/res/layout/fragment_app_settings.xml
new file mode 100644
index 00000000..0e738e9d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_app_settings.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_game_settings.xml b/app/src/main/res/layout/fragment_game_settings.xml
new file mode 100644
index 00000000..af1a003d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_game_settings.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml
new file mode 100644
index 00000000..ade658da
--- /dev/null
+++ b/app/src/main/res/layout/fragment_library.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_setup.xml b/app/src/main/res/layout/fragment_setup.xml
new file mode 100644
index 00000000..644a5b6f
--- /dev/null
+++ b/app/src/main/res/layout/fragment_setup.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_steam_login.xml b/app/src/main/res/layout/fragment_steam_login.xml
new file mode 100644
index 00000000..872437bd
--- /dev/null
+++ b/app/src/main/res/layout/fragment_steam_login.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_preference.xml b/app/src/main/res/layout/list_preference.xml
new file mode 100644
index 00000000..2a181013
--- /dev/null
+++ b/app/src/main/res/layout/list_preference.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/page_location.xml b/app/src/main/res/layout/page_location.xml
new file mode 100644
index 00000000..8659f4f5
--- /dev/null
+++ b/app/src/main/res/layout/page_location.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/page_welcome.xml b/app/src/main/res/layout/page_welcome.xml
new file mode 100644
index 00000000..eeeeb0da
--- /dev/null
+++ b/app/src/main/res/layout/page_welcome.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/steam_guard_dialog.xml b/app/src/main/res/layout/steam_guard_dialog.xml
new file mode 100644
index 00000000..84c7ec55
--- /dev/null
+++ b/app/src/main/res/layout/steam_guard_dialog.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/switch_preference.xml b/app/src/main/res/layout/switch_preference.xml
new file mode 100644
index 00000000..4ab4364b
--- /dev/null
+++ b/app/src/main/res/layout/switch_preference.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_game_settings.xml b/app/src/main/res/menu/menu_game_settings.xml
new file mode 100644
index 00000000..3a7c782b
--- /dev/null
+++ b/app/src/main/res/menu/menu_game_settings.xml
@@ -0,0 +1,14 @@
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_library.xml b/app/src/main/res/menu/menu_library.xml
new file mode 100644
index 00000000..a1830010
--- /dev/null
+++ b/app/src/main/res/menu/menu_library.xml
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..036d09bc
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..036d09bc
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..eb0b9248
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..5444e97c
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..c9dccea5
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..d1d5ddce
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..044af09d
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..dfe09de9
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..0b33b3df
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..53588d42
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..f3e13b91
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..992a8b31
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 00000000..d3d1b930
--- /dev/null
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
new file mode 100644
index 00000000..8b3c7def
--- /dev/null
+++ b/app/src/main/res/values-es/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Ok
+ Cancelar
+
\ No newline at end of file
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
new file mode 100644
index 00000000..4ab0095e
--- /dev/null
+++ b/app/src/main/res/values-it/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Annulla
+ Ok
+
\ No newline at end of file
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 00000000..8b3c7def
--- /dev/null
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Ok
+ Cancelar
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
new file mode 100644
index 00000000..e487cab8
--- /dev/null
+++ b/app/src/main/res/values-ru/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Отмена
+ ОК
+
\ No newline at end of file
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
new file mode 100644
index 00000000..7e859bf9
--- /dev/null
+++ b/app/src/main/res/values-tr/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Tamam
+ İptal
+
\ No newline at end of file
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
new file mode 100644
index 00000000..5089178e
--- /dev/null
+++ b/app/src/main/res/values-uk/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Ок
+ Скасувати
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..d6a7361c
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,12 @@
+
+
+ #F74843
+ #C5C3C0
+ #181A21
+ #32353C
+ #FB7E14
+ #000000
+ #151515
+ #292929
+
+
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 00000000..8a9d7629
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #F74843
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..1b76e0a6
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,36 @@
+
+
+ Xash3D FWGS
+ su.xash.engine.documents
+ Cancel
+ OK
+ Next
+ Browse
+ Install
+ Library
+ Steam Guard Code
+ Steam Login
+ Login
+ Username
+ Password
+ Steam
+ Uninstall
+ Dedicated
+ Error!
+ Setup
+ Settings
+ Game Settings
+ Command-line arguments
+ Use volume buttons in-game
+ Welcome to Xash3D FWGS!
+ Now, we will guide you through the installation process.
+ Games
+ Select the folder, where your games are located.
+ Selected directory doesn\'t contain any games.
+ Selected directory is invalid.
+ Libraries package
+ Libraries from separate packages
+ Client package
+ Server package
+ Use icons instead of backgrounds
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..a1f37a94
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 00000000..32040065
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,17 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/app_preferences.xml b/app/src/main/res/xml/app_preferences.xml
new file mode 100644
index 00000000..561f80d2
--- /dev/null
+++ b/app/src/main/res/xml/app_preferences.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/game_preferences.xml b/app/src/main/res/xml/game_preferences.xml
new file mode 100644
index 00000000..621089d0
--- /dev/null
+++ b/app/src/main/res/xml/game_preferences.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 00000000..b316d2cf
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,5 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ id("com.android.application") version "8.1.2" apply false
+ id("org.jetbrains.kotlin.android") version "1.9.0" apply false
+}
\ No newline at end of file
diff --git a/compile.sh b/compile.sh
deleted file mode 100755
index c4dba91e..00000000
--- a/compile.sh
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/bin/sh
-
-if echo "$HOME" | grep "com.termux"; then
- echo "-- Configuring for termux"
- export JAVAC=ecj
- export JAVA=true # /bin/true does nothing but returns success
- export JAR=true
- export JAVADOC=true
- TERMUX_ARG="--termux"
- TOOLCHAIN=host
-else
- echo "-- Configuring for Android SDK/NDK"
- if [ -z "$TOOLCHAIN" ]; then
- TOOLCHAIN=llvm
- fi
-fi
-
-if [ -z "$ARCHS" ]; then
- ARCHS="armeabi-v7a armeabi x86 aarch64"
-fi
-
-if [ -z "$API" ]; then
- API=9
-fi
-ROOT="$PWD" # compile.sh must be run from root of android project sources
-
-if [ -z "$1" ]; then
- BUILD_TYPE=debug
-else
- BUILD_TYPE=$1
- if [ "$TOOLCHAIN" = "host" || "$TOOLCHAIN" = "llvm" ]; then
- ENGINE_FLAGS="--enable-poly-opt"
- SDK_FLAGS="--enable-poly-opt"
- fi
-fi
-
-# Cleanup libraries
-rm -rf android/lib/
-
-# Generate extras.pak(TODO: move this to waf somehow)
-if [ -L "xash3d-fwgs-sl" ]; then
- python xash3d-fwgs-sl/scripts/makepak.py xash-extras android/assets/extras.pak
-else
- python xash3d-fwgs/scripts/makepak.py xash-extras android/assets/extras.pak
-fi
-
-# Generate configs
-android/gen-config.sh android/
-android/gen-version.sh android/
-
-# configure android project
-./waf configure -T $BUILD_TYPE $TERMUX_ARG|| exit 1
-
-die()
-{
- cat $1/config.log
- exit 1
-}
-
-build_native_project()
-{
- prj=$1
- shift
- arch=$1
- shift
-
- out="$ROOT/build-$prj/$arch"
-
- mkdir -p $out
- if [ -L "$prj-sl" ]; then
- cd $prj-sl # need to change directory, as waf doesn't work well with symlinks(used in development purposes)
- else
- cd $prj
- fi
- ./waf -o "$out" configure -T $BUILD_TYPE --android="$arch,$TOOLCHAIN,$API" $* build || die "$out"
- ./waf install --destdir=$ROOT/build/android/ --strip
- cd $ROOT # obviously, we can't ../ from symlink directory, so change to our root directory
-}
-
-# Do it inside waf?
-for i in $ARCHS; do
- build_native_project "xash3d-fwgs" "$i" $ENGINE_FLAGS
- build_native_project "hlsdk-xash3d" "$i" $SDK_FLAGS
-done
-
-# Run waf
-./waf build -v|| exit 1
-
-if [ "$BUILD_TYPE" != "debug" ] && [ "$USER" = "a1ba" ]; then
- # :)
- cp build/android/xashdroid.apk xashdroid.apk
-
- apksigner sign --ks ../myks.keystore xashdroid.apk
-else
- cp build/android/xashdroid-signed.apk xashdroid.apk
-fi
diff --git a/debug.keystore b/debug.keystore
index 7ef13e79..41f7fccb 100644
Binary files a/debug.keystore and b/debug.keystore differ
diff --git a/fastlane/Appfile b/fastlane/Appfile
new file mode 100644
index 00000000..fe341f3f
--- /dev/null
+++ b/fastlane/Appfile
@@ -0,0 +1,2 @@
+json_key_file("path/to/smth.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
+package_name("su.xash.engine") # e.g. com.krausefx.app
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
new file mode 100644
index 00000000..19c557cc
--- /dev/null
+++ b/fastlane/Fastfile
@@ -0,0 +1,38 @@
+# This file contains the fastlane.tools configuration
+# You can find the documentation at https://docs.fastlane.tools
+#
+# For a list of all available actions, check out
+#
+# https://docs.fastlane.tools/actions
+#
+# For a list of all available plugins, check out
+#
+# https://docs.fastlane.tools/plugins/available-plugins
+#
+
+# Uncomment the line if you want fastlane to automatically update itself
+# update_fastlane
+
+default_platform(:android)
+
+platform :android do
+ desc "Runs all the tests"
+ lane :test do
+ gradle(task: "test")
+ end
+
+ desc "Submit a new Beta Build to Crashlytics Beta"
+ lane :beta do
+ gradle(task: "clean assembleRelease")
+ crashlytics
+
+ # sh "your_script.sh"
+ # You can also use other beta testing services here
+ end
+
+ desc "Deploy a new version to the Google Play"
+ lane :deploy do
+ gradle(task: "clean assembleRelease")
+ upload_to_play_store
+ end
+end
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 00000000..3c5031eb
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..2b338a93
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..ab81a199
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Sep 22 13:23:17 EEST 2023
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 00000000..9d82f789
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..8a0b282a
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/hlsdk-xash3d b/hlsdk-xash3d
deleted file mode 160000
index eadade71..00000000
--- a/hlsdk-xash3d
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit eadade7157875c3bf589a54d7398e1dfa3d407ad
diff --git a/moddb/v1.json b/moddb/v1.json
new file mode 100644
index 00000000..d0ebfb32
--- /dev/null
+++ b/moddb/v1.json
@@ -0,0 +1,282 @@
+[
+ {
+ "name": "Counter-Strike",
+ "app_id": 10,
+ "gamedir": "cstrike",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Counter-Strike Base Content",
+ "depot_id": 11
+ },
+ {
+ "name": "Condition Zero Models",
+ "depot_id": 95
+ }
+ ],
+ "package_name": "in.celest.xash3d.cs16client"
+ },
+ {
+ "name": "Half-Life",
+ "app_id": 70,
+ "gamedir": "valve",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Half-Life Base Content",
+ "depot_id": 71
+ },
+ {
+ "name": "Half-Life High Definition",
+ "depot_id": 96
+ }
+ ],
+ "package_name": "su.xash.engine"
+ },
+ {
+ "name": "Half-Life: Opposing Force",
+ "app_id": 50,
+ "gamedir": "gearbox",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Opposing Force Base Content",
+ "depot_id": 51
+ },
+ {
+ "name": "Half-Life High Definition",
+ "depot_id": 96
+ }
+ ]
+ },
+ {
+ "name": "Counter-Strike: Condition Zero",
+ "app_id": 80,
+ "gamedir": "czero",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Counter-Strike Base Content",
+ "depot_id": 11
+ },
+ {
+ "name": "Condition Zero Base Contentt",
+ "depot_id": 81
+ }
+ ]
+ },
+ {
+ "name": "Half-Life: Blue Shift",
+ "app_id": 130,
+ "gamedir": "bshift",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Half-Life: Blue Shift",
+ "depot_id": 130
+ },
+ {
+ "name": "Half-Life High Definition",
+ "depot_id": 96
+ }
+ ]
+ },
+ {
+ "name": "Half-Life: C.A.G.E.D.",
+ "app_id": 679990,
+ "gamedir": "caged_fgs",
+ "depots": [
+ {
+ "name": "Half-Life: Caged Content",
+ "depot_id": 679991
+ },
+ {
+ "name": "Half-Life: C.A.G.E.D. Pathnodes",
+ "depot_id": 679992
+ },
+ {
+ "name": "Half-Life: C.A.G.E.D. HOLIDAY NONE",
+ "depot_id": 679996
+ }
+ ]
+ },
+ {
+ "name": "Day of Defeat",
+ "app_id": 30,
+ "gamedir": "dod",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Day of Defeat Base Content",
+ "depot_id": 31
+ }
+ ]
+ },
+ {
+ "name": "Cry of Fear",
+ "app_id": 223710,
+ "gamedir": "cryoffear",
+ "depots": [
+ {
+ "name": "Cry of Fear Content",
+ "depot_id": 223711
+ }
+ ]
+ },
+ {
+ "name": "Headcrab Frenzy!",
+ "app_id": 354900,
+ "gamedir": "hcfrenzy",
+ "depots": [
+ {
+ "name": "Headcrab Frenzy Common Content",
+ "depot_id": 354901
+ }
+ ]
+ },
+ {
+ "name": "Team Fortress Classic",
+ "app_id": 20,
+ "gamedir": "tfc",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Team Fortress Classic Base Content",
+ "depot_id": 21
+ },
+ {
+ "name": "Half-Life High Definition",
+ "depot_id": 96
+ }
+ ]
+ },
+ {
+ "name": "Base Defense",
+ "app_id": 632730,
+ "gamedir": "bdef",
+ "depots": [
+ {
+ "name": "Base Defense Content",
+ "depot_id": 632731
+ }
+ ]
+ },
+ {
+ "name": "Ricochet",
+ "app_id": 60,
+ "gamedir": "ricochet",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Ricochet Base Content",
+ "depot_id": 61
+ }
+ ]
+ },
+ {
+ "name": "Deathmatch Classic",
+ "app_id": 40,
+ "gamedir": "dmc",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Deathmatch Classic Base Content",
+ "depot_id": 41
+ }
+ ]
+ },
+ {
+ "name": "Halfquake Trilogy",
+ "app_id": 644320,
+ "gamedir": "hqtrilogy",
+ "depots": [
+ {
+ "name": "Halfquake Trilogy Content",
+ "depot_id": 644321
+ }
+ ]
+ },
+ {
+ "name": "Half-Rats: Parasomnia",
+ "app_id": 638360,
+ "gamedir": "hrp",
+ "depots": [
+ {
+ "name": "Parasomnia - Content",
+ "depot_id": 638361
+ },
+ {
+ "name": "Gold Source (Parasomnia) - Content",
+ "depot_id": 638364
+ }
+ ]
+ },
+ {
+ "name": "Counter-Strike: Condition Zero Deleted Scenes",
+ "app_id": 100,
+ "gamedir": "czeror",
+ "depots": [
+ {
+ "name": "Base Goldsrc Shared Content",
+ "depot_id": 1
+ },
+ {
+ "name": "Counter-Strike Base Content",
+ "depot_id": 11
+ },
+ {
+ "name": "Condition Zero Deleted Scenes Base Content",
+ "depot_id": 101
+ }
+ ]
+ },
+ {
+ "name": "Hard-Life",
+ "app_id": 850870,
+ "gamedir": "hardlife",
+ "depots": [
+ {
+ "name": "Hard-Life Content",
+ "depot_id": 850871
+ }
+ ]
+ },
+ {
+ "name": "Half-Life Decay: Solo Mission DEMO",
+ "app_id": 1889470,
+ "gamedir": "decaysolodemo",
+ "depots": [
+ {
+ "name": "Half-Life Decay: Solo Mission Demo Content",
+ "depot_id": 1889471
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/scripts/auto-rename.sh b/scripts/auto-rename.sh
deleted file mode 100755
index af4b0ca0..00000000
--- a/scripts/auto-rename.sh
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/bin/bash
-
-# Was used to move bunch of travis autobuilds to new path
-
-# Remove unneeded info
-function clearName
-{
- echo $1 | sed 's/xashdroid-//;s/.apk//'
-}
-
-function getYear
-{
- echo $1 | awk -F- '{ print $(NF-4)}'
-}
-
-function getMonth
-{
- echo $1 | awk -F- '{ print $(NF-3)}'
-}
-
-function getDay
-{
- echo $1 | awk -F- '{ print $(NF-2)}' | awk -F_ '{ print $1 }'
-}
-
-function getHour
-{
- echo $1 | awk -F- '{ print $(NF-2)}' | awk -F_ '{ print $2 }'
-}
-
-function getMinute
-{
- echo $1 | awk -F- '{ print $(NF-1)}'
-}
-
-function getHash
-{
- echo $1 | awk -F- '{ print $(NF)}'
-}
-
-
-function getArch
-{
- local SECOND=`echo $1 | awk -F- '{ print $(NF-5)}'`
- local FIRST=`echo $1 | awk -F- '{ print $(NF-6)}'`
-
- if [ "$SECOND" = "tegra2" ]; then
- echo $FIRST-$SECOND
- else
- echo $SECOND
- fi
-}
-
-function getDaysSinceRelease
-{
- printf %04d $(( ( $(date -ud "$1$2$3" +'%s') - $(date -ud '150401' +'%s') )/60/60/24 ))
-}
-
-
-for i in *.apk;
-do
- NAME=`clearName ${i}`
- YEAR=`getYear ${NAME}`
- MONTH=`getMonth ${NAME}`
- DAY=`getDay ${NAME}`
- HOUR=`getHour ${NAME}`
- MINUTE=`getMinute ${NAME}`
- ARCH=`getArch ${NAME}`
- HASH=`getHash ${NAME}`
- DAYSSINCERELEASE=`getDaysSinceRelease ${YEAR} ${MONTH} ${DAY}`
-
- echo "Moving ${i} to 20${YEAR}/${MONTH}/${DAY}/xash3d-${DAYSSINCERELEASE}-${HOUR}-${MINUTE}-${ARCH}-${HASH}.apk"
- mkdir -p 20${YEAR}/${MONTH}/${DAY}/
- mv ${i} 20${YEAR}/${MONTH}/${DAY}/xash3d-${DAYSSINCERELEASE}-${HOUR}-${MINUTE}-${ARCH}-${HASH}.apk
-done
\ No newline at end of file
diff --git a/scripts/travis-upload.sh b/scripts/travis-upload.sh
deleted file mode 100755
index 251f9a73..00000000
--- a/scripts/travis-upload.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/bash
-
-# Upload travis generated APKs to the Transfer.sh and Yandex.Disk
-
-function getDaysSinceRelease
-{
- printf %04d $(( ( $(date +'%s') - $(date -ud '150401' +'%s') )/60/60/24 ))
-}
-
-DAYSSINCERELEASE=`getDaysSinceRelease`
-COMMITHASH=$(git rev-parse --short HEAD)
-CURRENTBRANCH=$(git rev-parse --abbrev-ref HEAD)
-
-function generateFileName
-{
- echo "xash3d-$DAYSSINCERELEASE-$(date +"%H-%M")-$1-$COMMITHASH.apk"
-}
-
-
-
-# Transfer.sh
-TRANSFERSH_ARMV5=`curl --upload-file xashdroid-armv5.apk https://transfer.sh/$(generateFileName armv5)`
-TRANSFERSH_ARMV6=`curl --upload-file xashdroid-armv6.apk https://transfer.sh/$(generateFileName armv6)`
-TRANSFERSH_ARMV7=`curl --upload-file xashdroid-armv7.apk https://transfer.sh/$(generateFileName armv7)`
-TRANSFERSH_ARMV7TEGRA2=`curl --upload-file xashdroid-armv7-tegra2.apk https://transfer.sh/$(generateFileName armv7-tegra2)`
-TRANSFERSH_X86=`curl --upload-file xashdroid-x86.apk https://transfer.sh/$(generateFileName x86)`
-
-echo "Transfer.sh links:"
-echo "armv5: ${TRANSFERSH_ARMV5}"
-echo "armv6: ${TRANSFERSH_ARMV6}"
-echo "armv7: ${TRANSFERSH_ARMV7}"
-echo "tegra2: ${TRANSFERSH_ARMV7TEGRA2}"
-echo "x86: ${TRANSFERSH_X86}"
-
-# YaDisk
-
-YADISKPATH=`date +%Y/%m/%d`
-
-curl -u $YADISK_USERNAME:$YADISK_PASSWORD -X MKCOL https://webdav.yandex.ru/XashTestVersions/`date +%Y`
-curl -u $YADISK_USERNAME:$YADISK_PASSWORD -X MKCOL https://webdav.yandex.ru/XashTestVersions/`date +%Y/%m`/
-curl -u $YADISK_USERNAME:$YADISK_PASSWORD -X MKCOL https://webdav.yandex.ru/XashTestVersions/`date +%Y/%m/%d`/
-
-curl -T xashdroid-armv7.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$YADISKPATH/$(generateFileName armv7)
-curl -T xashdroid-armv6.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$YADISKPATH/$(generateFileName armv6)
-curl -T xashdroid-armv5.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$YADISKPATH/$(generateFileName armv5)
-curl -T xashdroid-armv7-tegra2.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$YADISKPATH/$(generateFileName armv7-tegra2)
-curl -T xashdroid-x86.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$YADISKPATH/$(generateFileName x86)
-
-# Update current
-# $TRAVIS_BRANCH is predefined by Travis CI
-function generateFileName_current
-{
- echo "xash3d-current-$1-$TRAVIS_BRANCH.apk"
-}
-
-curl -T xashdroid-armv7.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$(generateFileName_current armv7)
-curl -T xashdroid-armv6.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$(generateFileName_current armv6)
-curl -T xashdroid-armv5.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$(generateFileName_current armv5)
-curl -T xashdroid-armv7-tegra2.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$(generateFileName_current armv7-tegra2)
-curl -T xashdroid-x86.apk -u $YADISK_USERNAME:$YADISK_PASSWORD https://webdav.yandex.ru/XashTestVersions/$(generateFileName_current x86)
-
-
-exit 0
diff --git a/scripts/waifulib/android.py b/scripts/waifulib/android.py
deleted file mode 100644
index 93c58cae..00000000
--- a/scripts/waifulib/android.py
+++ /dev/null
@@ -1,337 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# a1batross, 2019
-
-import os
-from waflib import *
-from waflib.Tools import javaw
-
-android_sdk_home_env = ['ANDROID_SDK_HOME', 'ANDROID_SDK']
-
-# d8 started to roll out in 28
-D8_BUILD_TOOLS_MAJOR_VER = 28
-
-def options(opt):
- grp = opt.add_option_group('Android options')
-
- grp.add_option('--termux', dest='termux', default=False, action='store_true',
- help='configure to use tools included in termux')
- return
-
-def add_paths_to_path(paths):
- save_path = os.environ['PATH']
- os.environ['PATH'] = os.pathsep.join(paths) + os.pathsep + save_path
-
-def get_latest_build_tools_version(sdk):
- build_tools_path = os.path.join(sdk, 'build-tools')
- dirs = os.listdir(build_tools_path)
- dirs.sort(reverse=True)
- return dirs[0]
-
-def get_build_tools(sdk, ver):
- return os.path.join(sdk, 'build-tools', ver)
-
-def configure(conf):
- conf.load('java')
- paths = []
- if not conf.options.termux:
- conf.start_msg('Checking environment variables')
-
- sdk = None
- for i in android_sdk_home_env:
- if i in os.environ:
- sdk = conf.env.ANDROID_SDK_HOME_ENV = os.environ[i]
- break
-
- if not sdk:
- conf.fatal('Can\'t find path to SDK. Check if ANDROID_SDK_HOME environment variable is set')
- return
-
- conf.end_msg('ok')
-
- btv = get_latest_build_tools_version(sdk)
-
- conf.msg('Detected build-tools version', btv)
-
- paths += [os.path.join(sdk, 'tools'), get_build_tools(sdk, btv)]
-
- conf.env.BUILD_TOOLS_VERSION = [int(x) for x in btv.split('.')]
- else:
- conf.env.BUILD_TOOLS_VERSION = [ 0, 0, 0 ]
-
- paths += os.environ['PATH'].split(os.pathsep) # just in case we have installed tools
-
- conf.env.termux = conf.options.termux
-
- # mandatory
- for i in ['zipalign', 'apksigner', 'zip']:
- conf.find_program(i, path_list = paths)
-
- # optional
- try:
- conf.find_program('aapt', path_list = paths)
- except Errors.ConfigurationError:
- conf.find_program('aapt2', path_list = paths)
-
- # optional
- # if conf.env.BUILD_TOOLS_VERSION[0] >= D8_BUILD_TOOLS_MAJOR_VER:
- try:
- conf.find_program('d8', path_list = paths)
- # else:
- except Errors.ConfigurationError:
- conf.find_program('dx', path_list = paths)
-
-class aapt2compile(javaw.JTask):
- color = 'GREEN'
- run_str = 'mkdir -p ${RESOUTFILE} && ${AAPT2} compile -v ${SRC} -o ${RESOUTFILE}'
- vars = ['AAPT2', 'RESOUTFILE', 'RESDIR']
-
- def uid(self):
- """
- Hash by resource directory path
- """
- return Utils.h_list([self.__class__.__name__, self.generator.outdir.abspath(), self.env.RESDIR])
-
- def runnable_status(self):
- """
- Waits for dependent tasks to be complete, then read the file system to find the input nodes.
- """
- for t in self.run_after:
- if not t.hasrun:
- return Task.ASK_LATER
-
- if not self.inputs:
- root = self.generator.outdir.ctx.root
- resdir = root.make_node(self.env.RESDIR)
- self.inputs = resdir.ant_glob('**/*', quiet=True)
-
- return super(aapt2compile, self).runnable_status()
-
- def post_run(self):
- """
- List class files created
- """
- for node in self.generator.outdir.ant_glob('**/*.flat', quiet=True):
- self.generator.bld.node_sigs[node] = self.uid()
- self.generator.bld.task_sigs[self.uid()] = self.cache_sig
-
-class aapt2link(javaw.JTask):
- color = 'GREEN' # android green :)
- run_str = '${AAPT2} link -v ${AAPT2_LINKFLAGS} -o ${TGT} -A ${ASSETSDIR} --manifest ${MANIFEST} --java ${OUTRDIR} -I ${CLASSPATH_ANDROID} ${SRC}'
- vars = ['AAPT2', 'ASSETSDIR', 'MANIFEST', 'OUTRDIR', 'CLASSPATH_ANDROID']
-
- def runnable_status(self):
- """
- Waits for dependent tasks to be complete, then read the file system to find the input nodes.
- """
- for t in self.run_after:
- if not t.hasrun:
- return Task.ASK_LATER
-
- if not self.inputs:
- root = self.generator.outdir.ctx.root
- resdir = root.make_node(self.env.RESOUTFILE)
- self.inputs = resdir.ant_glob('**/*.flat', quiet=True)
-
- return super(aapt2link, self).runnable_status()
-
-class aaptpackage(javaw.JTask):
- color = 'GREEN' # androis green :)
- run_str = 'mkdir -p ${OUTRDIR} && ${AAPT} p -v -F ${TGT} -J ${OUTRDIR} -A ${ASSETSDIR} -I ${CLASSPATH_ANDROID} -M ${MANIFEST} -S ${RESDIR} -f'
- vars = ['AAPT', 'OUTRDIR', 'ASSETSDIR', 'CLASSPATH_ANDROID', 'MANIFEST', 'RESDIR' ]
-
- def runnable_status(self):
- """
- Waits for dependent tasks to be complete, then read the file system to find the input nodes.
- """
- for t in self.run_after:
- if not t.hasrun:
- return Task.ASK_LATER
-
- if not self.inputs:
- root = self.generator.outdir.ctx.root
- resdir = root.make_node(self.env.RESDIR)
- self.inputs = resdir.ant_glob('**/*', quiet=True) + [root.make_node(self.env.MANIFEST)]
-
- return super(aaptpackage, self).runnable_status()
-
-class DexerTask(javaw.JTask): # base dexer
- color = 'GREEN'
-
- def runnable_status(self):
- for t in self.run_after:
- if not t.hasrun:
- return Task.ASK_LATER
-
- if not self.inputs:
- self.inputs = self.generator.outdir.ant_glob('**/*.class', quiet=True)
-
- return super(DexerTask, self).runnable_status()
-
-class d8(DexerTask):
- # can't use TGT instead of OUTDIR here, because Google code monkeys don't know what __output__ should mean
- run_str = '${D8} ${SRC} ${D8_FLAGS} --output ${OUTDIR} --lib ${CLASSPATH_ANDROID} ${D8_CLASSPATH}'
- vars = ['D8', 'D8_FLAGS', 'OUTDIR', 'CLASSPATH_ANDROID', 'D8_CLASSPATH' ]
-
-class dx(DexerTask):
- run_str = '${DX} --dex ${D8_FLAGS} --output=${TGT} ${SRC} ${DX_CLASSPATH}'
- vars = ['DX', 'D8_FLAGS', 'OUTDIR']
-
-def custom_runnable_status(self):
- if not self.inputs:
- outrdir = self.srcdir[0].ctx.root.make_node(self.env.OUTRDIR)
- self.srcdir.append(outrdir)
- return self.old_runnable_status()
-setattr(javaw.javac, 'old_runnable_status', getattr(javaw.javac, 'runnable_status', None))
-setattr(javaw.javac, 'runnable_status', custom_runnable_status)
-
-class apkjni(Task.Task):
- color = 'BLUE'
- run_str = '${ZIP} -ru ${OUTAPK_UNALIGNED_NOCLASSES_NOJNI} ${JNIDIR} --out ${TGT}'
- vars = ['ZIP', 'JNIDIR', 'OUTAPK_UNALIGNED_NOCLASSES_NOJNI']
-
- def runnable_status(self):
- """
- Waits for dependent tasks to be complete, then read the file system to find the input nodes.
- """
- for t in self.run_after:
- if not t.hasrun:
- return Task.ASK_LATER
-
- # I could use SRC here, but I need to track changes of OUTAPK_UNALIGNED_NOCLASSES_NOJNI also
- self.inputs += self.generator.outdir.ant_glob('{0}/**/*'.format(self.env.JNIDIR), quiet=True)
-
- return super(apkjni, self).runnable_status()
-
-class apkdex(Task.Task):
- color = 'GREEN' # android green :)
- run_str = '${ZIP} -uj ${SRC} --out ${TGT}'
- vars = ['ZIP']
-
-class apkalign(Task.Task):
- color = 'GREEN' # android green :)
- run_str = '${ZIPALIGN} -f -v 4 ${SRC} ${TGT}'
- vars = ['ZIPALIGN']
-
-class SignerTask(Task.Task):
- color = 'GREEN'
- vars = ['APKSIGNER', 'KEYSTORE', 'KS_ALIAS', 'KS_PASS', 'KEY_PASS']
-
-class apksigner(SignerTask):
- run_str = '${APKSIGNER} sign --ks ${KEYSTORE} --ks-key-alias ${KS_ALIAS} --ks-pass ${KS_PASS} --key-pass ${KEY_PASS} --in ${SRC} --out ${TGT}'
-
-class apksigner_termux(SignerTask):
- run_str = '${APKSIGNER} ${KEYSTORE} ${SRC} ${TGT}'
-
-@TaskGen.feature('android')
-@TaskGen.before_method('apply_java')
-def apply_aapt(self):
- # Build resources, generate R.java and create empty APK
- outdir = getattr(self, 'outdir', None)
- if outdir:
- if not isinstance(outdir, Node.Node):
- outdir = self.path.get_bld().make_node(self.outdir)
- else:
- outdir = self.path.get_bld()
- outdir.mkdir()
- self.outdir = outdir
-
- srcdir = self.path.find_dir('.')
- sdk = self.env.ANDROID_SDK_HOME_ENV
-
- self.env.RESDIR = os.path.join(srcdir.abspath(), getattr(self, 'resdir', 'res'))
- self.env.ASSETSDIR = os.path.join(srcdir.abspath(), getattr(self, 'assetsdir', 'assets'))
- self.env.MANIFEST = os.path.join(srcdir.abspath(), getattr(self, 'manifest', 'AndroidManifest.xml'))
-
- try:
- self.env.JNIDIR = self.jni
- except AttributeError:
- pass
-
- self.env.OUTAPK_SIGNED = self.name + '-signed.apk'
- self.env.OUTAPK = self.name + '.apk'
- self.env.OUTAPK_UNALIGNED = self.name + '.unaligned.apk'
- self.env.OUTAPK_UNALIGNED_NOCLASSES = self.name + '.unaligned.noclasses.apk'
-
- if self.env.JNIDIR:
- self.env.OUTAPK_UNALIGNED_NOCLASSES_NOJNI = self.name + '.unaligned.noclasses.nojni.apk'
- else:
- self.env.OUTAPK_UNALIGNED_NOCLASSES_NOJNI = self.env.OUTAPK_UNALIGNED_NOCLASSES
-
- if self.env.BUILD_TOOLS_VERSION[0] > 27:
- self.env.append_unique('AAPT2_LINKFLAGS', '--allow-reserved-package-id')
-
- self.env.OUTRDIR = os.path.join(outdir.abspath(), getattr(self, 'gendir', 'gen')) # build/gen
- self.env.RESOUTFILE = os.path.join(outdir.abspath(), 'compiled')
- self.env.OUTDIR = outdir.abspath()
- self.env.TARGET_API = getattr(self, 'target_api', 10) # Android 2.3.3 TODO: parse AndroidManifest.xml to get target API!
- if self.env.termux:
- classpath = os.path.join(os.environ['PREFIX'], 'share', 'java', 'android.jar')
- else: classpath = os.path.join(sdk, 'platforms', 'android-' + str(self.env.TARGET_API), 'android.jar')
- self.env.CLASSPATH_ANDROID = classpath
-
-
- tgt = self.outdir.make_node(self.env.OUTAPK_UNALIGNED_NOCLASSES_NOJNI)
- if self.env.AAPT:
- self.aapt2link_task = self.create_task('aaptpackage', tgt=tgt, cwd=outdir)
- else:
- self.aapt2compile_task = self.create_task('aapt2compile', cwd=outdir)
- self.aapt2link_task = self.create_task('aapt2link', tgt=tgt, cwd=outdir)
- self.aapt2link_task.set_run_after(self.aapt2compile_task) # we don't know *.flat outputs from aapt2compile yet
-
-@TaskGen.feature('android')
-@TaskGen.after_method('apply_java')
-def apply_d8(self):
- self.javac_task.set_run_after(self.aapt2link_task) # we don't know R.java yet
-
- if getattr(self, 'debug', False):
- self.env.D8_FLAGS = '--debug'
- elif self.env.D8: self.env.D8_FLAGS = '--release'
-
- self.d8_task = self.create_task('d8' if self.env.D8 else 'dx',
- tgt=self.outdir.make_node('classes.dex'),
- cwd=self.outdir)
- self.d8_task.set_run_after(self.javac_task) # we don't know javac outputs
-
- if self.env.JNIDIR:
- self.apkjni_task = self.create_task('apkjni',
- src=self.outdir.make_node(self.env.OUTAPK_UNALIGNED_NOCLASSES_NOJNI),
- tgt=self.outdir.make_node(self.env.OUTAPK_UNALIGNED_NOCLASSES),
- cwd=self.outdir)
-
- self.apkdex_task = self.create_task('apkdex',
- [self.outdir.make_node(self.env.OUTAPK_UNALIGNED_NOCLASSES), self.d8_task.outputs[0]],
- self.outdir.make_node(self.env.OUTAPK_UNALIGNED),
- cwd=self.outdir)
-
- self.apkalign_task = self.create_task('apkalign',
- self.outdir.make_node(self.env.OUTAPK_UNALIGNED),
- self.outdir.make_node(self.env.OUTAPK),
- cwd=self.outdir)
-
- # signing is optional
- try:
- self.env.KEYSTORE = self.keystore.abspath()
- if 'debug' in self.env.KEYSTORE:
- self.env.KS_ALIAS = 'androiddebugkey'
- self.env.KS_PASS = self.env.KEY_PASS = 'pass:android'
- else:
- self.env.KS_ALIAS = self.ks_alias
- self.env.KS_PASS = self.ks_pass
- self.env.KEY_PASS = self.key_pass
-
- self.apksigner_task = self.create_task('apksigner' if not self.env.termux else 'apksigner_termux',
- self.outdir.make_node(self.env.OUTAPK),
- self.outdir.make_node(self.env.OUTAPK_SIGNED))
- except AttributeError:
- pass
-
-@TaskGen.feature('android')
-@TaskGen.after_method('set_classpath')
-def set_android_classpath(self):
- if len(self.env.CLASSPATH) == 0:
- self.env.D8_CLASSPATH = ''
- else:
- self.env.D8_CLASSPATH = '--classpath' + os.pathsep.join(self.env.CLASSPATH) + os.pathsep # old classpath without android.jar for d8
- for x in self.tasks:
- x.env.CLASSPATH = self.env.CLASSPATH_ANDROID + x.env.CLASSPATH
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 00000000..0f0c0589
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,17 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "Xash3D FWGS"
+include(":app")
diff --git a/waf b/waf
deleted file mode 100755
index 53213cb6..00000000
--- a/waf
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env python
-# encoding: latin-1
-# Thomas Nagy, 2005-2018
-#
-"""
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-"""
-
-import os, sys, inspect
-
-VERSION="2.0.18"
-REVISION="ff338576c6abcf8ea755ffa7e678f790"
-GIT="6539bd1ad3e285b124c02859ee5862dbd80704b7"
-INSTALL=''
-C1='#['
-C2='#E'
-C3='#2'
-cwd = os.getcwd()
-join = os.path.join
-
-
-WAF='waf'
-def b(x):
- return x
-if sys.hexversion>0x300000f:
- WAF='waf3'
- def b(x):
- return x.encode()
-
-def err(m):
- print(('\033[91mError: %s\033[0m' % m))
- sys.exit(1)
-
-def unpack_wafdir(dir, src):
- f = open(src,'rb')
- c = 'corrupt archive (%d)'
- while 1:
- line = f.readline()
- if not line: err('run waf-light from a folder containing waflib')
- if line == b('#==>\n'):
- txt = f.readline()
- if not txt: err(c % 1)
- if f.readline() != b('#<==\n'): err(c % 2)
- break
- if not txt: err(c % 3)
- txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00'))
-
- import shutil, tarfile
- try: shutil.rmtree(dir)
- except OSError: pass
- try:
- for x in ('Tools', 'extras'):
- os.makedirs(join(dir, 'waflib', x))
- except OSError:
- err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir)
-
- os.chdir(dir)
- tmp = 't.bz2'
- t = open(tmp,'wb')
- try: t.write(txt)
- finally: t.close()
-
- try:
- t = tarfile.open(tmp)
- except:
- try:
- os.system('bunzip2 t.bz2')
- t = tarfile.open('t')
- tmp = 't'
- except:
- os.chdir(cwd)
- try: shutil.rmtree(dir)
- except OSError: pass
- err("Waf cannot be unpacked, check that bzip2 support is present")
-
- try:
- for x in t: t.extract(x)
- finally:
- t.close()
-
- for x in ('Tools', 'extras'):
- os.chmod(join('waflib',x), 493)
-
- if sys.hexversion<0x300000f:
- sys.path = [join(dir, 'waflib')] + sys.path
- import fixpy2
- fixpy2.fixdir(dir)
-
- os.remove(tmp)
- os.chdir(cwd)
-
- try: dir = unicode(dir, 'mbcs')
- except: pass
- try:
- from ctypes import windll
- windll.kernel32.SetFileAttributesW(dir, 2)
- except:
- pass
-
-def test(dir):
- try:
- os.stat(join(dir, 'waflib'))
- return os.path.abspath(dir)
- except OSError:
- pass
-
-def find_lib():
- src = os.path.abspath(inspect.getfile(inspect.getmodule(err)))
- base, name = os.path.split(src)
-
- #devs use $WAFDIR
- w=test(os.environ.get('WAFDIR', ''))
- if w: return w
-
- #waf-light
- if name.endswith('waf-light'):
- w = test(base)
- if w: return w
- for dir in sys.path:
- if test(dir):
- return dir
- err('waf-light requires waflib -> export WAFDIR=/folder')
-
- dirname = '%s-%s-%s' % (WAF, VERSION, REVISION)
- for i in (INSTALL,'/usr','/usr/local','/opt'):
- w = test(i + '/lib/' + dirname)
- if w: return w
-
- #waf-local
- dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname)
- w = test(dir)
- if w: return w
-
- #unpack
- unpack_wafdir(dir, src)
- return dir
-
-wafdir = find_lib()
-sys.path.insert(0, wafdir)
-
-if __name__ == '__main__':
- sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'scripts', 'waifulib'))
- from waflib import Scripting
- Scripting.waf_entry_point(cwd, VERSION, wafdir)
-
-#==>
-#BZh91AY&SY܋HP},Ƭ#200ebV{#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2Q{=hMOrw4fgTO/h]ZVO [X4>|lM<{T:of{]@b 7ozꮀg|9}9绽ës[Y#2}ww^n|G{ET}a{ok]ө{d3n&&ڷ4>Cvns.۷|#f6uѧ_ns;nNrvGu^7ιOlO{p4ne,=^^w6.wc)#2@&HQ#[!]`3n_E/sz)]75dvZ:uu]ΪlVix#2#2wQ#2*{sX{َ)آG9Ǜqb}g]Aڙnt5zz}y#2$zanfucjsvpz0:}=d6^}gO[ٞnv͆Cg|]9=s^y_dمl#E(V.Oz6[@8gK˦4*}ڸﻟ}#2;tݺZ#E*p6{]#[=m^3N7빰租UZrPzt==4't݈RvθwԞ9]{|#2ac@DZ|4#2@ #2 #2#24D#2FOM@zCM4PjzS@ !A2 CS&G&&1hh#2#2#2#2#2#2H 44ЙG钣4iiOQ#[im=h#2#2#2#2#2#2$JHjijOM50 SLSOP4iF=@#2#2#2#2#2$ #2#2#A0@h#E5=<@dA24MDA#2 2dȧ2hTbSeOS4#2#2#2#2#2rmwJGusmQWwkh̓>:HSTjʳ=[j6#X/|,gjʋ /|>s9Mc)j%ZGi#[eے]ukoxۻkƹm+~<NjL$8Ի˼đ.V8J*pzsJ(WDq$gO&-fJ+UvvL1Եoj7+\b" 4PI(C,"EtaaȀ#-HR=R`ALU1-*Z5E^ݵw#E#[ H$`YLZ 4Ril F %lLʄK#2J)maeKd5A0#Efɦ"b6HIQCiEE-Q$K+) IAe6H`1e3H6h&I-"f#%aiec)MM-Z*3X2 &6KI55R3d-&dHЕRe&34XFȖ6CP44I((X2#45)(!A"$,@#$!X!fhd"$aLMj231"JEej1ƉYHdbM RdSL%&M#E1"5%Fh3#[Q$D̒m$$`I؉1M)mIBLeahII"KIE$DIB)ɂ("aIIc3I)5eI&($BZSd LleE"̒("b&ZQ$#JPlŋdLM&ɋER#Sd$fFhBIRKJ2m!)*e&1%K1F,L&H#[(јLPƠ#)Li#LPF2fQMc#["a#Kf,)*6iEF$$cc54Lcb4͓3%Da+#$l54"`QCSF#E51F#R2SDHlɑJeI#[X,LI&4"E#E#`LF0LiD#EIJ1fCfD%)(&jiebKI$# 6jJD2YeRXijSJM3ZPД̤l`LhҘ0̙kh2LH)&djSl#[YRiBYRmL-1 b&)J"f&lXk7vf)Qda*iZm6Dm464ڕQeS(͢Y,mRAid#E0QjKTaFf2YM*HF3[%hiE&D-l&L6eZEEM"TdU6i*aMMfUQbȍledJe6UEM2ƪF,)QcDU!j06TRmQXbKdѵ[(,Q4M$m-حF-Q4f4J)FB$Ҵڈ4m15RE[TQd&S5-d&ĄJZF,ԫ*RSe53eL6U,6[I$Yaaͤ-a 0Ih$hbRDTBTb2Ii+3@j+$E4QR16XSe hYd2E1)K#[EM2BE#6I#&)DąhĐdŢ,F#E E$Df4Ym2,i1f)Bj-"3j1F̤35"VKI,(%#[2Z(#[)Ě4e6e%*f&H,dD1٭*5)i5Dj@%16$*L$&k LTRji,m0DJ2Zdk"4г1)a1(*M#b5MFl%EFUa$i$Q&6#EeBD*2$JmƴmDMQAXm&0MiDj5EF4QF"ْZ"1b1b2VRUř"ɤfP(3%`Ģ&m5V#E25JS4+E&KYRJR1jI! ldQY$1d5!3!j4m1R[$Z!M%54mI66LQFKPd+,Z+DV6i-R hLdfFcMHFl+F,mdeЕmDTQ$mQLiQmE1f&3Mhm4lJԢT#4#[ZP4hD6KPk2ԕdڔISLV2cbmU*)*Q`!(ئ5L(cl[b5mֲT[)dSSl&4eDhIEPjJ3eb4 TF$)&DmIZ"|ܟWYiq,0閭J2,?Їye:b.!4%X(l0fD6O,:(|15žl{L*P <#[lZ/u\(4ZQB^?~YFrܝ5gjhM_JpfRfV:cFםwЇΜs_ٻ['?I,xڹQ#[X'mQgFѡ>IXBS#[f' e;6j4^.5E,DqKS\.YUPN0UIYC"Ҫ`K謼кTfõ&EcDETP1PXqNthxEڹ`E,8+u\,bźoM&Ω`h V>;|0zQ#EPJ^XNacXE`(#l*ڐ%;b"h/i^\-m"RklZ5#[4j袖(DAgHFcxûccQRmIh%.{/>O=Kd]+8uX"1Y$A?[vPاv|{RJ罗"SZ`8i(bi$2݁ʎU ﺖ"Vwլ*Х5zY`ńQ )#E-6iU%;N%]MZMj˷|!#[#[@2(YU"N#[(~X\:!(zÈ:*}I+U"t##E.*pBUOSe(+;zÉH7͇T ]'QҡSn ?>xTC9k,5ӳ5rã,2ɞ6\@PRffF~Ox4P^bڼ4T_W:K<<136$X]:Qj3tsM̼1FJ2P3T͒lYۭlτ&1mHmY~9n!BiP]~kfz/\TDN5auljx6XsY(}SC./̍~:HTႰԦ;'xo^֫WF&p#ekrab=!9n;Ez[{6y9Ժ5$7CwJH1֛@83F?,bwW)DJ* Y!(.7'B4ߗ#[{AqkFoH|Cka!Cƶѯ(`q6>uXƬcȶ_f~pg0֧mz#!Mź_}Wg'VB] lP:`_cB#[:WrݟCqHf\)n_BRI&|o[OxkhE_c[y'FH(56/зm8{V=f{1A}[2H?ãw .GsHaުL/ƺ(?5L`.A-kc [avTS.A8Uf5ώY:6? Jj+{Uy6dY?s`ꚎO*ms%ltӿ;EEqQQx[1H4龜-}[1GO7~\f4ES`i=غ4x2/fH?#2rO&r2Om}P&dFiv>&Z:wæp#b)Lv_4$m;E)UN|x;./z-ӍiDQQe5a-FC#E((ꝚV!ԙ/g$&lwkV*s"1A>kAVG梳m/;<{E%#[Gq-2"#@Qh ̊5}5W65[5fC-88;J!jۥklX8woȲ31ҡ%MN0kP0Ő:!tx1KR] :YQ/"Qn5 Eu6쒈msNM";YFh5sr dkr)WZ|PvX@Hהmomգ|K>rC{x2.+6o~U0$ݻKlۿ,(~^]$W9(Xhʇ{ԇV7VE8mȥսkWYK\Z7IIw,P֜9tC,b`qǟ*Kewv*eUnǿ鮬NpsfJ+Z=ҸSWrFs1^n< փ"kh6OMdGU.Kd0>!;+P)˯]#[12Fw.3k1sUQD́ÿAr>~eho3ߪ0p$Cc̨~8Pj'5":X@ @`[RsxE.::/>ƬF֘4s>wWxzؒ|%I$&GCdՐ2O{c>)&Bψ֓x#2 ѹR#2H@m}>#E.V}pمtڂY:zq&~w~UFF`H_g^&f(ҧտ"̲cEMvv(M$Q֙{h9=m/XGVέVgWT$3Yc0k;c#NMZSmwj8ީ7OZ!w|R貎]^(5$@5*(E+dX(#[b)!,gn#[W݀ߜES0lz)~ht=WQtLs|v>V1jѡkL#Wq*3>۵M.xflr Kfm"go,br?\J1k~KV_%S}LLa˵$8}J>8 $.9. /q])qe\G_7C8t㰭q~:>xc@KMFMƥPxV\sK*ҸX#E#ESφj:wWj4.w|Sm,8qhU ;;ﴒoh-6Z\.UrMp#[TJm=2ӺpS&q@vl3iP%!˿fHt _]jUCQ\O5ϩ4z ~(w,3)=o~3&\_kĥR "#2,mr4U|){0>y~6[FMbv\>\ZE#E#Hrٳ;g+[FW}]AO4. /LFncDt6yg;bf(jlzwܾ;q+2Us:Qb:JسVUUJb)aBY|ZJ ?j;APz.#2!gGkRQX(SE D`|ѝs6@j@DQwyLmã>,Wω$f76.ʣ#2ƁIuc1@M㮢pX#[} o䣦p͚Dx4#'Jr'duvZ9_1X9^ONޞ0: wGۆ'b4)v-^uktպ/ zO}}K/8~O7]eZ0/p~`_}ɬoWLvj,sn=fO8L]VrPןD%Sm@drYz-V)@)DȌߚ#Jg\-#2CbC`,9ȯuR@y*Vԯt:luUL8.@V۲ttKBF%a-?䯒#HNr+M<<80p !GgBF0졐rbu0(m52Jk?OsySo҂ƸI]D$I{#>=+r˪`#EuGQlyGU)PK6cXt4-H%ꐳɷMѯt?w&W0'UQP0wڃZyNso#FCW(LoBuRB-M4D #E}+Y ւ"#2#[;?~#2i^kdBYxouwy%3喅G*v30Oz}ŵ۳of;#[7kߧ,_][ClmBL0PD*yRJ(Ȣ$03a#2c.ӠusD#ma#Ed|pYv`P[l#E5GsJ>u "vK0#E~~ik"^/Ƶ 61A!0t\lK1:m+WP\_?\#)1?<S$#EQWd#;:~>N\e;v:Pc#ECKT^FHLv?9\ѵ/P#2KuFq_=ϯcHl:\3pO~l/#~>|#Eh3sGԻ3;%_#:Cg1?el.Mm8*Th͊x'/H mv&FfzFߎf_.CEXȑuq^%^Njjl@TƾG-6/IN3ŖO?` X#vf1-!Z\X.W?E9>F;9vmE[#[*+#E!#EuA'^nd#E4VQmY֓axy4FfbUPV4k%"2#L|`"b9}#[8aL^3g&g1:0חe=q(\*#ET,43U]'*L<#ӡ=abCIJz#La:.X;3;T˝,PU[ה|uڙZ{,..H9ea@t̳yj\Q~@~̈́#2$Z|5aavxmESaLc-c#Bg;:ܤ$XѩN^eCCGқ3ѽ2I[Wb)a}q'MOO^mkx9DIN@<~ql&-d˃ߎ,02+M҂nhJHg{Sm]z潆h#0oɓ#EfL';~k mhJz3,PA#0N[5UdK-RzNaɝQ_Hb4"zVwc~ED&`%aYGGC7vWQj5E5nJh#Eԫ,abHUy>oK3Ȱ:tԄ_<~#[=F"%4LFZtU])6^Muc/gFPۉaj=7)8oq%/>LcF#E0TztJ,]PA#%VDh\༄&/ө1$}kp/U`_PO#2,*b#EsRdnA{oPў8+vVl5 eb(_spKclh/uuXF2D*H MFŕf1)[XS R1SQ1CJ.W3#[XcAvA\tyAtȷ_LlxˋBLF1#[,"vNӸv5Q]YyݧH)1Iר@wis#nrsWx<^8wTvgkM]e$=OYŵ"`,j%|HU{[m.hQgjTa{ˆ@?:X0Ʊm(,[UJ[hQx-@Be/KoMx#EץI]k5#2f"͘=F<1K|abe7$,F2zuay_2*Pz1&S%EYbњЭ֨Cdn"gOM槽^j1}1;|v9Dnjo+Ӊ,8.ln#5H6hLu .XȆ77ptb#[ēY(C.p949BöB(y1/qP3y 4|Y^w=)HH╎\ĵdW4s7Hew|#Eӯm5.+ۑѺɷՅ>%`#tfHCacb@RxΤ-T,hAyӡeCD#21\!iyHsml#2Oqs#Eyb#2+6y6(Kv.wu1#FwnۖJʿut|ÿM4usTy!PXʅUPe"*TDkۡ4EeH+QU_WW|^]GxkDO.#EKJfT1D6x#,ofLcˇ5/YccB.8P)"S"o*$#[x!1Bu:#E[q̋6fJ;b7em|w!?gܕ'y#Ӵ1JևNw+h9)i5Y=]^u?כHLBW9ӟ3zfb/V18`$DfeZ`an:&eC!R;[#E֘Ι 4ͺB#[2J`@D(mzcjߪj4,Mh&o6+٢.c+cuR'RS-*B `<^=iw$ pjdy Op,@b ILռ/oׇXc>:3!NA.sy/s?}qf|S#2{=>qd!9ż\4#[?/s([%"6}sgyzwQϽ9ؓKQ$,S#EO<1O#2K#[En˹=ッm(#eE̩NxS6Ν>w~p./%jA"ҽknW)hWm}l1 hE sB/r[GS+1Piʡ:.Sp;S)saWpmZI$#/^#E|][U,_<{p샣,@w-tqg?&6]^#[R';!~Xy>[4^ ;!p#j]ulpB<Oǚg[)t]$T'f(=ЙoU SQejRD4Y1@EiuH4|d_՟w(2a#[W+*}`E^YM_PԵd/lzₒ;?/ڲI?̂kgi,<=_W{z~J>^<}a~8:{$jl?,}B"¡EvLڒɢL@fʖ%8MlUEɪSDHnT}aH"c7:i|($6I=?wo7W]kD&)0(Cˈ喃%4L1(p}wsFh"uM\C>R7˽~AY wP>;ÁOX(ۂ05k9knmO?PDx2**He[jr#[$}LV%R뎌i5Ͱ+N ;zۑZ?vڒʩ[m4ƝKsRƏ]ZK`Jԛ]Kۿ⏛&h(U=e\N$MSqzCums}ullH`e7I!U#EchKQXXJ}Mrx2=(T(`riaEE ׳#[2Zfd9xem$1c>~&*{Q>#["CalEa P#[A #[DRhm#[^Ϛ_`luy~oo֬GwQK4q%?OS\mzXb vo;Yii}X)Uǥ;HO没P?PlN 8G^UJ` 4!NҚ4}̃DM]rqI}i`P~Nׄ4MO?|a =SG'ѿƊ4 fFCY26QEt_]wvx93>"9MMG*S1JXTAUbzs(6oĒP<Ԡ:"w(dyX]fMSSּxwX>op$I7\k=_CHeܡXflzA!L#[dP>acQF4bA@mjEPM_qV6 \&8K㻠}θ=ޮ}?]~}'qX2?Yz<gؖ|~m<ʣzFN_FbѺzOܳ#rw^%w|~Kħpn>Yݘ=5~[ڥ|wI';4y۷7;vlZ>o)8;юs;7\£vN~>:/>C Z6Q1Bb\b#EysUsO9QuIܞ<Î=nn;"^Vl廑ۯ;C¡1ds_1vl7>Rdxz#2zwXOg"anۻz#B| vbsGR g/}ǭf#MwcZHh12+gCһTv}}gha?gtفv#Ef>#EF?H˲O[߁wp"TF9NMSRVtN_{Q;JV8.o}=UA<8O~r:_3s#2m#2is$;;y?+ɒGv4QJ%Ъf壈rv$\=3$!Kܩ:-@DCM#E{dm:^Wry|W65ܗnF;Iױ͇E'c!IOdb.}]99+ϖRw~oM@77Iz^ÄyؒU?٥GY*bGuTA쒞Q|qz#2去cY|u~|/#`ydOZ,̹,0!1#EAȑFdAJbqx&(vh1 UiAQQ:Si68kMjD +HR#[kd0!XjlYYc'Ý;V&bTMFf&#ohW}*2N?wK-~;Yhfq[w]ZO!uN#[&$/[^0D[%v?Mw|ǁ#cF6,#f¾僻>3#2#2P,[2FfFDa`֗}IAb¥*26B40TUPT!( #2SݽuS;%v?+ֆчh.8`VU 8xja2s5;/sG͕뮭_N/ *>h~:~A)v~Lnk>|? lw[~oA\We,0OdsP96GC^;a $av6?oٳNWyF Z[p9Vӧ)慛se|,$uwr8g]'5_WE=X*kR.~~~=|&r&s;- q2I|AEnӁ"M6Vz" U´[J-B:ゔ,JhQ< 1#EV4M QFT%TH#֡SӑDA6(VNiB@xU-pLi@e^0b:h-2TQee+4"dì7VbaV'vkj=J༓:tcoSwsEE]'5c""'No"U87-V-YipuKzs``K[X aĐ\S|1#>\R8@x۬P5о)s.TK2[֣F[@&$byw !NCCהj#8;q/vKzwI$"PG(cTRvRTHW43PiTR̦H\S]y$$%ׯOy9#3#2DF>a(1*2#ER/\mFHG#[5 .ʹKі)YQK||{_0C*ww|ɠ ,``g\Xz2"cE뢴#[MɆ##D1TD|$T\P\+c0#ES릘7}UqƠՑAF4#NfhUw-F&QZ#2!{lDbk*FcTZ2}- r9p()Ne0#Ej5bLjf$dg9[bZSo֙\3+e-c2l?l(Ո#[&i.6B41@rƢln#N\ &e[C`2`.Bl˶1G2Q/-0wccWPmhǕF ;.D>t:wf<F`liZm~Gۮ/$cMPv~<_mw,QI[bT<(!c,ƛ y_ge703oPT+s 4۾|]Hi}':;nm~l) #[vcљ#2f F,XZUT4~c5DnGHҌiO|Y%ө Hȑ#u4CߪƫzV745LrHwq#Ela#[2T(qPGcE{/F04RhDŀL03+kB!S/]M$<(-,H`~;?Ayqz|iF0EC78r-1t[풄[v7ec˙`!I`8#EБWZa AoTe'hWEՐfRr7x;G#ccGR4yUE#Pm]B#EԈmଁk;o3~`isZÂQ",S*Ip#E#Zc_H!#2PuD}N[UYo"M\шThGbG|5w.IFXKL4'dDօ#h&>h4Bb8ijF5Gs}M`rBy[`n0tE&Y#j+20f%﹨[=U&240O04OK"vs5McL>y9?_VdL-ۻzA!l?"{ְhz=F)]mᶫƀO|`/#[!-ҳf&_C5-ƫ:}llc.";nfЅUL"g87#E=W#אM@of{7:XĐ;"Q@uBƮvR()9f=cqڭtV=,9)69j#E)g#[5xoPNZ"-Dƴd"3SDP87Iq*#2LylOTf՝4#EݘF<ƨÆbnd|f3q2!Cpc(437ܦ^nюѭn:My5.ߗ8|2;I'5$%MfACx幻S8\A%g̙̈!9ʍ(|7#Et>rN\5#[#GV]Wk"wT%QvtwDydw#[6#[9c\&2]qqh5#EٌHmE|HX뫣NLyX-jv=.Xda9ɍhTr3}\sJ) n%h`XVC69vdr Z@"6f19X؞}Ι8g5j:U cZN~K1IO:ۢ+JaX2E#[KЖSl#Q)SU#E%2$sw(2~T|?OUNjqa197=|(S!>vZp"6S(kI6QnB@aNuc9'^3$ޥtb^l#[Dyǫ `M06:U+3xPqEц=]z5{_\#E)L#[?WZUyhz{zi74HFM{#"/ҭh܇s#g43bJKӭAE9McVrp5ĝF1̪]p{ uz+^]y1 k6j{\~?Oe>Z8Z`ޯ-u'4DEr@EK}j'zKFrq+mlO622‹iƴ$p#2 mHfνnvP| @xs#2%Wa>yO/ڷe{1#[3b['(d1#[{ZNp牢.Wk#2aly9sd?A^68k:.v`=CwCɪW9*=d*?u0jKD£';O-d'4jN<ws/5|#[|x:THxP^ఖ0䌧aW9v0twۗ/$i9~(*ꔛ/#EL\M1GD>5U5~(#Eofڥ^'躮znZ+ѺBmWfεSն|#[V!~E]7:_}tGIRN4e2E'8sl鈐xnMU*(J 'CewQጢrd#'126ۦ6\#2ޣ;eGu}Ӽ%$/6'Ah^#[Eb薆}h]yݩQmFPid/Qȡ]jR6j ^I됔Щ"uWppSD#E5,<&i}lGU$i4-yb o-8O"F,tvPt!'ACV>Z| BӕϤH^16KpQC=ϚVqLWo٬5'JuuK[ÍR]T(Fk4˔Jl,U'uy9ʓVElj#EB#ֶLWvZ+W.0۩GMhdMqQ綂Q-p[c1TeLߟ[B&TFYC^}[ɞ`ĐtkMBYdӚۚ-Y{S>LkEx9ٽZwɆ}ҝE{e8s!t7EMmH[N-j.4>pI0ʋѩ]CԓIWf!Pzʧ(XyXUw9ûQ[[[t9~m[~p(4ID>_!#2tO6#[#KcEFB#izs$h^0K6b誌WSgu#"O<},mPfX|fNԭwj*a";"mu,wL3tG(pp{פ3 l-@6-=.r*e2zxID?OSbvK'~<9k#E6Y?Uƻ2wCNDЧ+*#%[noo4$:m?Q7歹`Ȣ#Ew"j#2%HZ`e;8L}(}iĮYyx 3c+Atj{#EƷ1x/g0*gb`eo`،CbqYL\G~$BM:<>Z`,FhZ?W5*:eqϿQTy?3صnZp*4[h!ZlUJԹYU}U}y)`nY+rt*5D. Ki%eEA#[`VfC+DrNOUsI햼E#E!V6`A7.Y4Ubra1h(?]RAcIg`8ev#E8qϴ:s~%Ӗ6n3ՅXbU,T_[7(ZK&f]prZAHR3@gK'ܜ9X˿Mo#EQ/?NwOQ]8`oW;dz,iX,5LP#E]c\fO2BKAĆa#2^_7:OmZ0L8C8nv]%Y]@ťɺa+Gn)|lWXEQLkBV-pdJRS*;R)%{}}lkm9Ɲ`_z5Sa2y.dVFVKWE~BI1:csg{V.B-ɚ9!8=cMڱ/UؒaV\˷'ĝ|2yfcގ(6G]Ɏ6Ֆi<,6gk;Amh{\N/ͥg\WES|w[-jsT#E84ipŰ~y+9~[8R:/WcȺd<2:&eV>HmZ4´'tiJ#`>Ym|,|[&DX)XGjB<V AU`4i$)<ey¶W:'=,p.jZZ0p(Bz\`̝>zH_P9m]`˹o0cBU2:Ux7 C-nlXU=u^,[:b&ʍg=Xv|?3umS;6KnnQV|4'hhibKU#[GB0IIҶ:,%F#[:ZbOqז8EE+cmHE_7n7+3o9fnI=wl:GPg5pc{ ^$&o#}ELw3u >K.PM;4Z,a}5V#6loL.\0"!s~0.`t{M'oK:#=ϋHZPu%Bu0#E^-~01Xӥykg!uMg(TE#[[t4ÍU VD-+63Hm4/}.}>ӍtT3lMi)tAHs盳YhKuš#2Bq6Osq趿ϦzJmJ8c#2ppf4c`6LNeXSncy>g'`S:Ol&Nf$՜;^qc~'}v)`PϒӪUOKue]uЗ2;wp~`_=eXaӡt9PPI#[J(6ϡ1eA?^j*_v[P2k,<u AUp4we%ar#ZH#}/ikniT鉖p|o$_L^tCn=N1y㏏n"C̿.>߄C4F8SR8xxq3CR?{ %EgYL?f0/VM]x}ia*M_9YIHN0wKsUMsɕJMEFc?V,R:bm!4}/k>g#EXUxKKM)U;,=KxSine!,8 Ĭ vCc=9)i*jt1\mB+J0S:Ѵbv0vje2@p!#2CO 2)@Ġ}y¸w[UϷ6EBhP?pnC#2\70T_0,bVcv}9F倁PG&lx~#[;*9UkKicj%/0h>n Q!Nft3کR^"[k\d8Zn8/'SRȎ3m5+~k#[7ӂZg*&|]D*_ ۚfa[,8TGt>%W|sb}^%u<#O8{sSժp z^!R<#E9'7<GI:־3k v(Aج-MOw6^hJy`Wc,Ήyp06y\$aXթ6DrgxL7 qXw`XmeI a}Q\ʤ^FY@a19łyLƄ2z(0Wtg9ѣcn'8%x.kkvDGT tF*h5MT_=*N#$ZBAO@dJ?-<ѵ% 4h`EV{#2xtruǶIX:YEMn\kuզ_grXmb)T%mϩD絥`1MI?rd,c;#AD#ihZQ/;#2ŏFMR6۸ޏy#[!W י%=%%tX!5fYIuPM왆9۾R';ci!"`zXB?3SIGxgb|hO~IHYM_U+7M۵ъWMhۿlohL=0#˪M3yOtvs)#u:NJc+Nm=}\vLEYs&Sc@"9H#Et:v>/}L3X폟CNgcgӒ#>1ipNW{{-vN}R%}5X|f8:G>qrc#䇷;(M2:P[T'ŭSdKБw~?k/\zt>\(шq49-^3#A9#Ean23ϽV2ro)R5q&á,QeӤJ7r*JL>7|gBctnc :jI))i'8012#2AOwoXn#) GwiMūrߣT QP:3c>ˇVIUOTΛ#2:#2@/EޚpVAl=(ﳗVWރfX]飥PQ snQKr5k>E8vx C[G]-',**uT4Z-tFG}sSnARySUTU9;f8G]t{t:*a1:եO;WDҭ$2S7٢.K6wZu2h.&mJsھuLL#EުJnp{N;4f27_v͍ߧx 9zTe+WBr'Ҋ̎.V$C|C |?d/}B?MC#[Ke=Gf~Ņ܆~L˻br|1Q+L$Uz1btҩ[߶w-- K~e~jKdŶAA]Ƽ3>Ȯ#E}QTxL >4XEwd$c88sa5瞹&y?emKnUH ( &Sal\){b7_5`kaQ5|&j-h)挏6NϪI g_o2mc ,XhHUUջ>(qHTi.Jz'"cHFfةk`yݽEpgH:By3Xv/aY,z1#[#[vÕ]V@[tAF]y>#ET ltTؒΔֻC."DJ0#plD'Aٺ( Μ{+"~QH.RhE8_M){Ԛ=ƵB|Am W3q*Ѓ|zj!rZ!P[6cK_#E3K$sǯRFciVy@FպЋ7Kkj8`r'IwITssE '6)B_aNLFT5U"Q({d0, x`KF/I{=ZPƕZD;I^A}ߐanQsLo2kmdUq#[XzeYUM7;1nQy_l)A+w̩H~DvϦ;4Zd8c~=PgpE1tӦ/RwtM-Sl|HZF0v4/d#EH`62юgWs$|v/t9:"θZuQz:wjUSc$"@Ȅ$:sCHev4>#2Vª#Eܝ/(d2f8x7Ƀ9؇$6gGRe|h2C"5#^f#%3-I?wB2tC8&WC`(-3M74O>w5MR2AT&UPBJ^3;wF)]#]ufw5XmnKB\@p`؋G$(!=E,F>F,cײlvV~+ ՆஹAD0NSu7s8 ^9Ȳ䥺#A(Ԛ"ɘm pALÝdťJo4BNt@oUcE*[Amp}QprP#j/0\%K]q(*ޯ}v"_4dRRZ"B_Њp-/W2 ~9o!ts!Nm4L_f4嫴LN,XZRzc}K~UӼD/mr!xBq;8]c5ѽ= L=n@6Ƙs/4I;ZR'!ep[r EC͝aE4S@Q;U]{|fy_Gu!N*R#[=pbͅ*D=34V~Δd"Up5^ 7`OomFS6<"4ãVB=PՇg(h'ǎ8{}EXHL#ַ.he,\Qv-Fᓇ9wMD5V\I@d(]o)b9Ȼ`fttz"S>{yg@3T{䛷J|L*|poƚ0VVneh#E#2Sv f˵FWgm3Bn@YIF=-l4(ۦ51t#E*0|xOOrہ** =tBFf?΄&P>Ow#2#[zO1R/x0#2I=;"#2{/).-w5W9x#[㞩N.lJGץ kEē\j$ymtڷK>>S-Na~-UM$|s8hw]#E?q!u4CܨوVT2#m#D%|U4ު0df=={Ha2^pK2pi-#[$eAJ?ә'Ƥ=v̯\rʘ)|nyN'lt;8=ӻM2Mi_w6xl7fY&`.}ٞlϟ깡Ab'Ļ#[.Yr#[{]@؇ۓ̬mUsBy#[Cݷ/ICRxi@te-AQuCZ"a`#2;;OѶ[Z3K#2V"һa`bnK*Y D[&";#[KRA.7qbH(RP&3l!pFPĺkKnxXf[,(İl#[cfJJZ#E#[K5Pk D3#[:=WT#E۱Õ#E%a(*Ń#269|#[o}#[#[M5V.)qƣ#ER: ^9x#E,dΈQ .w$QN}(}Vui ]#[}@sbŗgModžr#2I#E4/JБɽ4;(Ka7M46&R]-1A8oE3FzvA9#Ir59gsY(vr{*~=,W$2UFP?㾭7iz*8#E6lT3M#E4:SINd8"a.5dGV#E@Wr͒S8:h/0+\ӺꩈL闘B=w=(-i5~|fнlJQ!#[ŸıXhɢbU0i)TZfiLXo#.J**,ERwr7mϋrwFYπl#EиN`Cm2$ T )(l՝J),=qثzwO߳]Sx^7c '7ʆ{t)l`:0o '"RTNh43n2QǸ;k @CiBPz-Pwk :(gMqQCuMל}*M5p9\ܩ+{Ɛ"vϞ4];&2s:fP?Ѯn#F`M \DO4|Zё8(wD`jVKNKCەkZk^5IZUtY~F9f#E F#[+(.Zb(ͲĹ5x$R'e5/zl2 zM_>g sä!5wa}nVU,twVMzf%d(Zaĵ>RS)Ҥmٕb[_-xU&}EG9xu٘djzeE;*>d2'Aɦ#E=P\jRdF[I)-{#[`'_]Pvfۊ۞\tŰè$Ė%)lmP;o[>7j0AZҍ.톖 lgdICX#29@%:ɐ`TEXRMFLDqђ̔l!^9(5K V֧V}2(y(Vnle'RoþyO"IS>oɋ1J:eB#E#2,|>nUUOw=WHtAN-<@ӠmA҄ҹ:*gV$-y}o\z0P*nxQ(PUzVU5)Wuz&WwJIb*ERTYeΪ8#Ehl%!%]|a6[rNA}ۻo(!gFО^L$H2P. rKq7yGjGP';KPGG~ͽp&l;@ԅP1Ie$d1M }#2za.zJ KٙCkJk+f7wc'Ja33$s#E#E#[Npg!)mqC*gsN.1#E#E.x#[a}'suψe:d9&A`((zZLI߱er+ăIPm4yxY*r#uM5ITwߞ|J;ف0zqI^70=2-bńhi>Iӑ6dDItF˥C(tLUc!T+(L$_"=IzPQн5G)ܳF#EQ1vj-,vNlAK0iأ%v0@̬wU0'(wI CF9gޜc#1ʊ8AA,#"8IJ;Yg#E$86uxqNuWNOur!#E$F$(dф06Q18:Mio\h|QSc5'{#[6_o(ΔU8.$ (jځuYRfj|4Sh;4ֶxh[ѻu~>p}LҀ#[I7ӳ;u5#EzB|QLq:?qa$};u;nU2*J ߚ& V h%n>y*Q9~#E߳ Y 8q큐:,e{S9fGdLO:eV u#[O'J=y#E18v:>f)*so[#O}oQc#DdRco|&#[ ncrBd7L!JY]'_'#27yg-dD[:~RT0VRU*+LwwV7VdD߾OHO?ν̄D ]#2=_|?_0o0}):ٻkk9[&۟R=;5[G-f=c_0!tuX Egݦ} /]~v[֊\K5k0̧?O}ʽnmR0 M)^b^tݩMk7D>(}U"4'?~_Smj*8Kq9$5YHL$:Zr~3طknJŨ+ם !A6p}A,("m;=o_X%n*Zb8~RD#CܢLs!/:"tG]#2JfvmD+#E4AsQ.m;,noϸ'".햍]-9k{5>@ #[%$DNhnal:+z&&mPSh* %+u}$|_#[03!Bs>Mx uQeJRtOoONA$$b2%^u[bx.{˺w#[3WiĔD&JiOyfEznxC~ϰ(g4ԟԜ1KO*#[,Y5gRUZUrfɁORNv;8gΘa4fHǏ#[m*( sK:tt5<CV Q6"N|~Bjb&;+`4LmS(]OUڹmYb3=3+Źͽ)O2#2xvt:sP'#EBs^x|E ^?)>BX"_0?˨!Mnh#2#E:M]SzD#E\5;eӴ&ilԚt @76gcG`h(:w!sE{8rS[ctӎ-gp<`o0 ~OGӻ A[oLٶG#g$?zc ?#9MdWHMpx g]q*ͧϥv?R{#2$c<_u,"#EݱBh#2nSoC3ڞ}n]$#E֦?S{@]5Бb#EYۣl#EUV\(I=m֯AR#2Z|~~gd#EoIZ|`T+4C9^TB> aT>,$WvaB:0>P1D:'uF!6F[hdbFcĚY펌;r˞:E5YVyN_1e*CmP#["vJ:MCzQN%,UAD^>0{/3q"_Hv٭5E[ǯ:h%O=cr{i4.~c\C8ѰY\a#2a8q~:i0sm3p%zF"F6#E 7CyT&i;>vD>=Zݝ"V=<#J#ݵWϹ_殪^n$dE['mRRZ\-{ɶ:R(#'~E=Sˍ~x]%൚+vhYHV#0%o"`ś<;wN._D~XX Fes+nwE?/}ߑ?t:uU(wg}lɤFgM>fQ.#.D&υ =V,㚕\Hsܪ*st}yrkvBml%/f6?+Mwz:1g>k]sr(ɉ_f8G|KHMqⳮ:KњVASy#[}|8ۻ_,hiv0%Bz$W%J/3\lGUb_L)P亳l<#[V{#EJ*X)?G>'49u/cqI Qyk߭Qvre?m#E9w=0O'k-r)5fMأZ@q46wfaT0rģ#2XSAfsh]a@O$gƠ0wk/+g}ciYG%~zwc#2C..e40p&4wt E3niP~Py#1_@YKtw[q{#[shŵMG#2o&>0q#E!*Lƽ3Ȁ),#n]c IH2?; LS`8Ep"M2h((nNC"sȶ|gZAZggϖ_c*\?|G_~(lyf#ElaL_z~%E&4DQ~%bP<bwv= BegNR)D/Kyi6\rߋ˳2O}\728zv)#.>OcJ\E/zC#2>wbPa$k'k=ÃD@UΉ;;4I|}U7_:<W]Pp鬋)h U[/ʳZ |0|тv!=O2,,<ӿf݄rz٤%^@yrs xdm6 +ԊQo#[ALC{ jWEw+j!OgP6ok+3)("MRw^~kNN$3.2"jm=10rz9OV-[o&VҺ}u6?H'b;w`f6ُ,rexkBH(J;n|!{Kr"/?^#EߓĎ&F;"j CTunnNzE̲1#2˟oO}_i&~cqӳ%J4mz|߶!(3uu`9ͰjI;l~b?i@RFxΗfWd$>ڡO_nHtp+ETP#EJ#[Hz@zDrր??Κxr{m'_s?Y?GSǝ#[aA,*#[xHR' tp6m#[In1;Ckumrlی[9v.3*\#E?NP1mD/FDA/-wlߵ,r*ǜ<Zګ].H[zԟNSK߸?rL>sD`#[]qX(#2t̴=mʶckFП@qjϾ&~a's\K% )av?/՟/pA!KFu.KA"2j0Bċh({^W.5m9z#2MY`L,Fbݞj]:^W4;N5@A8Z+M4>RČtꜶZ;`r.rH:w(9 :ŵ$9 eZp}z\#22)$<}Ӄ)oMqFe#2z)AY`N|3{"*d{۫o`Ȝr I#1;5M9ˤ谗4.\Q#ERI4#29l'qe;MZ1&#Eb[`+(*N9f.%T8ZI#2T-O#E?D6;B#Bi架x-hvd#EYgH]2Kc"r;6$юx=EOB20H!D$*E*<дҨLw9K5D0!CmT8#X]nX(u.+S)F8XR[[#c7>K1g`z<^4y?:W{+Ae#%q`:嶅嚾-`ݫy/BLP^કQAl/RA|)_R"##[jGHQx+У+\0IϹsS03 ]vTEx9OtGkHc[adR'G>IμLbSNDT:1AhaкPDcYqZFy#[}/ oFS]ރt:NQё:0@+hfk*dx5ч>Kt\;y#E%f3N>8x4\Zܝy37kv|C$oP]l0g(D\^S\Z@аQ=g-b1h/aj{O>WՄQ}ʻyli}_W HYThgM\er;H 8ze-"6#[Zu*HQxy&P`ӬXߔsE-Lj7$f.hs4|slٜ<Np:82*۪~g݇(GhI#)3HrE2}K!b?WCl֥0z(Ɋ0W m+PS1jmIO\#2s#2`fBm_Eo8<-$=>#2AȮL Y9ӓ`Ld<1w{#El iJp4'\V~⼐M`6)`[g`?'@8ξΏaadY?I!JI<\#2@rR$x5yIP7D1;31'o|9;z#@r@y{ڪ/ 2SP1l 1@ \#2g[$ga5X#2r^2}m-\vpLM fi#EWntӛr:Y:K A$$fɫgn%$3j$M1nc][g ]E N)+^(#6#Eox:V9p1bmA]#U4qw_eA/̌[Gp X# :#[m2Z#C1R66^DgYݪՎiam6%6&f8Y|vj(#E-s#EgNDmGs#exnВ]1D?y}ja?B+uq"E=~l\㉖ǪL΄ڴKp3{Y21qAzx79x5Mu*(]k01w|CjΌ\M%x(*6|efK@D)жot( fP.="YlzFպAcYpo:'Y\}.H":W{j*`.*X#EV̡5Zns]?^#fk18G"da#fa~רtӅp-PE8Jd&.$zCFتs7 'a0!Z.@].ry1;bn[z@2b}Kd"4=SG;σV|b/^opy\13g\þW>m`"acg/̅C/7o0OOp<^Z(Rd'>pУ,#2zX"9ٔ(8'#E"5/XGB楪#EürUԬgk9XԜ7#2>g{rl@4^Ցe:Zc<rK:wx,l#2pMkk`uWOG#[5#E7?_W?ʪxp~_ۏ#2YT)Q#2~9#2(@yDr|~@K:zDuyb=gWby:}eAʄ?zAb |j|:Y3Un6b}52zGΫ%Ls'y#EAëmG#EmTYRtc[I6R8Hu@K%!XQ8S]ɮV(BCGCIj TAH\W-RC\>x[ڝ0;KOs~M@eI;6jJo)#ENA㙝瓀0j,ZLHQ$Pak6ໞ+JQ$olHtNKי#r\8[$aiaV}JZ'uY}_J(?n40_h)=:,Ahhk2RI?CƵRfCcv-oPM@'R.'}Q3JY-~1N6dEC 1)Q(>"pzzqVVYfH#Eژ<))Xy=PUW↴VʨI&B*`"w#6\#2MBClH(#O۷8A@<$!DC9=5ME}#EU,F#p:̤>#2)$#E'q8D4U!n~/!,yS$a:Qc@zi"ee'm!Ka^r\tboX%I$xw.Hl7i)>g>:g6=!FA#EV~FPs:LH;53ijlBJ.a/bC{=_hfgG@#E~Kٸ.d@c1MpI?A#eR:?vl|'zi'L ڢͰŦ#[A 6O5W {;J6dbgVOO{J<ѡ#=V>A ixuOJ_UA#[oV_A=Fxյ`0h8mQ25wǨ8l6#E!#E˼n&F7yGC:CEF`BO#Es{H$(i^=JlvONZz7%7["!d95#2"o!Cp52dSt*)S<1a*/da$s2"Цa$ Mʔk!=#2Lˆ[7#EDI?5ޮޮ!o#2+ܳDHd뒓`P{6W5ԛђ/\Lc`ޚcԳw5ݝnan72WYYYjѦee7O5IZ,7r6\JlɲG^I3ukZyYk#8nu:W3:Q$#[ qwJ"7e\D=(%'~0W'*x%hKd07kf9#R>WJ]`_SC3k#1ҝȝ#[ܻk " -Rmt2NvXMxzZU#ALPA+3/|DU&8KѬ)<#fT^2zdkwS-$|+#[*I E0Z qOP72HH#>])$ RP5@RȆ~#[ٳ#2x}Թ#2#2 wWNWĨ_h*s78H0}6E'ʾTn/#2`Kz#[}O=F^Eϙz }?gԚ{m0,h0ȡ"B:kAcˡ7䃞uB,cN@xv: ʧ8ޟ!Н"Hð&S$Xz7y]Ǜih%nK*Z~]a&pk덍k%%/ؾ_v+gH]C=fIJ-W;ӓhnpo#t$U!*B#h??y~-~2o>u) KƇ <>_Cݰ/aMh{Ժf!!dI@76#[Y6,*tIqFoP% 45TiʌdBf^sJ6iR'y WoG`W*Pt}azw!;X_tOxM}0:N8X#2zP;w-G<ӌӺ|SABV#Jq2lDYX&T҉džưbF_D㳱%T$)t$#!#[R#Eۦ&%f-ur6E7>ϓ8PxnłC#[ [l=Iy%%HBOð1plV#Ep9NrC#2s͠U @^"(nEX2@c,Hd!sL!d05CnQ#2BQKYJ9;7ً$8^vgO1x/l/!܅ `שÑ6DIƵEf: #ED/iFȅnM'G@;'v[lsr6ͅ@alfnz=V~-#[%IxT#[(9/XUO>mGHxosg3g-#[&W#k6zم/Atngԅ#[j)(&axI#[(5hqE/@B=TtdQלdA6lR pMXG#[*KHZA_QAuϪN;Rf}uA*~*gp?ĶZ@n#EYqv4ul)h~)TW~vgiXhb0Xd&|DgՎ~b~fXTjT>UX&5ZMrOsoS~g5[ј=?β'D#2,Z[;ڰB8Tr]ؐݲ#25Ij#2uB* cn9k *?hq #,w$i#2Z!=Ԫ_qWnl}XY3BD#_XA^)y'7h^eV`Ph$@l#[ݴ!P=ʱy(b+rY6*Im+iZ܋lbTے&3qiKRv0Z@եfA~EX[?ձ|]*~@7 ^%"Mv+Ɓcѳ#~u䬁H!sh6*Jb~a$)#E?]K]C1B,zHZ{HiZaYԅ`Ɍ@W?uUuj('b{;"p}!C+k?>!,q'p~g#2m0!"+wahV#2h[F$>@t\"Axm+0`]s x=(_#2jut/}%~Du6(_밮_ÚX0~,#[ݵS7eyJwxvʋ%WJahɠ$&iUˆ|(2b(@#EcxQd^y5E2+ҠZ2E6}5+~_~2^hqc~>Cy="f7?U_B,&&7wUHX>uwGO7xآr=Q &~xGك#Ez&bA"Ǻ=H4Eej&9I_;ЊKhڀ(M9T*7\{h=A>Qd҃7!jdSb#2Vʊ76@H erxpBxx@ϱãJ?ɷK#f.Lk** r70Ԗk:o Ͻd=\tGA෨w\wBEˣ\+@^ljnt~ekүQQ!;;)%{9Ўع+[18;ztQtC%KTs4zֈ][^S<@k1QX:6#E:)e b#[7Vl-*m0pί0p5G_-xNp3+@K~ɒĊGIQ&PTχ[`vpзC˰[J>;>#E5Q1#EَvyDp=Wtݯ61֜]˂Gz7Uێy8;rWsm'd:~/10f2ioSٳ|PpM)*QhZPZMztS#<A6("#[s0ߟ[3VNM#2#2 9w嗟{X-s^yJ{b:pW6WufED82"t哻$X'*14gtO9p|?Ui.-$KtbfWLe炓{ vVs#3ufqHI#v-]6Q-9[1{RRv@0(S?C'v>;[My<#EVDbT[ţF(Eozt~'{ٿMqMpsq~>0GѶ!t0bgW=9V,>Teр94:zԉNG=!&*X?{GO,F:Ǖ[5!a0/=e8GnXCq+H5OqdT@8_7y4.2#EUd6fƘ=vIKzCuL\Ӫbe%#q˅%%L4)Ll>NwgsGN-hwYOzj+^JaI#E1$dElnVU<11Wݪs;Dq.6-Ꚃ?dVWOd61A̱E=瘀H 1^#j O7_k!D'8_p^\i榕~_OIM>N}O#[BѓA1KSjV%U#[Q8W3n!'5ZH92-몪`]LOav#E݆Қ#[ĭɘkPjk#[v(#"1'jevꛝ9x$T}Na0l,8k=VT>vI-efbl:!;pnmQUM@ӏsդ<ψnGa#2w=}<'HВCS"S@g,̆VScc`/HAv-RոLަlpf{I.4Uz+_̅XYS $,#vΜ}V!S!ηa-S-bbxg=r7ГgɇC&8zjU*2SMsk"0f0j`,Mb Dj`8p}gH1<{#23vr};gHAfXWy.*vK] wArOJɦd$[ 7(̅#[@ nyF;3BYd\OǪKj~Fb4\3ufgftdݨTh8iElj6\)ZcljJ$Ly&b0,*0ݿvUڷr -WvܙglRƙHbu^iu~Ae}htB>B0kKX߁#[#A,PknAfS;d`;'7Hǎ˝/xr"$Ȥ"jY{7'OMN_)#oX#3Qws y6=a!#[pW caPf1sCxƠڈBuvB;vuAق8EK;5b`?-8DSGPߨ-kɮ!6[\yZTcl霄!D#[Z=WXj^&qmt&&M^Ce`u+#EFP{$,a=i-OLMmه#uw0;K9vhuGsG! "=<&G bu(+79-HFihvpTMn0?7"[#Eo47vMo62#2!.э7qy"(;SV)k83Ȳ-77,xxrʊoR,pr2pxκѳO&sTU#2Y)j4Υ|#[5tM]<#[i5z/MzoU#EbnLZQUDȘB 6Y;r;vܜ#E-'NJ6C >ZJ;:0PyfwyuDђ܃W|N"V2t՟j`!267fd侜1y7mN;#E쪃b*D׃ɧ$qSE((ŌӢBI(Wa#E:.vGϰUԫѡi(;݃ns-UF@*(L8TK jAP*r]XlUV TeE&QP#E#[x%aGVbG{uU'#E#[G(t[K:&v;:ضB'(c{7pMNy|siQTqNmlMcIl۵m,r,a({jz=48(Ҋ"8532s]"z|h$d(#[pJ"K e}L#"|1C#[u}0kqF-FPY8r#[ha}t:*(Gf{%j}̜{G-DZa#EY2F/Tx&Dpv1wp6vAp!$86H*`ј(4]"+΅Em`ejEQ(Jc++'R#(/n<"'E*67]Wu&I`"Qa u)FB2Q.:3q 5hv`ENۓp ,E:]Y9:F+6@fxCyJs"%uaͺz:;<ȹRCb27x9"a[G<#p*0BWU0l~PޕlsE0w ,(I~?z9j;yC"ʫii;+O9q`#[bCnfYӕ2K,3diJ#2AJzKf,(ݬݑ0LtX q#2xPq_0RIGG܌5.1gL1lfu?0.~1F|j+~&A'V &~%mǩ.(h Beww|#ECq0Hè@LɎCHHFo譺f\$Dz[RSˏn[*+i:(00}4fBSm'ʶ*υ?N^!vJ]Vg<{AS ]I )kخ3%{#2_?$D0j-(/Tz/#8xoe%gy$uk7T:*od-Iz~$2 #Em\*dHDI^D.@>Y #2(WSM ŌT j HNA`=Ԇ#E0"$ AM{Ĩ\ -\\lVJm!$JZSrT!|Y۷zQ#B k8.Cj`]2HlCNk?׃VTTWLr_V(<qs}ӱc-=žG~n]2Kq9:{@BʮfZn=tZnBl(ַ5-XzĦf5 o:#E(ogbWķj#[zFגN1ph\5qh\X#[=҄FhJgҝ\SEWbz05u<{a=^@@(B#YUA_X#E넩_IIdp#E{X}YId?CD?w/{wJE?>T-7S6"* //_-W EbU1LR+ K넇#[ ?Fk6&ڍ@lՍ$D5ͥZljEiFTRZm5k#[z{i-SwUc"zdUH#2#2~>q2*d^PH`<;?F˘!Yq*_&.hH9݁s@늣D,跤##2@]ǚ&j!C}Z߄C8ǿtW4u4m=. "C6\mnhyPK`4B0f 1-굦`J$E^۽n'EB$AT1VHAEVJ@h#2r=yt2NjpU2-L 202#YPhf"'t}ޑ(R0PJ72@!KoUhƳMI#[lQ%QZ6j3PBQlb#EvIE~߶.\ȁWm5#E2#[$ "jry_^Ã?z=#[h-!#22< 8O1'p=wb#2XFoMIa>c)HN<(ڀwwXPPn*xoBb/D*H~#|XD0I0A}r(ѳ<)T2V:7~5E^4A礆ǖ-dW:b+ NȒh{BqYd@ErȔ)JP(M~s~[.uiMf_i9xi؝Zq5 zJ8U8s{aNno~_EXdGi6cʺ:u#[} (B <*XG<_MҚ#2_k$xBzRJJJ5_C`FEwnrTd~O7;+Sעևs͑C$46/7WHy!"$tcl>ne`>%]4k&@%(iI9T&9 n(>A'R r$D`ƟmF]̥R;(&h|(uxfP8ٺ!@Z06#[zݕ<.~}(=c729ߜ`,73ViyjO&7KQt@㥷;WecpqF;jt,FCnP(}HSn{CF#Eu}E<{c*C#E8Hr8/[:m4ڸr/G`WpH7~ljm-NbdPV;Vb>x^=:yt$#v9s~|ښ9Y3YnïM#2ɍ68'^$Ƕn~Ǜ!d;G#P=A#[O"#2q#E[6鍄Qu:m+GW>E獾%vr!c=R5,l _[fϚNHE#E:.ED&ἔZʡKŅuQ!~P8yB2`P#2RBS.`ؖ$T,k͒g-l_u`C<}6 㪁GCq$$uERa{DE#Yr ; ]cc"AaoڏtW3xiޚr-bC2*:YH,Ƿ@Gzl.Qyvˡ! =[?V1Q_t/fwAHR::55,?gVDyH;IS#Ot@gdE3U6NL};6DdFޞkm@T :y5@wwP#2r(PjbV%ڮbFlK(ȺKj0DCd Ģ"¢%\#EKFX@FA(60Mt4pJS`0b1 =#[ЁX]S%WFu==y^(d!BEV1@<(dBؔj$0q,lx-ɖ^{1bOh/i$B@SBoN=ecR#+9cM#E3шP>]<cl6hD6,"PM=MꈐZ䄐^mopLE)AjYy̪b'[}lhXA"ꢄH:1WI\bzoL#[oMfN0%l7SnsY%WlDDEܝ<}8^Bj'e,u;xU4`-PXj6YBLlFFFND;O}[IٮePYGOI$`CIͥ$"Z4`u#E/#EBBkR֛gp1p}zB&L5#EjxlTf% 3Cxh\Ѐo5JNR1F@$K dN/s{g1!&Xr(5#2u:m#Ef7c$`26k#]C#E#Ev4X10B3KZ26<ÇI M!KI}h!F,@Zb!i5lk. (%Kl%1CG-=L> BׄU*s1ZTiB%tbW5c70Po0a>_aݤChą5٨Ɏɶ\O#2dIՓ߲am=퐳Vi@,qĵeW #EܲKE9VGr%np%xEϪZrMr((P;8Í-&#[iwCA6EĊ:k=/LYkRdst>U3ਙ!ly"-u뗵a'~fd(#[Z"q]X&1&1c$_]M6o;Y^qX@$oU2QlM#H7I];VQu]%Wu$$;]%w@h'izhD BHPX0#2tUJiL$I¶"ًrQ]BRiR24ؿUP-PlV|Rږ*3!cE1ц4 pqOK2䬥P gc+m'hѢ[qJ CdN$نz 2c6#E#EF4`K`LBlddٰrEroV#EM6[Hpzj晹F`ʨ![&D)i4JZ+41dAR+zv,f$tB6]sʚqg<_>6mJQpm[^F+]0B1(=A#2YMh2iJNafZ@"Fj}˔r"i`#zO%A!NFw)ܝêO+̂rDw=Xڃ8ZI400[IRHЈ&Jei?aMMQi3%\LIH`Dҥ#[iM0mfd5b4Jelcf$M3i#&)"(%,M/(PiRJK20ɵ05Q"(%1Mb&Q)2S))J1#E3i4ƒ"DWoD7{h9)#[_7b2YZ*_[7o3y;ng:10Np5:,uplY&6B[6L@Lurv'f.hYL:=:s!\z-Cdd4 f]N͂G!;^Xmڍ0G[=84*.mؽ*F".kLǻI8`\GA6cGF e\C $FB1FRH٬)d*11fAEu<9nދx,ͅ,0ϹNUMaY+H]ZZCɃc#E+Ӿ'.#EK5@cr}#E\M#2'~m.WD7]OhƢo=$(so4Jٹu#EN#2kn#[l #:lGGge!U[7AhRJ$Q@"@#[&̠U:J?b8m`C<^E#_s着r$3w)M@̖vįX4b-izj*[i#[Ӈчf53*-hrEXN.Uyka7`3Oaie$ڱU5LD 鶣nWc.["^7LPKsM;4k]mw3XA\9b)_s9o &}ձd]+4/oo't.g!IO!W1T~r%I2rLw("Ngc7$wz;la=[y7gItn'[V:׳]v>gpA8y{HT8+xC\C>33g9i,Fġ;Q[|#EMs1mgZD"O'Ţ:25u܌qVeo$$XRW#[2yuӃ)$/|Ls iI҃O9S&24dfԺHf>*%%CZf/T̑;ýUeТ.#Ev`DXQ۠TI$ O :w[zɲ+92%~1 :ѻplp;&.)Ě0NP;`bL#`rL#[.8kT90:a(i̴9dNjRCTF-};e=6 g$NL+\q:8/̳|tQv`B\lӳV4!ŭoy**_vN4&sS0wM#EC`׃rQ뇁YDn>\(=}#Eڃ\ݒHbN4y>59͙;Y"H^Mk8O:(zqFUnޢ%#|OmGJT.6巇.-B~t%&,wFj5U(#;1Bh2s[|SSuҒ|3#Ez!{=T;q%j6McC`d#>g}e:,aLigV4BG[:»-m&3fסDia5&w!SS04\4ƈI4u* 5*oRE*BHҩ~NoYqPo8WVMﺣt^ȄI1[K+{%a<%N78+yeЌQԹsiN1Զh1/QLhfS\qP3.m<-*>&%!öD#tîr\6%䦽e9͜\ebq`JcTCVLֺ֢{sH0qKh3mQ)Y#J#OMPglC鵅,5rח+NP+ƔYh19D:Fb,1kC14qL&01sjR}iunXVȝ;qrbBZF#2$$zdbcmF8w Q bLvK0)N<]fms%pWrÝ7$ps[M5si-7׃uU6uu?S]iña(TI2))ͥ[B!`C8fmqKfs%O6(R*xq,HR*%'E)!*yD<;:-K&;T^|ydF"syL3qy1FQh8.%#+rzDc,Tf^m;FQFՑcY:Y%4n#E2a48dGN7xš#i$#Ezev٧3X:̦1LdMw]D|iLH^:6We$>u8YU&tVv3P6EqX2a#[!:H=<Խ#E68pF4jfE:aQy96kfjWڢA:hHS *rK#Et1(Dwhm_b.skm#[#[ҪG[!$N`Tl)L;ڎ؛&FhRhmh)Ȏɯ#E{l7]bvžU˳;iidթHԐ!Im k$3A&D)~L*[# h`ۚV6&NoCaTa4`n'`y2cLS-WeBd<g5)&Y&,L$.RjC^XmjG4[e5tLP7aVMlffё4bmA-R+])ʛpmDeIz֘JHaE]+dia[JjN,)CV[,,#E0ʎl*s@p$ntp,y+C:49]}O%imt@vjU`eBq1`&c<.S6pCd0m;`BPïBY.p0:!]du'f\`Ehn66f4q_/=7[6'gMX|k;3kߊ~@(yCp#[FLІӵ @9Jk ÙHL23훺$*c)|`Ҳv!0#[0bX%rjl"Ǯ1|9!M#2a٦`a"ѦX]=QؠeԞB#8hI##ZA9Dcu48ř*F=.CE#2: ѽ#ټX2֦Q1Ρb)S ?ޫFBB(V&in+yW "x6CB#2dٲ r#2 l1ub?W~o=ه<#[G:6K,̽6jGTpYŵS5xɻ:(мk*ËCg/13\B{Y|T1eZ#E[U88k46CQXd: !\r98בus"j I6kAM8Yj:eTS\,1`oCXw\UQA 1hda dD01)T27#Ez<,",Xc3Qj4zY!'XZҨk^ hASh{}Hh6fV~#2OD*T(;kuݙsuuA\ ~Y cjH#>ayCzHaJ`o^B"H(童'Jc"4 j(=pE=XS7C3jP7X~ȸ|@#2 m=8>|3l5HFW1Vfɤ\#[ 1BĤKhńb&T@ 2&?^FQ&,FSL*%4#[!rˆh+f>'Gd2#[̤-شm!kcQbf*#[ih-mѫmx[j'n{\)#E#(B)n9n\2^%a$w $=E"e}qkm&0dAST#2ZI)'A3(f|,c ⬠BZ(8qơbX^ޕEO $)z-`7b$yԢ##[V$b{&11(0#E0&TP#KH^a&,ꠡ0"ɫ1IG?q+D*9'p@P,U`kTKi0`_0ޤ4y'n(pЁ0L."NعGh8njHbG/z.aY5V@}H3CLΣjPed Cr-)RmhCt($4F+x Q#6^,[?/x#2rO3#[)$Q#[UKiSFFKDB/`6QF #EcAM`-}D&}4E`҃0\AR~dXC5lI}6(GWY&4x/UA2]\JZ3!l=,Xj*M5jQA IrNJ5ے|{Ԍ|&rkT#E}h{Ӯj#[[{[֗F%+CJ/rRudKhⵇbc9e!¹tRJ-Sm(m B җQQB3S0oF#[HmYMjN2K,zfd2Lz5ՏUZ3ED^3JζR&x#EI"ndL8-)C`{ph]-wɩ SiSk&'"#ESn(ΖVVϕ-U!\N#2vf751UrCls#EL&K5.oMgB`roSmeM8WK-}j:f|ÊD<#[4If0!˴}^tX3`#$8pq)JI5G①R>5{jN"iHv0[#[A`C V H4I$Y@X.B4%)#!e텃t"PV2*5CDQlT,k%Dj)-9+h\ۨ-fln8ҵ#,5#qB:;n)zfuUpQ11iqJlLimԭb5F81ÿ&IQۊڼlTlRHjRm6eS6mU55ZY2^TR[P`ڙFXJT5Izo|6E:\l.@`G]&TNH)DJDA;bϴZx$q+rT}b1Gua)h{`fy<>LWiE*(sܯoSy@-,l#ELXDFO`Ne-2!sƥzB&~u1H5TBA@)%*#2ZY#2̙@#@ACcbf3 Dm̈́,S`p#2*LX; [xN+G8bhH߬ LU5Waè 7~r%kX\5Ř(l\N~놖O%T2r "@,էݼc|qT8Z&"\ $/HUKk9噧CZ#pYlӗ͖| %( Ƞ{&s1jt'軅(#EAxtHEʨ#2DUa!>5nM^J>ޢpFO.7bn2У?_2.}uI Y~%lR;%h!FH]J&^ݮ12In" i-ҮƩyJɦҨ-FƤQK4ԖS%+LRh)H[]aKI7{6$(k5jh8-]MKVv٫߮Ɗj)IUL3Uur%^$״(+6DiU\FIfjRUziBfF6[6zucmYIMZ;&̳]YJ]eS魮$m& A&r c9ŮivKXuz7@BqG#|{hp:ov ng\ԓDRzFS"7hSCNqSDYnXE$iǾTeV隖K*0IJi##2r^.K_JŤ"+fK[٪Mc[EWYvZkjr6k}*%H Mumi2R#2 #2qUecf)i~%tPZRke-m٦mdՊSF)̷e0&Zb%M5$(m-%M#E3̦(,F2QM$FIZ4XbJM)L5J2Y#jQj6iY#[RbIM2M2TU#j)bfԙ$Y[ZYV(hҔ"0 *"#2JTMK|%Ŋ@D,m\zkkJ-敫"kZTVm?v";{@tGqF+"zq OwGh0ekUs@=vߊb|ωjp"#[`b^Q=7y;# YvEgGv5ѳlf=][M&H nPRb]W҃^r9#ER{tqzB#[ /BCxC@.S1\a1TAQ;$"Q-B\A5GL؛b=H #_N*xH&"!'M5Q3?vILDs1 B."[^F=S-.y 4(nf}(|yصVv7#[8T>*#T蔴3{WoשodCIC~PR{H8d\_GJڤv7$sج$z3ep")~z0aΤ2}Tb/m^ݧH<#26QmJې8{;[#ij-=, AdM/3qODONKdzP1Y#E^BmoqĻPLP3#2^"c2sj3(m15̇T9j˞;AN]5p;ɱ^u)jBH0{Shl @]bo9ހC@E*堳 f#[((c笳 ְ@syh) k7TP2S!Wk_F7Ĭ(YI#25yTM-4A4CP"dai``N\44(t&),֊bˁ ΡcmH&ѪlƠ%R(lL2!1ig5b9b-a#[(]@ɂC" L}U#[C\R]3Olm~,7\̈?Tשng(S&բ w 9!m@iAss^Ė‛9EM}QR19uy7"@yffC89r;zs,pbgpшTyb)p-DZ Nvݝگ?m[]RH|.Y#2'Xco#E}FL韐y6g!ctW-I=SG^VP<$f*W&`#EBKk\dLBBO[4sC3c(0H&7z[XD>5CAm*}#EH4̌FԝnQ=g[zp>;OR:4#E&A[bX#2]Z-J؆_;,8Tl6dBoڧ htJq"ǍPhiF:I !%'續#En$TX#[1#[h3ѡ֟!pI0"U#Ee#<ɪW3Tm~g(WMNtfRBd`ځc8sh:ZZotQlUAx@TDR7ϾԩyHz PdP[[%b%CLfT#[3+?_,?]y eEQhXNt1!AW8s&a9Ť;N1cD&扃nD!j:5u )6Qx~<őU\;1c9Imw/.]u,92&e"uޚ[^vɲduf_LZm<rW7en) iLX&QFYb( _Ml2\ #2_q8xlַCvL~*E#Efyc$,ʕZX}]fSW[8C6X+5嵆jҍY6?p0#[ª-KH$IJ#[leSfME]f$5Qj*mmȱTI[m_"" hAU*k[uϞ`b`p{kLsu.\ l@-Q#[Ð44l( VFRl[FAiT+J[M!B|}u^品I!XzfGe{䢣EB9k@(N0D%2UGT2YAPTa)&,zz2]Q(E*)-U "31McmSV9yO#EBgȡ5b˘nG¸`k+r8#2$Q!9 ;?Ǣ9}NAgV, b5% K#[A~ܕ5iID<~aP+Qm !.D3n?%`T@Rb㚴;lyKH˼k#0Q@C`It("@Cp7lriR}z{>#[Q!d=p'rCg*A$"mkQ[dj#[FŘ$"$FE #2)wdiS,ECq+BAiuB$(Jk44}>Gm1}C ڞ%!h8+, @RE#E!(HUvA2ZPH}Y}VmD̥O>SW@D^a2 &Z1#26|!z#En+imn>qkvW_Ӗ]myzy5MVy0b!#[PI@#2_i+ץ%""#Ei5!H,TU#[E3wn)g U$,%4a?ťi#E?ꤰD@?e#E:\CGDPnqRLRr,`7,8h-d"1`Fٕ$@3GƑmVo*4d4ed%1Íc]XEuP[\24ڮZ6b)m|$\b2.fj;&Fn׳x66k^#26ӣL j`9QF`L2тK-J+[ޞ@mV*ь9aZ56&Vt9(#E#En$l#ݹZʹm+,j+Erܾ#Eyܓ=u^7xErKyXg+SgY1N,k#"4ԋk0,$iKbcG|xt4%ፁ$&Dֶin-LQCT$GIkM;Rv;(P3wPmOEI'"mO?'cwl۵LjUVC41\'0t4WUގ#2yrT@xP?a}~[EEeVV#[Nn^W-y.m53I5&弚McJ2\I,V(]Mm5SAXA"Da8J"Fն-zg.ˤyD(R@^l-ȲaXzve~kDW#[,Ɇ;,$v&26BH}'r#[U#EvoE!R%v`JZ A @?-[Y75k")!4ZfIEgn_y~{ ѪvP(W5>xACiUq_+)aÊa6m;#E<>#IhoLH/L!!'.7셱B&!!@Z2Utkk]M\vRx6£zLŒ cwup6ζr56ō%Խ2QEDP$[k`w2L(,Hƚb0`SPafZ--"!%#2_'Y9@,E(P*x {R"*zʼCox#2EnFC&3יGN^K1:HR=趝50mHm,!#2iHvcВɒω5("-r!z=8;@gɒ zƈQ7V!t5'a!v(h #`y&TyQLt2 Ii`q>A#ES\҂h#EDVCMGę?xFurQf\xjy!bByJ0UR8>xc!DS]ٍ\lh!ֵWds>>]Jh^pa4 v ӅpMaj>7>)6ŨV4&"-m,-FV$ׇ~ּ'Y ,Lr`O08b&8:(hj5dX0dY0i3l:p%#[٨2o=\R|~/ﵚd7&Ѭ=M1 B0ܮL*v#[HۉbLU)x`H#[S-9anTFmxıC^$S#2B(0Mjqo:5&3U2fbDDȤT7`BRx%U)n̲C<ͦ(X)_TUDǒ#[[L`)MeP<8a6Hѫ&W$Gt.dh@/6vN/D=#[qqzf&T4Zz&Cٽ$Uȥ2c" B@ETX#E<[(x.3.|v"wUQ# 5"RKL\>8sibB#96;6YuJ#2N|Gd"15-$BȌ0]PF!mH807FC!L#[AyIeb\B,@Q&2Ry6d&-3T>6QdPĈ1T)]eK#2)vs2jQfRDGCtdN4i9&]#X9=]g[-=r+m'Iz/58Ѣ7һR9E\9k~ygޡTiIaTD#Eq[Salʼ-BK&˭(2ӣPǑiX?t:AB#En}Y*# l4ɝd Cwh*TNi%-`v~Ɉm3 Ɠ86Nk&ԦZ-|{Q&SҭNF||v,Jɪ7UI|!6g18Ab0FKc0-*.aC/L&Gr]HP+]BնUJE{eiRZ-#2Y"*@c#2Vumt) t7qNp7owj2مj V^Y3#EtoC3Ngg2Qd!d!CprѠS)#EI%lWV6L]A(@' #E.HA{{}[ջdռӴ;HH}~^ɞI#2F>kFu]WIzF&DՓ7]玕םEuhʹcIm5k%Yɦh$q lR@LJD>?>QAl6K|-`N@\Ɗi_uU/|-FA2Ks1r`j|#[6FĈͽ1<7%ZB9iX0#0Z4\\3AI#UAswCƧwhǙ͎39tAW8b`˯JZ,#[֠FEed9qKwL:--.r]KLP#[ƫ(:ƣ#[^>j!RA@jﵼ)i-2شUkجZɕZ^5xstJ!!Ӿ$R87~c儢ޖ0p>Awn#2@t)sϟ#9(>\E}ΡRA{` >0JUoUbq61$(6 <00 D=4&m0b09_0/(](WK@K^(q2YlNMUY4%(I*6y!7z^%NHo'ؖ+:Ғ(iQb1b!AudeqR$`xVy۹:WUtkv#E+DDOEX pB QCq!oY=ɋgĞɃ}'nANcQP jzS1khrCԫ#2}p?.gEW&qR@iPTĩfP&q"Bh퍥s+_payp-cMAp[(uFd#ENf@v#$0|%PAPJ+J#EŤ`Q_8`۲ʕh #2F)h ,I$:u[+w[f #[TDk:*D1JVng4eȩ0$pƢM)6Ngd}>H5!W܅x7.3 7iK|%P' hN<>%Aؖ!Z\Mm#(SL^j#2՝Hu҃5,=+'?kˢ 2#7ξ/DɃT {4M62(EI.kGBJ9{5¾g:.z!`e~R[ՋUۮ0VaEҁ"}!Eh焹рcmp@$~8;Hrv}Y~;w_[X)jqTkÛIV3ۜcqm6A3}-IbU`6& k+Bô*m]Z0mdlAA[v,a%)`Ik$ХCiְ}`7P(8Iv8hC,@~_jGC;dLAPS4<>LlNvK3:skY~[d(cB0&(c&ȓfW(DeR:z90qlZLm#EDagjl(i] `Y)0(ϐmeVԪiݨ)={2uТHukg%x#*#[ntxރ51$) ~2G-?mlգ+c!}/ώrYն.o=b"y<f6%p*XT8G?#LIM*C<c!<,ybHa@(%z(B<9&g%3@uATƮyBFBBPBM5_ǚckFգ\kU6ɍ,mZҭ\1 9˔Ӵhhir#[CN4E2*OBk1,.Bǯam" ܳ)vRkFz:PP1w8-z{}n}Tɀ_[Gh8ތH0I#E4I_jCj{M&ú5CAH"H5J٘x".e*)CФ:5t}>pQ.s\pE߾' AN㘼{lZ#[FCC٩僾a`}Fjr$0(}'HJ?1\$l`>EK[CHTJs|汘6e5F#EMڙxljE#9aUMb#QbY#Vnmm8m/\#4.@k1c{z,Pı9wp?a5 $/ikAQOjr-Rlg*m/&Ux:6te:d.(J|XWL}2,+{YL1#2ͥ0)4ֳ:Ud&%77ГʬZ6mhk1U,T|k#E,^{O7k/9vb]#[l"`RS)ChҌMIP[̡[vGQ,44,ebl\%T PFK*X0#2Aa@)#["Й.1$`!P#[8@9\l}v=-r,l'ؘE_4^ftsa#O!t&dײX8|_&[S#A# #MH'<+F9>=S <k"v-!V\6=F@T<ǡ4O.Z~F!$07o)!u<p3G#E#[#EE}5xmED2kN9-|0PBS.·WK|5td~R#Ew#28P d3SGv#EQ3=o\R&9n֬kþ0ToJeT1OE53͕#8q&/&qcg1Z[bG\co3 "'f1[-"r_b.V/F,j0FE#[0#P)V*#2yFuiF6T*填'5X%<ݮR&lhUY]kٴV+Ԧd_O\EXh65QlVZ4m2ѲTe4fLjh6Z@65`]@(YP)`:̐>#E!PEF"u$ FH I!"ȃe:u_.Z%O}P(}gs,4dΎ/HAADi)}#E̾BmdڶR~^igTQm;:])knQQmR[s\[5WebU^y4}7dF$CSIP4LelJ#2`o":Bu.ۊ6*5#[HiT,2J6}VJ1AsGc#2B"f\z8MHk[O0zBmڞqk6wH(p\9uQ@ީ% f Y#a誏nfmdaLf7?,qew2M5 F3R-AeBa-su.ӓ2Ln#X|^^^hC&(l>A+u*;,yI]x4`xM#[b^IVsq8DFZM3-ҍJ=uɣKpꖊ,/ ^)dHwСEF0d^{B̀^.N;l>qYlz1~x`LU}&eꕵTY01)4Ҥ%52;0b#[wHDUc@l|n۸ם\Sws44ܷy:,&Սe)YekS7V6c5X!#2mlkRAUzu"XH`X,J٤h4V+DA2#2k+jѓHBH91x,=ac\4BRHcAA' irzx%>Jrlg31=FkIkdl۷ay]I(3j6ݿ= k̇3v= d AE-!(0@!#22L:#2ϑ:}#cUd!0wCڍ527Γ]$x4#E)Pc+hz#2f9Yg?hABH,T [mPmzh6H0ځ!sc&Hjsמyu;fDoSky%>7yKL#[yRX*֪KdՑqLJ5/bbғ$o(FrD(71DHQKҭo25"[ dBiH@"9kC~똙i^؟\@qHP>>.ƲЀ.@Y(F$BY*[lMڦڠECzNh"k01G17mK[64ɚ!#2E9_AjAIZv9i+&*&n5hlm$7.܂ 2A#e8د#[HѤTuo%zࡩ$YGM&ר^{v?n?VH?D"Aޯӥ~kKnY[$#E`b^"#[%A0v KY4-R.#O::1)""pZ95inu~6Czy#2ZEO\88I#E"Hd#EADHVI-M7AM큦2LBm.JPKT@`ٌԅPlX,b]`#[#[#[l6A*5eRUnEdm3qu|`pW%PTsNi4PR$5Hl8:Aydd&Y`#[JHYnE8b0E`$BhTVޭ[KN2Sۢj ֫5N7ltR!SQQ$:ș{y#E#E#[UMvE1]SZk-;Wjm[,RU QY IUI(-4Q#PZVζ$b+JBT0t{"̜aEO0&(|j 6,L[D Mtg_Lkꫠo<-\rښ)ɒcBH#[1xm$"uEXmYQߟ&ݛQKK\`Zek-4Bz=aw< hSIc[m4;CAA?n?\#ETD?MQQߴદZj]KV}nUS~ZokԮPE;%vDԳsU6#E8Άt^!-7o?ӏYȥ$уHX*f?kI&\Ps@PDDuG<Q_KttA_d:/? eetϼ2Ԅgц8ZCD"2Ög4ū3:B:6."cm-LJ8';7n*e6jo\3gDșC#E28Aq)37#ED#2adƍ-!c?k 熣#EOqTr Z1*+@R bV'f*i'#u<qr#[>U[g>$#EAahlt#3H`(._%v鏹1C},jۄ{r=RoF"*L&a}2+!#Vm1PŹ#f45M.EsH:}=n_~ʯKY{^#EcCm6`3ZS{O-;YҞi{K֞m#2>Dŕm}I#="cg9l/ؐWb鯆G4v8+,;(U^jq邛dfj{Q۞ԇr#E|`0T\fҧm~jNHf#[GkfM敚زeY evӢq #2 I#[FPUs>*;/3&p>>~|g@܁PB=zEf#"yU{xDvD:m #[1-kkȄ4̄h|ǂX1ΥF~tHT#[&iQu63I hUf-9HV,p{Bv{عl3tk8[!ḑXPRRI5rh1JB$`$Ab#[d4WkkuV\Iswmo\llg>ns10o45?Y8k$lDe[<dX]kk,Fx՝<*kʾq|6p&Pphc!i @,@6D2241s#E۞S6ت銬5.v/doA:6vt*r#[͝V7$rUPr|D2H7&E.dthΩ*-6kP#=hWyG^M㷱p.FnBp6#[S(ooY&%kJ=A|>@+iUEV+\#2#ٿEHqלC35P:4CYNq#2ss#EAn=\$JcQn I\sGkb"Um`֭vs>'98]л#[EO2dÜ$F#[QwBMpJ8a3⊇y96|ˮW>rWA9VXkb!|mՋmԚmMPX$QTPu%;ω#B>#EYUbXa 8-kǟ?̬WS/H$#>ۺ}b}J4#2QRD-t@<'O} Tbt~twuBHz=)Y:)Bo[9|u>n?h=kQE1tB ږ .Y♋i`eh`P2GۯeFgwJo)XF"z#?O|/\cc4_*EXIT#2P瀍,dNeMZw,wܫL0̥kS~jFX$~YO'oiz*Q)ȿdU1ȹ#2:K5w.j{.p.4Є:o#2STn^[5!Qdyw,(RkQ%d7Qoc,:-dBʨr#!PT~6G2d@Sӑﯷ&j0b. H(딨D$xu,mw5rlLgCBsoIURP)t[Q7BaD#[a<-daEFuH{nߗ}NT3]ֻU!ŭML $!!"!=XcZH#2;2zWE7E#E[$P }o)#@&љFTfDE&!&4eJIeI#0]'6 9 ؒGyL_v)LWnl#Ec#EDɆ$D#iDgDfH#2#2[/<Sop"ͳa2Q#[ԊFVj(%CѓQLBV̆L_mtjrr}XH|6{Xjv^vOBS3f#2JS;u'bʤTBO@I)E9rIP2M,HV*(E,C@;I@Q@k-TJRiƔjg|l-,U5I4FdDd.C5ͪwIwn],r#245YLTA-SȬ001 ^#[V蔀#[J+M*(#2m4QY66mKH( GmK2AZ.B:%#E[wFVxȪx0ǘ2aBhMW/SO<Yb&`7a.#[*99T|\mpX(hB0:'fi#E6EX/k[6hqiF4BЀ7sijҋcTEV%cy$D#ҕFؖRJa9)QR6cD%SIm46LjhV.nyhuxPaTNYj:R\لm$!3l"š4A(F9*²1&6*e(lo3C012h1s-^hٔ#[4pB+R#Em,jh32Є1Ga%.Sb#xMa]={LXaha~7iq( ]i3Pu=7kX6WK1dR0qx8Bټ1EMjJ#EBmKH'pA^KF#[Gp@.3NXդ#[@62*4E.A& F♬FMHmFoҊ7$;豘TnuZS+j$R #I#EL!L#[:2 dIdPdaH*RF0&8e!ZLCcF(6O3OAlU8T6Ģ% وPlPȍ;,)FH|#E4ޡҨ?&,#EL5zN#[fMgFSE Aj+#E<14PP|EbY!滳lFڱg6y&w3\g߲f\#c\qIźߦg^znU,`6vRcpdY~`!H~1aؾj/zۦ/b8 s8^%ze@RA!<3ޝ 8?3f'3X+4mM2y(62SrBYp|gQ"IDCeXh:>S|H,S iG#Y8I$7!U8}(?"~';ip/VWy#@v矘*tT2"B+NiFoC)D-Z1+\S<ғ:[٩9Bj묶R<9}ĪumptGiK%t#[܂hIEE/5~_#Eqw|!gOTeD@Q/eW5T%Qa?H&l6H#[9#[f#[썵!A+ LH24,"2Iv&ܻ6űcnZ[!mͤlVӻٮEFFьQQ\Yݬm_(/6^#EcW@riX}d>lo"GtE#2Y(zgC*L0wU|C#2{@^hܪ#2NZ$R]$悑@*]ǏM)#!*0Hw]dH`hWz.0@V0TA#2`*2#[*"aUMTomꨨR%ۈ]*/^*AQHѪ-aXe,MZ >b "܂U!s(ū8b>9_0b۹t6֫g@QTTu}z$A <=F7nJuYTCWiJkWURS3d)B-,E(ڊ)%bUVƶmiZejekEO\ֳ&1aPF#EZ6W"D>m6aU#ש=7^:WF(!" c#[16 cHD*F E#cDQ4DB("E#[B䢒*-@VwDQSŗNiӻ1uW[^[xu*A[6J#[;#2dP&](B`+:vIʟ_EisE)^R#2&Ȏ懭~a8gnu\Z#n! QT&<#oÌJRzqsbC4E8RXT0N اp#Et4E\;^7&˩RFVEkZ.EVo%o' Gr'S;ۺB@J/N1Td>{d^/zh.ؒ7rps~_~7!ZfҔc?ۥF@M}k_tC<%\"Mc/ӿm-ȚS窼 l㴼C#E,{퍈8 .#Eg%akBv4~#'gGࡢYU;ɗrpӀcHq }=@Te|eh|sKԻ:=Q>~1&\.*w[=&75zE M(#2`|36X:}=c8kTnmp#2AἻ5FkٕZ.x5]ppbIP489vҞ=5B#E⺻x:}N٢dJ;\z#E&1#ObSOǵ^rc=iA&; "rywZIqǧ<{o mA#['~î=E*'#EВnl! /ys74ׇ%.!¤Bu)-@^dAo]&V~9>TͥAACj:,=bM]dbqn//b4G09%Q"!m(#W$dxYH̓Ct+Bsr8i&r=:n!;bzz->'#f7<K[E@65&LyG&SAr<ݎ,ٶ$1SM`V'噢u^P.p.!Ύd3[FE=K6}xw[A3gε)#EgJ\۬;v(̎'%5.Oue~e$89λѬmym0k9l>DR C8̭DTg>툧Ƴ֗!"Jf u,GeNyl-+<YTG#2GXR(Y%nTl4gFg*yLls~ 1WNXiDF1aT9iaJ76+`cXXhfUI]\,PK՞p* =<ֻAv:m0FD=!Sف@PT0#q$ #E^[Ƥ+˳wfybO2."4q2NhkSACR5D0rp~2$٤S";KW~.r CJj#[VDg,gT3^^rx*(KbQQf+]bv:-e7ZX*gnl>Kuv߮;KOz[ɷ{"S1Rғ˳!=QX*7sDӑY[8{bd8Y7̜u36QjyLAӵQ)rTʓrz!*i3F%͝khΠu|b8g#E>\o|Ovb",|#{gk:8wc,nj]ē#1%'Lҫ"-gdPX#-ۣZwWf:a۷&٫t%U'<"B``e.v7Enpq-DZ̝d멿=ΈɐiTN港oC^Tl.ywh3q yH]}ᠥ%g3#ozVWdE6|>SB) Z`jE`LP'Z#[#[[22·y!tY#ۋp#E8`3#[u7,;ÞR>np~l^+߳&jBQc}km?LM8m<;P9j'#4f˧ʤ(aK/dyդ#ECזNec8QFcӵlNe]Pے3:{iVm%4^YM[#ElBÇp%ִH+NUUa8և 0!sYX;Ϯ)-[etY,#[Pp5Y<%o+3#"! 0݉ArG+k#2#ޠE:(b^oC^9j$֘ HJ^ilϤ2aZqvkX ,r.Ĉޙ 0%pg2vx8:q)[b,204EDb$,fku[!?4fӨm-D3aP#E"4б(b#[QEY#[4ƒHj/fTcmoMh`#2#EXB"(ڎ^-65*&PTҊX`Y,BŖƠr<33}mH$&$HvΣ=5.H*"tŊj^Wbڶ-mhֹUj7*#-Sr31o]NV5]c-PRbc4BQHͳ@$$ۅQ!ѳQ+^3J{2tq1O#Ecׅ!(I ]R2AWˍ=HJo"DQNPk1j44#EaDi6K)a.+M1Ɔa 9,h墣S3U(3LGSPZs}zpcXߥaB#Du5S+$*6q+"`M,cfL"TX.tuˉ0:X#[2+M1d46NFFO=3jL;5:wF#E5ainmdBc"Q[ڟފ=#^f>2P(Xģ܋F:ݔpf {bib7'Sm6tp`mI#E@bof!br; Lf8wVfoRgULsa*"(R#(,n`ny&9ݾ#[OrA#DHT_Nvi+9s]mːO#[ vp?/P~DSgmXn*$9gIaOYޠ^ŗNqcPAz}2C?t#2!o'4}U8I١0zQǑ7vwc_T&rkm. ]MF1F̪f|8yRm#wIܘD_w@y9;1cUS-Igºcȴkz@<@#EQE8ߍ%Dbe~ӯû#8_MJAAfNך 25i-v6\Ս֮ɵiutHgi">_mwWzU!ckHje[aF6Lc%T-S*#[md#[J6ĕ#[4Qh͡M6I&J6RTF4"JD2BihL6#ED &Km$$E?aݫ~#/\5^G{ԩQ&]Ś]dj~Q:"{%487`vDa"ŏ@$z8ȫ베D%KT#2@چ`nj#[3\&x[N!ƊPnejLn|O#E~7p"H(EV\@d*>'fᘛL4b(aXUSy||WYSRBbsY8/V$6#[KTE%4}Vm*5(Rj4b#>ڹYj^]VvbY0ӓ$L#T1f@ʪx v.B}H֟uvjKƢQGJ5$r[lTPAawNP+56IC(B[#2YGP%ĉؽ7 .kί3E75+I.h[_FG6\[(bEi(Q#""1/EiӻP*'\{N1Kyl@;{j|{#[ sjtp:[X.1$S*Li[ZVlP>-fEb#E/2b*7߭$m.8/Twh0xN:dj'9A%WK6$>?\QܲCQIZ"SA;k*)4Q$2J v(n]K2=W!B//Q`=ؤPߓGIX#2 .j`vc"x۟|`)GL71ĞQ*L#E||":߉tQXr<@?qe-_Xdjg4==j<УYXzb4YH&-O`:0aoQ{"ܠn,-tE`U2gQ,Wn-c0p#Jaou'98>I5csY%hdvTvx3͞.kbfe{~߮FA%5b?@ȏM IVQWiq鍔xfB?3ԏǸFr2g/z!$\:n&-bgбG$&%➠sxSpBH%m#E84s9,hLƶn"6ﻍF_uC&ϮNA"4ЩL iwc'HkY F4³EJvct&ܨq*D`J#E0 HԅE1ZQkj#`*+b28\A@UCmcij"HCHRESx0T::^#E&1B97wΣYũGFF<,101:%bQ_zyԚ:?N6,F~v2eܦBd[ѼuEDTew\?v\gιwnL.#2a%魷=|$rnWD7f%+*0e/0B#EBRAxu#fB@3 Y03 Dh mlZUO-+c=-I5Rp+#[*hE|fPwZn<Lnkm&P1o.t@k삷#8`ʂXVFʲe.*eō!sslcar4p$6ĶP=Em7Xv5ii2K1r=I tSc5-),id4fOȜ䘎v7״J{Ɔll\Vg%mWM.S9gSN);&vt.s`\9W.d!&w|ؚ4t$!90ю+ظY+VKC-xsuZuvD#[eT;<=Dg2ɤ[ia#[J%XUǗC&M5wO.Xb.d$'5.;HX!/U6Zexg)#ENiyK\r"Yr-Y\[Sk#E7d.yR$1䎓H|V"ىd̓46yt֯.T.g[I#2aȱր{Ctc#S@8o{LDlCWÕņBI,k$`mHlR fy/ti#[]Hi6H"P(B&mI\aЀk|T3Fe#EX`C }U*5H$$EѬ5-fKZnRDv)Uӛ<1ymd(viU,6ddܺd\h!-_.6˝Et:"OF^.edR5LM4N:æ$ 14y({SyH'|]<1l>mCO|3"&q~<&aLS&3m͖&GCdYqUb|2A_!f栌դd0v5#Y#Es~f&K%! 6ҰUشS&z-6F݃lS3ΧGIf$LFJŚHPK(fc~y,M#[XrfP Ԇ+ˋɄhY#E-@@V*L06S UV^v\Da4Jjrs&z"yyBn\C8Ls= 22ږvA=38L$wqWnɽ}K#E8`kcZ#E!*Cw_355[%L&IaJ.ttwR#E[BV E0eELMkI4"ݺ^w:EuHz 0͏0H$!uфaႍH`ȫn֩hI7C30lQYlj̚$#E$L}(xnqec&/͈mbRpq#EQ+@,&([v&aeHC!$#[l&.xL v 6"&dGfA3bTlB4odADtJ#$#VUmȻ!1`SFΦ;Kl#[u]`v#[40# %$`g6bPyw|(@)2m#LQJ!BFCcAQE@Y' à|XU(%JמԛtM#-/sylxhdw]#[]v~-G*Z!D5,=̖xկp!yt#H`!{ɌXCYŹFDN#EI:f"+#E]&!W#E(#E5Ha ¢c#[$J#Ew&9w#[ncNL}3d*s=TYϮ4u*&YI>m$_?C8zBb%%,0yIjE6mՔUkYT/1a8]6uLDB 8Ny9ۃvzN3D'#EGf.{/xQ {h0Y`iّfR}fk kG;t穬YDI(w{L`(x`Iu&"IFZՔ1%KmI#"aeƅ*^jMm\o5W-WlB#[ ,]\P* R{&zMR/rSM? Lui{龆جdص$վke/'ޥ0n#21,# kewLTG#EYba]/8=CwIp2zy7IZM. $#E3\&QJ* FGlƔar`02`#2ȈTGLJ~Np857:DB{NO?9PoM=NE%"#[#2뵇"19$$ڲ~)^uUnʹk#nU6.#2(w3eWfX)hTE~d'#EkuVRQ,JZnM6wrPyR[~!%-a(|s$4(ͺuEz=0MgYCe"1B5*D3=`e>9:T* ӆ^)&`LV8Sf)OKKmTT9;;$Jy7#E`0"tۉ7Hݔ\ّ>vDA\49|61PhTAFfa40HlU&5#h"(1yODTJBi"uCu&-#[A( (H<q#1hl~}nw#2{DȄlZ4M}$U9Ŋl8,ŪK3(3p]2EKBϬ8DR#2"a[ Jw|RdH8-SB$<ۄ;J$p80#Ewg_mV#:\=IsuLyۻ)MX#[8#2<(\{i,ٮk5C#2_h#E(#P4@]X={KYFLfGj#4I#f}ͱsכ7ᐩE4E/&k^Ehs\,yvIZ̛*m]I#!S`7r۳wPQU+`EA$-M>U)#[~;@ê!(dfʬH^ u<@@XbJFѤYITٯ5u_F4lCflh)USIK5soMI\%-lH02.0諺Zn1Mak-b#jR`=y-I(tZ"wQ5{IܯxA5 FOjz#岜ڔ.I>8I$x{HC5`8IQx@:V1*.+~6Xdl IIT;g`ЂsNl[JB.#[!BY>Ssӯpx#EBhށ`0?6J=A#2$#[F#[J6[i45JkW@U0jlkL#2 ۔#E#[u=*ȰZ̲j2˪Dkz3.b1+#En&` #[&rVLն0ez4oNmĎ]Ͷ}0s*><+h)cvB0M$@JdTRF#Eb66Rѿ~F$$H$?2:w^=v2Q f6B$a=*ܫ|F:J(Ab0E4M#EJ5RkS{nbI"#2A(F,XZ* VmBE#2BF$n.a_={*I#a!#Eb&N6דL#EĀ[R]$!(]~,i}GXR du2!RLDRȉcOdpQ71& p]XM#E4M-{p9kwezk6%W6T[fnʮݵsȳVƦ[RTJFy[5$ISa!H6bM{v{7jרP4LPĀQ4Yl;nvV˦J_%=00hFa4A?`וUkB-/v/kbgToT1zLfgړ,b#[rrgxYT(pJƭl50:t#2j.rT.0\DNpۦ#[T!Ǔy%ąOM#EUJ]/αo&i13VBN1H+R3x\Lo5aMN1USp"^|3ww:@俔j>V]J[E(?^n#w/w6w?o?^p-s&IszO#[d+6;"m\?ӌ#E@7W#\K_31QazvTEdzO/s@3>ַT~`l#E)&wm$c>&aMf #l/ep#['`~鴠ssxqE@rzY'AJ(E(H-#[k.31#2AH(#'@WKHRYkC\#8y.PF\ʶPrРt!Bee}%?5rܧC#EsƗFc HڬV#2ԩU%3KL!TLf*avwjU2J 6^\I98L3`KNSzc'48u>|1ikc%Pf\5ѽifw$%NRUxԛ͢Da$n&4KF5W#[_4^Q&kن\B!RFS#EHͮ^ `f6m#Pĝ?\cîTv7M^AȊY[N予nѳӳt5`%B(zy|uEfJ'w#EFbO#0۱L]IL|i'0aSӑh[gxa#[c[һ0hѿu̡# c15xu7VE;DlbH* 1!},'Pr"B@K3/ݳ>$Jz9Y+Gb0H'v 5Z%owA#$Shґ1/kB*ҙmEf&,(M}(PR#['@t`cΩ*Ә,Rؤ;C@e0ԤU W??*FPPIHlLG~W+ϙUIDjKKǻ&QU&ٽflzC=$2Fc6ʆ#E}]>֓|h|#2pǤq,J\D-y@3+]'تhx5E8٫#ED|c [+Yj?/Fg:&'THdocchV+ŶWZަԛUm0D`\D,n&볡H`nd#bNO.d=:$`62Ft)CB$ÌvfmkAA=z/u\dFn+<<~QۢsGr:琾0+O,P$DX @G-n#[ )+Ve35۱-_B6hQVӻ{g>6E!xrˌ!z5X1zTGEQߦ,?f>?#[^olGQPAlC ((G#[z_~]KB'qxAP&~go?Ѭ.d.g&+0^8}vB^h|(5sN;g]wϪL<z\0O{'_r#7Xn#KBaw |J=-bh+SAMy0W#E#(f!X=T"q'%D=kG%Mob#[;?*Yh5K }#2(NY]N*pM\e|!m:v:G9bo1yl%جDârBF76TtaPt4,.b٭Yuu5[@(qh+h WP7U1Cw?a~jb/AzsAxXmrTHS֗N&@?!S [fmR[{oR??R#2#)_@
-#<==
diff --git a/wscript b/wscript
deleted file mode 100644
index 554b0036..00000000
--- a/wscript
+++ /dev/null
@@ -1,99 +0,0 @@
-#! /usr/bin/env python
-# encoding: utf-8
-# a1batross 2019
-
-from __future__ import print_function
-from waflib import Logs
-import sys
-import os
-
-sys.path.append(os.path.realpath('scripts/waflib'))
-# print(sys.path)
-
-VERSION = '0.99'
-APPNAME = 'xash3d-fwgs-android'
-top = '.'
-
-class Subproject:
- name = ''
- options = False # if true options() will be ignored
- ignore = False # if true will be ignored, set by user request
-
- def __init__(self, name, options = False):
- self.name = name
- self.options = options
-
-SUBDIRS = [
-# Subproject('xash3d-fwgs', True), # we set multiple hardcoded configurations, so ignore options
- Subproject('android')
-]
-
-def subdirs():
- return map(lambda x: x.name, SUBDIRS)
-
-def options(opt):
- grp = opt.add_option_group('Common options')
-
- grp.add_option('-T', '--build-type', action='store', dest='BUILD_TYPE', default = None,
- help = 'build type: debug, release or none(custom flags)')
-
- grp.add_option('-S', '--skip-subprojects', action='store', dest = 'SKIP_SUBDIRS', default=None,
- help = 'don\'t recurse into specified subprojects. Current subdirs: ' + str(subdirs()))
-
- for i in SUBDIRS:
- if not os.path.isfile(os.path.join(i.name, 'wscript')):
- # HACKHACK: this way we get warning message right in the help
- # so this just becomes more noticeable
- opt.add_option_group('Cannot find wscript in ' + i.name + '. You probably missed submodule update')
- continue
-
- if i.options:
- continue
-
- opt.recurse(i.name)
-
-def set_ignored_subdirs(subdirs):
- for i in SUBDIRS:
- if i.ignore:
- continue
-
- if i.name in subdirs:
- i.ignore = True
-
-def configure(conf):
- conf.start_msg('Build type')
- if conf.options.BUILD_TYPE == None:
- conf.end_msg('not set', color='RED')
- conf.fatal('Please set a build type, for example "--build-type=release"')
- elif not conf.options.BUILD_TYPE in ['release', 'debug', 'none']:
- conf.end_msg(conf.options.BUILD_TYPE, color='RED')
- conf.fatal('Invalid build type. Valid are "debug", "release" or "none"')
- conf.end_msg(conf.options.BUILD_TYPE)
-
- # skip some subdirectories, if requested
- if conf.options.SKIP_SUBDIRS:
- skip_subdirs = conf.options.SKIP_SUBDIRS.split(',')
- set_ignored_subdirs(skip_subdirs)
-
- for i in SUBDIRS:
- if i.ignore:
- continue
-
- conf.setenv(i.name, conf.env) # derive new env from global one
- conf.env.ENVNAME = i.name
- conf.msg(msg='--> ' + i.name, result='in progress', color='BLUE')
- # configure in standalone env
- conf.recurse(i.name)
- conf.msg(msg='<-- ' + i.name, result='done', color='BLUE')
- conf.setenv('')
-
-def build(bld):
- for i in SUBDIRS:
- if i.ignore:
- continue
-
- bld.load_envs()
- saveenv = bld.env
- bld.env = bld.all_envs[i.name]
- bld.recurse(i.name)
- bld.env = saveenv
diff --git a/xash-extras b/xash-extras
deleted file mode 160000
index 764735a3..00000000
--- a/xash-extras
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 764735a326bd4904e78eda8944c8142918fbf63d
diff --git a/xash3d-fwgs b/xash3d-fwgs
deleted file mode 160000
index ac213c22..00000000
--- a/xash3d-fwgs
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit ac213c22ed9cc1e7dd156da45dde7b460ce5fd8b