Browse Source

upload realtime ok

Fares 11 months ago
parent
commit
1c0f2e607d

+ 9 - 77
bin/main.dart

@@ -1,95 +1,27 @@
-import 'dart:io';
-import 'dart:convert';
 import 'package:shelf/shelf.dart';
 import 'package:shelf/shelf_io.dart' as shelf_io;
-import 'package:shelf_multipart/shelf_multipart.dart';
 import 'package:shelf_router/shelf_router.dart';
 
+import 'package:myshelf/handlers/greet_handler.dart';
+import 'package:myshelf/handlers/echo_handler.dart';
+import 'package:myshelf/handlers/upload_handler.dart';
+
 void main() async {
   // Create a router
   final router = Router();
 
   // Define routes
-  router.get('/greet', _handleGreet);
-  router.post('/echo', _handleEcho);
-  router.post('/upload', _handleFileUpload);
+  router.get('/greet', handleGreet);
+  router.post('/echo', handleEcho);
+  router.post('/upload', handleFileUpload);
 
   // Create a middleware pipeline
   final handler = const Pipeline()
       .addMiddleware(logRequests())
-      // .addMiddleware(_checkAuthorization())
-      .addHandler(router);
+      // .addMiddleware(checkAuthorization())
+      .addHandler(router.call);
 
   // Start the server
   final server = await shelf_io.serve(handler, 'localhost', 8080);
   print('Server listening on port ${server.port}');
 }
-
-// Handler for the /greet route with query parameters
-Response _handleGreet(Request request) {
-  final name = request.url.queryParameters['name'] ?? 'stranger';
-  return Response.ok('Hello, $name!');
-}
-
-// Handler for the /echo route that handles POST JSON body
-Future<Response> _handleEcho(Request request) async {
-  final payload = await request.readAsString();
-  final data = jsonDecode(payload) as Map;
-  return Response.ok(jsonEncode(data),
-      headers: {'Content-Type': 'application/json'});
-}
-
-// Handler for the /upload route that accepts file uploads
-Future<Response> _handleFileUpload(Request request) async {
-  final contentType = request.headers['content-type'];
-  if (contentType == null || !contentType.contains('multipart/form-data')) {
-    return Response(400, body: 'Unsupported content-type');
-  }
-
-  if (request.multipart() case var multipart?) {
-    // Iterate over parts making up this request:
-    List<String> uploadedFiles = [];
-    await for (final part in multipart.parts) {
-      // Headers are available through part.headers as a map:
-      final contentDisposition = part.headers['content-disposition'];
-      if (contentDisposition != null &&
-          contentDisposition.contains('filename=')) {
-        final name =
-            RegExp(r'name="([^"]*)"').firstMatch(contentDisposition)?.group(1);
-        final filename = RegExp(r'filename="([^"]*)"')
-            .firstMatch(contentDisposition)
-            ?.group(1);
-        if (name != null && filename != null) {
-          final file = File('uploads/$filename');
-          await file.create(recursive: true);
-          await part.pipe(file.openWrite());
-          uploadedFiles.add(filename);
-        }
-      }
-    }
-    if (uploadedFiles.isNotEmpty) {
-      return Response.ok('File(s) uploaded: $uploadedFiles');
-    }
-    {
-      return Response(400, body: 'Unsupported content-type');
-    }
-  } else {
-    return Response(401); // not a multipart request
-  }
-}
-
-// Custom middleware for authorization
-Middleware _checkAuthorization() {
-  return (Handler handler) {
-    return (Request request) async {
-      // Protect routes with authorization
-      if ((request.url.path.startsWith('greet') ||
-              request.url.path.startsWith('echo') ||
-              request.url.path.startsWith('upload')) &&
-          request.headers['Authorization'] != 'Bearer mysecrettoken') {
-        return Response.forbidden('Authorization header missing or invalid');
-      }
-      return handler(request);
-    };
-  };
-}

+ 11 - 0
lib/handlers/echo_handler.dart

@@ -0,0 +1,11 @@
+import 'dart:convert';
+import 'package:shelf/shelf.dart';
+
+Future<Response> handleEcho(Request request) async {
+  final payload = await request.readAsString();
+  final data = jsonDecode(payload) as Map;
+  return Response.ok(
+    jsonEncode(data),
+    headers: {'Content-Type': 'application/json'},
+  );
+}

+ 6 - 0
lib/handlers/greet_handler.dart

@@ -0,0 +1,6 @@
+import 'package:shelf/shelf.dart';
+
+Response handleGreet(Request request) {
+  final name = request.url.queryParameters['name'] ?? 'stranger';
+  return Response.ok('Hello, $name!');
+}

+ 189 - 0
lib/handlers/upload_handler.dart

@@ -0,0 +1,189 @@
+import 'dart:convert';
+import 'dart:io';
+import 'package:myshelf/models/data.dart';
+import 'package:shelf/shelf.dart';
+import 'package:shelf_multipart/shelf_multipart.dart';
+import 'package:supabase/supabase.dart';
+import 'package:archive/archive.dart';
+
+Future<Response> handleFileUpload(Request request) async {
+  // Check authorization
+  final authHeader = request.headers['authorization'];
+  if (authHeader == null || !authHeader.startsWith('Bearer ')) {
+    return Response.forbidden('Authorization header missing or invalid');
+  }
+  final token = authHeader.substring(7); // Remove 'Bearer ' prefix
+
+  // Initialize Supabase client with the bearer token
+  final supabase = SupabaseClient(
+    'http://baas.fares.cyou:8000',
+    token,
+  );
+
+  final contentType = request.headers['content-type'];
+  if (contentType == null || !contentType.contains('multipart/form-data')) {
+    return Response(400, body: 'Unsupported content-type');
+  }
+
+  if (request.multipart() case var multipart?) {
+    List<Map<String, dynamic>> uploadedFiles = [];
+    await for (final part in multipart.parts) {
+      final contentDisposition = part.headers['content-disposition'];
+      if (contentDisposition != null &&
+          contentDisposition.contains('filename=')) {
+        final name =
+            RegExp(r'name="([^"]*)"').firstMatch(contentDisposition)?.group(1);
+        final filename = RegExp(r'filename="([^"]*)"')
+            .firstMatch(contentDisposition)
+            ?.group(1);
+
+        if (name != null && filename != null) {
+          try {
+            // Create temporary file
+            final tempFile = File('uploads/$filename');
+            await tempFile.create(recursive: true);
+            await part.pipe(tempFile.openWrite());
+
+            // Upload to Supabase
+            final bytes = await tempFile.readAsBytes();
+            await supabase.storage.from('csvhich').uploadBinary(
+                  filename,
+                  bytes,
+                  fileOptions: FileOptions(
+                    upsert: true,
+                    contentType: part.headers['content-type'],
+                  ),
+                );
+
+            //insertline in csvhichupdates
+            await supabase.from('csvhichupdates').insert({
+              'filename': filename,
+              'updated_at': DateTime.now().toUtc().toIso8601String(),
+            });
+
+            //copy file to csvhich archive
+            final nowdt = DateTime.now().toUtc();
+            final now = nowdt.toIso8601String();
+            // final timestamp ='${nowdt.year}${nowdt.month.toString().padLeft(2, '0')}${nowdt.day.toString().padLeft(2, '0')}_${nowdt.hour.toString().padLeft(2, '0')}${nowdt.minute.toString().padLeft(2, '0')}';
+            final timestamp = nowdt.millisecondsSinceEpoch.toString();
+
+            //upload file to storage archive bucket
+            try {
+              final archiveFilename = 'upload/${timestamp}_$filename';
+              await supabase.storage.from('csvhich_archive').uploadBinary(
+                    archiveFilename,
+                    bytes,
+                    fileOptions: FileOptions(
+                      upsert: true,
+                      contentType: part.headers['content-type'],
+                    ),
+                  );
+            } catch (e) {
+              print('Error uploading to archive: $e');
+              // Continue execution even if archive upload fails
+            }
+
+            await processCsvFile(tempFile);
+
+            // No need to subscribe to channel
+            final channel = supabase.channel('csvhichstorage');
+            final res = await channel.sendBroadcastMessage(
+              event: "upload",
+              payload: {
+                "filename": filename,
+                "updated_at": now,
+              },
+            );
+            print("fileupload: realtime res: $res");
+
+            //add filename ta list
+            uploadedFiles.add({
+              'filename': filename,
+              'updated_at': now,
+            });
+
+            // Clean up temporary file
+            await tempFile.delete();
+          } catch (e) {
+            print('Error processing file: $e');
+            return Response.internalServerError(
+                body: 'Error processing file: ${e.toString()}');
+          }
+        }
+      }
+    }
+
+    if (uploadedFiles.isNotEmpty) {
+      return Response.ok(
+        '{"status": "success", "files": ${uploadedFiles.toString()}}',
+        headers: {'Content-Type': 'application/json'},
+      );
+    }
+
+    return Response(400, body: 'No files were uploaded');
+  } else {
+    return Response(401, body: 'Not a multipart request');
+  }
+}
+
+class FilesAsData {
+  String? filename;
+  String? updatedAt;
+  String data;
+  FilesAsData({
+    this.filename,
+    this.updatedAt,
+    required this.data,
+  });
+}
+
+processCsvFile(File tempfile) async {
+  List<FilesAsData> csvData = [];
+  final filename = tempfile.path.split('/').last;
+  final bytes = await tempfile.readAsBytes();
+  // Check if file is a zip archive
+  String? csvcontent;
+  if (filename.toLowerCase().endsWith('.zip')) {
+    final archive = ZipDecoder().decodeBytes(bytes);
+    for (final file in archive) {
+      if (!file.isFile) continue;
+
+      csvcontent = utf8.decode(file.content as List<int>);
+      csvData.add(FilesAsData(filename: file.name, data: csvcontent));
+    }
+  } else {
+    // For non-zip files, store in extracted folder
+    csvcontent = utf8.decode(bytes);
+    csvData.add(FilesAsData(filename: filename, data: csvcontent));
+  }
+
+// No need to subscribe to channel
+
+  print((csv2list(csvData!.first!.data!))
+      .map((e) => Pnleg.fromList(e))
+      .toList()
+      .first
+      .toMap()
+      .keys);
+
+  // print(
+  //     (csv2list(csvData!.first!.data!)).map((e) => Acleg.fromList(e)).toList());
+
+  //insert csv content to database
+  // List<List<dynamic>> csvData = [];
+  // if (csvcontent != null) {
+  //   List<String> lines = csvcontent.split('\n');
+  //   for (String line in lines) {
+  //     List<String> values = line.split(',');
+  //     csvData.add(values.map((value) {
+  //       String trimmedValue = value
+  //           .trim()
+  //           .replaceAll(RegExp(r'^"|"$'), '')
+  //           .replaceAll(RegExp(r'^ | $'), '')
+  //           .trim();
+  //       return trimmedValue.isEmpty ? null : trimmedValue;
+  //     }).toList());
+  //   }
+  //   print(csvData);
+  // }
+}

+ 15 - 0
lib/middleware/auth_middleware.dart

@@ -0,0 +1,15 @@
+import 'package:shelf/shelf.dart';
+
+Middleware checkAuthorization() {
+  return (Handler handler) {
+    return (Request request) async {
+      if ((request.url.path.startsWith('greet') ||
+              request.url.path.startsWith('echo') ||
+              request.url.path.startsWith('upload')) &&
+          request.headers['Authorization'] != 'Bearer mysecrettoken') {
+        return Response.forbidden('Authorization header missing or invalid');
+      }
+      return handler(request);
+    };
+  };
+}

+ 1081 - 0
lib/models/data.dart

@@ -0,0 +1,1081 @@
+import 'dart:convert';
+import 'package:jiffy/jiffy.dart';
+import 'package:myshelf/models/dtinterval.dart';
+
+List<List<dynamic>> csv2list(String text,
+    {bool nulling = true, bool quotes = true, bool trim = true}) {
+  List<List<dynamic>> out = [];
+  final lines = text.split("\n");
+  for (var line in lines) {
+    final cols = line.split(",").map((String? e) {
+      if (e != null && quotes) {
+        e = e.replaceAll('"', "");
+      }
+      if (e != null && trim) {
+        e = e.trim();
+      }
+      if (nulling) {
+        e = (e == "") ? null : e;
+      }
+      return e;
+    }).toList();
+    // print("${out.length}: $cols");
+    if (cols.isNotEmpty && cols.length > 1) out.add(cols);
+  }
+  return out;
+}
+
+class Qualif {
+  String? tlc;
+  String? lname;
+  String? mname;
+  String? fname;
+  String? date;
+  String? ac;
+  String? college;
+  String? base;
+  Qualif({
+    this.tlc,
+    this.lname,
+    this.mname,
+    this.fname,
+    this.date,
+    this.ac,
+    this.college,
+    this.base,
+  });
+
+  Qualif copyWith({
+    String? tlc,
+    String? lname,
+    String? mname,
+    String? fname,
+    String? date,
+    String? ac,
+    String? college,
+    String? base,
+  }) {
+    return Qualif(
+      tlc: tlc ?? this.tlc,
+      lname: lname ?? this.lname,
+      mname: mname ?? this.mname,
+      fname: fname ?? this.fname,
+      date: date ?? this.date,
+      ac: ac ?? this.ac,
+      college: college ?? this.college,
+      base: base ?? this.base,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return <String, dynamic>{
+      'tlc': tlc,
+      'lname': lname,
+      'mname': mname,
+      'fname': fname,
+      'date': date,
+      'ac': ac,
+      'college': college,
+      'base': base,
+    };
+  }
+
+  factory Qualif.fromList(List datalist) {
+    return Qualif(
+        tlc: datalist[0],
+        lname: datalist[1],
+        mname: datalist[2],
+        fname: datalist[3],
+        date: datalist[4],
+        ac: datalist[5],
+        college: datalist[6],
+        base: datalist[7]);
+  }
+
+  factory Qualif.fromMap(Map<String, dynamic> map) {
+    return Qualif(
+      tlc: map['tlc'] != null ? map['tlc'] as String : null,
+      lname: map['lname'] != null ? map['lname'] as String : null,
+      mname: map['mname'] != null ? map['mname'] as String : null,
+      fname: map['fname'] != null ? map['fname'] as String : null,
+      date: map['date'] != null ? map['date'] as String : null,
+      ac: map['ac'] != null ? map['ac'] as String : null,
+      college: map['college'] != null ? map['college'] as String : null,
+      base: map['base'] != null ? map['base'] as String : null,
+    );
+  }
+
+  String toJson() => json.encode(toMap());
+
+  factory Qualif.fromJson(String source) =>
+      Qualif.fromMap(json.decode(source) as Map<String, dynamic>);
+
+  @override
+  String toString() {
+    return 'Qualif(tlc: $tlc, lname: $lname, mname: $mname, fname: $fname, date: $date, ac: $ac, college: $college, base: $base)';
+  }
+
+  @override
+  bool operator ==(covariant Qualif other) {
+    if (identical(this, other)) return true;
+
+    return other.tlc == tlc &&
+        other.lname == lname &&
+        other.mname == mname &&
+        other.fname == fname &&
+        other.date == date &&
+        other.ac == ac &&
+        other.college == college &&
+        other.base == base;
+  }
+
+  @override
+  int get hashCode {
+    return tlc.hashCode ^
+        lname.hashCode ^
+        mname.hashCode ^
+        fname.hashCode ^
+        date.hashCode ^
+        ac.hashCode ^
+        college.hashCode ^
+        base.hashCode;
+  }
+}
+
+class Pnleg {
+  String? date;
+  Jiffy? get jdate => date != null
+      ? Jiffy.parse(date ?? "01/01/1970", pattern: "dd/MM/yyyy", isUtc: true)
+      : null;
+
+  String? tlc;
+  String? actype;
+  String? al;
+  String? fnum;
+  String? depdate;
+  String? deptime;
+  String? arrdate;
+  String? arrtime;
+  String? dep;
+  String? arr;
+  String? label;
+  String? type;
+  Jiffy? get jdep =>
+      deptime != null ? "$depdate $deptime".parseddmmyyyyhhmm() : null;
+  Jiffy? get jarr =>
+      arrtime != null ? "$arrdate $arrtime".parseddmmyyyyhhmm() : null;
+
+  String get dutytype {
+    if (type == "L") {
+      return "flight";
+    } else if ((type == "G")) {
+      return "dhlimo";
+    } else if ((type == "F") || ((dep ?? "") != "" && (arr ?? "") != "")) {
+      return "dhflight";
+    } else if ((label?.startsWith("SBY") ?? false) || (label == "R0")) {
+      return "standby";
+    } else if ((!["OFF", "CM", "CA", "PP"].contains(label)) &&
+        (jarr != null &&
+            jdep != null &&
+            DTInterval(jdep!, jarr!).duration.inHours < 18)) {
+      return "ground";
+    } else {
+      return "day";
+    }
+  }
+
+  Pnleg({
+    this.date,
+    this.tlc,
+    this.actype,
+    this.al,
+    this.fnum,
+    this.depdate,
+    this.deptime,
+    this.arrdate,
+    this.arrtime,
+    this.dep,
+    this.arr,
+    this.label,
+    this.type,
+  });
+
+  Pnleg copyWith({
+    String? date,
+    String? tlc,
+    String? actype,
+    String? al,
+    String? fnum,
+    String? depdate,
+    String? deptime,
+    String? arrdate,
+    String? arrtime,
+    String? dep,
+    String? arr,
+    String? label,
+    String? type,
+  }) {
+    return Pnleg(
+      date: date ?? this.date,
+      tlc: tlc ?? this.tlc,
+      actype: actype ?? this.actype,
+      al: al ?? this.al,
+      fnum: fnum ?? this.fnum,
+      depdate: depdate ?? this.depdate,
+      deptime: deptime ?? this.deptime,
+      arrdate: arrdate ?? this.arrdate,
+      arrtime: arrtime ?? this.arrtime,
+      dep: dep ?? this.dep,
+      arr: arr ?? this.arr,
+      label: label ?? this.label,
+      type: type ?? this.type,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return <String, dynamic>{
+      'date': date,
+      'tlc': tlc,
+      'actype': actype,
+      'al': al,
+      'fnum': fnum,
+      'depdate': depdate,
+      'deptime': deptime,
+      'arrdate': arrdate,
+      'arrtime': arrtime,
+      'dep': dep,
+      'arr': arr,
+      'label': label,
+      'type': type,
+    };
+  }
+
+  factory Pnleg.fromList(List datalist) {
+    return Pnleg(
+        date: datalist[0],
+        tlc: datalist[1],
+        actype: datalist[2],
+        al: datalist[3],
+        fnum: datalist[4],
+        depdate: datalist[5],
+        deptime: datalist[6],
+        arrdate: datalist[7],
+        arrtime: datalist[8],
+        dep: datalist[9],
+        arr: datalist[10],
+        label: datalist[11],
+        type: datalist[12]);
+  }
+
+  factory Pnleg.fromMap(Map<String, dynamic> map) {
+    return Pnleg(
+      date: map['date'] != null ? map['date'] as String : null,
+      tlc: map['tlc'] != null ? map['tlc'] as String : null,
+      actype: map['actype'] != null ? map['actype'] as String : null,
+      al: map['al'] != null ? map['al'] as String : null,
+      fnum: map['fnum'] != null ? map['fnum'] as String : null,
+      depdate: map['depdate'] != null ? map['depdate'] as String : null,
+      deptime: map['deptime'] != null ? map['deptime'] as String : null,
+      arrdate: map['arrdate'] != null ? map['arrdate'] as String : null,
+      arrtime: map['arrtime'] != null ? map['arrtime'] as String : null,
+      dep: map['dep'] != null ? map['dep'] as String : null,
+      arr: map['arr'] != null ? map['arr'] as String : null,
+      label: map['label'] != null ? map['label'] as String : null,
+      type: map['type'] != null ? map['type'] as String : null,
+    );
+  }
+
+  String toJson() => json.encode(toMap());
+
+  factory Pnleg.fromJson(String source) =>
+      Pnleg.fromMap(json.decode(source) as Map<String, dynamic>);
+
+  @override
+  String toString() {
+    return 'Pnleg(date: $date, tlc: $tlc, actype: $actype, al: $al, fnum: $fnum, depdate: $depdate, deptime: $deptime, arrdate: $arrdate, arrtime: $arrtime, dep: $dep, arr: $arr, label: $label, type: $type)';
+  }
+
+  @override
+  bool operator ==(covariant Pnleg other) {
+    if (identical(this, other)) return true;
+
+    return other.date == date &&
+        other.tlc == tlc &&
+        other.actype == actype &&
+        other.al == al &&
+        other.fnum == fnum &&
+        other.depdate == depdate &&
+        other.deptime == deptime &&
+        other.arrdate == arrdate &&
+        other.arrtime == arrtime &&
+        other.dep == dep &&
+        other.arr == arr &&
+        other.label == label &&
+        other.type == type;
+  }
+
+  @override
+  int get hashCode {
+    return date.hashCode ^
+        tlc.hashCode ^
+        actype.hashCode ^
+        al.hashCode ^
+        fnum.hashCode ^
+        depdate.hashCode ^
+        deptime.hashCode ^
+        arrdate.hashCode ^
+        arrtime.hashCode ^
+        dep.hashCode ^
+        arr.hashCode ^
+        label.hashCode ^
+        type.hashCode;
+  }
+}
+
+//enum flt_status { sched, delayed, taxiout, enroute, landed, arrived }
+
+class Acleg {
+  String? LEG_NO;
+  String? FN_CARRIER;
+  String? FN_NUMBER;
+  String? FN_SUFFIX;
+  String? DAY_OF_ORIGIN;
+  String? AC_OWNER;
+  String? AC_SUBTYPE;
+  String? AC_VERSION;
+  String? AC_REGISTRATION;
+  String? DEP_AP_ACTUAL;
+  String? DEP_AP_SCHED;
+  String? DEP_DT_EST;
+  Jiffy? get jdepest =>
+      (DEP_DT_EST == null) ? null : DEP_DT_EST!.parseyyyymmddhhmm();
+  String? DEP_SCHED_DT;
+  Jiffy? get jdepsched =>
+      (DEP_SCHED_DT == null) ? null : DEP_SCHED_DT!.parseyyyymmddhhmm();
+  String? ARR_AP_ACTUAL;
+  String? ARR_AP_SCHED;
+  String? ARR_DT_EST;
+  Jiffy? get jarrest =>
+      (ARR_DT_EST == null) ? null : ARR_DT_EST!.parseyyyymmddhhmm();
+  String? ARR_SCHED_DT;
+  Jiffy? get jarrsched =>
+      (ARR_SCHED_DT == null) ? null : ARR_SCHED_DT!.parseyyyymmddhhmm();
+  String? SLOT_TIME_ACTUAL;
+  Jiffy? get slot =>
+      (SLOT_TIME_ACTUAL == null) ? null : SLOT_TIME_ACTUAL!.parseyyyymmddhhmm();
+  String? LEG_TYPE;
+  String? STATUS;
+  String? EMPLOYER_COCKPIT;
+  String? EMPLOYER_CABIN;
+  String? CYCLES;
+  String? DELAY_CODE_01;
+  String? DELAY_CODE_02;
+  String? DELAY_CODE_03;
+  String? DELAY_CODE_04;
+  String? DELAY_TIME_01;
+  String? DELAY_TIME_02;
+  String? DELAY_TIME_03;
+  String? DELAY_TIME_04;
+  String? SUBDELAY_CODE_01;
+  String? SUBDELAY_CODE_02;
+  String? SUBDELAY_CODE_03;
+  String? SUBDELAY_CODE_04;
+  List<List> get dla => [
+        [
+          SUBDELAY_CODE_01 ?? DELAY_CODE_01,
+          DELAY_TIME_01 == null
+              ? null
+              : Duration(minutes: int.parse(DELAY_TIME_01!))
+        ],
+        [
+          SUBDELAY_CODE_02 ?? DELAY_CODE_02,
+          DELAY_TIME_02 == null
+              ? null
+              : Duration(minutes: int.parse(DELAY_TIME_02!))
+        ],
+        [
+          SUBDELAY_CODE_03 ?? DELAY_CODE_03,
+          DELAY_TIME_03 == null
+              ? null
+              : Duration(minutes: int.parse(DELAY_TIME_03!))
+        ],
+        [
+          SUBDELAY_CODE_04 ?? DELAY_CODE_04,
+          DELAY_TIME_04 == null
+              ? null
+              : Duration(minutes: int.parse(DELAY_TIME_04!))
+        ],
+      ].where((e) => e.every((f) => f != null)).toList();
+  List<String> get delaycode => [
+        DELAY_CODE_01,
+        DELAY_CODE_02,
+        DELAY_CODE_03,
+        DELAY_CODE_04
+      ].nonNulls.toList();
+  List<String> get delaysubcode => [
+        SUBDELAY_CODE_01,
+        SUBDELAY_CODE_02,
+        SUBDELAY_CODE_03,
+        SUBDELAY_CODE_04
+      ].nonNulls.toList();
+  List<Duration?> get delaytime => [
+        DELAY_TIME_01 == null
+            ? null
+            : Duration(minutes: int.parse(DELAY_TIME_01!)),
+        DELAY_TIME_02 == null
+            ? null
+            : Duration(minutes: int.parse(DELAY_TIME_02!)),
+        DELAY_TIME_03 == null
+            ? null
+            : Duration(minutes: int.parse(DELAY_TIME_03!)),
+        DELAY_TIME_04 == null
+            ? null
+            : Duration(minutes: int.parse(DELAY_TIME_04!))
+      ].nonNulls.toList();
+
+  String? PAX_BOOKED_C;
+  String? PAX_BOOKED_Y;
+  String? get pax_booked => (PAX_BOOKED_C != null || PAX_BOOKED_Y != null)
+      ? "${(AC_VERSION != null && AC_VERSION!.contains("C")) ? "C${PAX_BOOKED_C ?? 0}." : ""}Y${PAX_BOOKED_Y ?? 0}"
+      : null;
+  String? PAX_BOOKED_TRS_C;
+  String? PAX_BOOKED_TRS_Y;
+  String? get pax_trs => (PAX_BOOKED_TRS_C != null || PAX_BOOKED_TRS_Y != null)
+      ? "C${PAX_BOOKED_TRS_C ?? 0}/Y${PAX_BOOKED_TRS_Y ?? 0}"
+      : null;
+  String? PAD_BOOKED_C;
+  String? PAD_BOOKED_Y;
+  String? get pad_booked => (PAD_BOOKED_C != null || PAD_BOOKED_Y != null)
+      ? "C${PAD_BOOKED_C ?? 0}/Y${PAD_BOOKED_Y ?? 0}"
+      : null;
+  String? OFFBLOCK_DT_A;
+  String? AIRBORNE_DT_A;
+  String? LANDING_DT_A;
+  String? ONBLOCK_DT_A;
+  List<Jiffy?> get blocks_a => [
+        (OFFBLOCK_DT_A ?? "").parseyyyymmddhhmm(),
+        (AIRBORNE_DT_A ?? "").parseyyyymmddhhmm(),
+        (LANDING_DT_A ?? "").parseyyyymmddhhmm(),
+        (ONBLOCK_DT_A ?? "").parseyyyymmddhhmm()
+      ];
+  String get flt_status {
+    if (blocks[3] != null) {
+      return "Arrived";
+    } else if (blocks[2] != null) {
+      return "Landed";
+    } else if (blocks[1] != null) {
+      return "Inflight";
+    } else if (blocks[0] != null) {
+      return "Taxiout";
+    } else if (jdepest != null &&
+        jarrsched != null &&
+        jdepest!.isAfter(jdepsched!)) {
+      return "Delayed";
+    } else {
+      return "Sched";
+    }
+  }
+
+  String? OFFBLOCK_DT_F;
+  String? AIRBORNE_DT_F;
+  String? LANDING_DT_F;
+  String? ONBLOCK_DT_F;
+  List<Jiffy?> get blocks_f => [
+        (OFFBLOCK_DT_F ?? "").parseyyyymmddhhmm(),
+        (AIRBORNE_DT_F ?? "").parseyyyymmddhhmm(),
+        (LANDING_DT_F ?? "").parseyyyymmddhhmm(),
+        (ONBLOCK_DT_F ?? "").parseyyyymmddhhmm()
+      ];
+
+  String? OFFBLOCK_DT_M;
+  String? AIRBORNE_DT_M;
+  String? LANDING_DT_M;
+  String? ONBLOCK_DT_M;
+  List<Jiffy?> get blocks_m => [
+        (OFFBLOCK_DT_M ?? "").parseyyyymmddhhmm(),
+        (AIRBORNE_DT_M ?? "").parseyyyymmddhhmm(),
+        (LANDING_DT_M ?? "").parseyyyymmddhhmm(),
+        (ONBLOCK_DT_M ?? "").parseyyyymmddhhmm()
+      ];
+  List<Jiffy?> get blocks => [
+        blocks_m[0] ?? blocks_a[0] ?? blocks_f[0],
+        blocks_m[1] ?? blocks_a[1] ?? blocks_f[1],
+        blocks_m[2] ?? blocks_a[2] ?? blocks_f[2],
+        blocks_m[3] ?? blocks_a[3] ?? blocks_f[3]
+      ];
+  Jiffy? get jdep => blocks[0] ?? jdepest ?? jdepsched;
+  Jiffy? get jarr =>
+      blocks[3] ??
+      blocks[2]?.add(minutes: 5) ??
+      (eet == null ? null : blocks[1]?.addDuration(eet!).add(minutes: 8)) ??
+      (eet == null
+          ? null
+          : blocks[0]?.add(minutes: 5).addDuration(eet!).add(minutes: 8)) ??
+      (eet == null
+          ? null
+          : jdep?.addDuration(eet!).add(minutes: 8).add(minutes: 5)) ??
+      jarrest ??
+      jarrsched;
+  String? EET;
+  Duration? get eet => EET == null ? null : Duration(minutes: int.parse(EET!));
+  Acleg({
+    this.LEG_NO,
+    this.FN_CARRIER,
+    this.FN_NUMBER,
+    this.FN_SUFFIX,
+    this.DAY_OF_ORIGIN,
+    this.AC_OWNER,
+    this.AC_SUBTYPE,
+    this.AC_VERSION,
+    this.AC_REGISTRATION,
+    this.DEP_AP_ACTUAL,
+    this.DEP_AP_SCHED,
+    this.DEP_DT_EST,
+    this.DEP_SCHED_DT,
+    this.ARR_AP_ACTUAL,
+    this.ARR_AP_SCHED,
+    this.ARR_DT_EST,
+    this.ARR_SCHED_DT,
+    this.SLOT_TIME_ACTUAL,
+    this.LEG_TYPE,
+    this.STATUS,
+    this.EMPLOYER_COCKPIT,
+    this.EMPLOYER_CABIN,
+    this.CYCLES,
+    this.DELAY_CODE_01,
+    this.DELAY_CODE_02,
+    this.DELAY_CODE_03,
+    this.DELAY_CODE_04,
+    this.DELAY_TIME_01,
+    this.DELAY_TIME_02,
+    this.DELAY_TIME_03,
+    this.DELAY_TIME_04,
+    this.SUBDELAY_CODE_01,
+    this.SUBDELAY_CODE_02,
+    this.SUBDELAY_CODE_03,
+    this.SUBDELAY_CODE_04,
+    this.PAX_BOOKED_C,
+    this.PAX_BOOKED_Y,
+    this.PAX_BOOKED_TRS_C,
+    this.PAX_BOOKED_TRS_Y,
+    this.PAD_BOOKED_C,
+    this.PAD_BOOKED_Y,
+    this.OFFBLOCK_DT_A,
+    this.AIRBORNE_DT_A,
+    this.LANDING_DT_A,
+    this.ONBLOCK_DT_A,
+    this.OFFBLOCK_DT_F,
+    this.AIRBORNE_DT_F,
+    this.LANDING_DT_F,
+    this.ONBLOCK_DT_F,
+    this.OFFBLOCK_DT_M,
+    this.AIRBORNE_DT_M,
+    this.LANDING_DT_M,
+    this.ONBLOCK_DT_M,
+    this.EET,
+  });
+
+  Acleg copyWith({
+    String? LEG_NO,
+    String? FN_CARRIER,
+    String? FN_NUMBER,
+    String? FN_SUFFIX,
+    String? DAY_OF_ORIGIN,
+    String? AC_OWNER,
+    String? AC_SUBTYPE,
+    String? AC_VERSION,
+    String? AC_REGISTRATION,
+    String? DEP_AP_ACTUAL,
+    String? DEP_AP_SCHED,
+    String? DEP_DT_EST,
+    String? DEP_SCHED_DT,
+    String? ARR_AP_ACTUAL,
+    String? ARR_AP_SCHED,
+    String? ARR_DT_EST,
+    String? ARR_SCHED_DT,
+    String? SLOT_TIME_ACTUAL,
+    String? LEG_TYPE,
+    String? STATUS,
+    String? EMPLOYER_COCKPIT,
+    String? EMPLOYER_CABIN,
+    String? CYCLES,
+    String? DELAY_CODE_01,
+    String? DELAY_CODE_02,
+    String? DELAY_CODE_03,
+    String? DELAY_CODE_04,
+    String? DELAY_TIME_01,
+    String? DELAY_TIME_02,
+    String? DELAY_TIME_03,
+    String? DELAY_TIME_04,
+    String? SUBDELAY_CODE_01,
+    String? SUBDELAY_CODE_02,
+    String? SUBDELAY_CODE_03,
+    String? SUBDELAY_CODE_04,
+    String? PAX_BOOKED_C,
+    String? PAX_BOOKED_Y,
+    String? PAX_BOOKED_TRS_C,
+    String? PAX_BOOKED_TRS_Y,
+    String? PAD_BOOKED_C,
+    String? PAD_BOOKED_Y,
+    String? OFFBLOCK_DT_A,
+    String? AIRBORNE_DT_A,
+    String? LANDING_DT_A,
+    String? ONBLOCK_DT_A,
+    String? OFFBLOCK_DT_F,
+    String? AIRBORNE_DT_F,
+    String? LANDING_DT_F,
+    String? ONBLOCK_DT_F,
+    String? OFFBLOCK_DT_M,
+    String? AIRBORNE_DT_M,
+    String? LANDING_DT_M,
+    String? ONBLOCK_DT_M,
+    String? EET,
+  }) {
+    return Acleg(
+      LEG_NO: LEG_NO ?? this.LEG_NO,
+      FN_CARRIER: FN_CARRIER ?? this.FN_CARRIER,
+      FN_NUMBER: FN_NUMBER ?? this.FN_NUMBER,
+      FN_SUFFIX: FN_SUFFIX ?? this.FN_SUFFIX,
+      DAY_OF_ORIGIN: DAY_OF_ORIGIN ?? this.DAY_OF_ORIGIN,
+      AC_OWNER: AC_OWNER ?? this.AC_OWNER,
+      AC_SUBTYPE: AC_SUBTYPE ?? this.AC_SUBTYPE,
+      AC_VERSION: AC_VERSION ?? this.AC_VERSION,
+      AC_REGISTRATION: AC_REGISTRATION ?? this.AC_REGISTRATION,
+      DEP_AP_ACTUAL: DEP_AP_ACTUAL ?? this.DEP_AP_ACTUAL,
+      DEP_AP_SCHED: DEP_AP_SCHED ?? this.DEP_AP_SCHED,
+      DEP_DT_EST: DEP_DT_EST ?? this.DEP_DT_EST,
+      DEP_SCHED_DT: DEP_SCHED_DT ?? this.DEP_SCHED_DT,
+      ARR_AP_ACTUAL: ARR_AP_ACTUAL ?? this.ARR_AP_ACTUAL,
+      ARR_AP_SCHED: ARR_AP_SCHED ?? this.ARR_AP_SCHED,
+      ARR_DT_EST: ARR_DT_EST ?? this.ARR_DT_EST,
+      ARR_SCHED_DT: ARR_SCHED_DT ?? this.ARR_SCHED_DT,
+      SLOT_TIME_ACTUAL: SLOT_TIME_ACTUAL ?? this.SLOT_TIME_ACTUAL,
+      LEG_TYPE: LEG_TYPE ?? this.LEG_TYPE,
+      STATUS: STATUS ?? this.STATUS,
+      EMPLOYER_COCKPIT: EMPLOYER_COCKPIT ?? this.EMPLOYER_COCKPIT,
+      EMPLOYER_CABIN: EMPLOYER_CABIN ?? this.EMPLOYER_CABIN,
+      CYCLES: CYCLES ?? this.CYCLES,
+      DELAY_CODE_01: DELAY_CODE_01 ?? this.DELAY_CODE_01,
+      DELAY_CODE_02: DELAY_CODE_02 ?? this.DELAY_CODE_02,
+      DELAY_CODE_03: DELAY_CODE_03 ?? this.DELAY_CODE_03,
+      DELAY_CODE_04: DELAY_CODE_04 ?? this.DELAY_CODE_04,
+      DELAY_TIME_01: DELAY_TIME_01 ?? this.DELAY_TIME_01,
+      DELAY_TIME_02: DELAY_TIME_02 ?? this.DELAY_TIME_02,
+      DELAY_TIME_03: DELAY_TIME_03 ?? this.DELAY_TIME_03,
+      DELAY_TIME_04: DELAY_TIME_04 ?? this.DELAY_TIME_04,
+      SUBDELAY_CODE_01: SUBDELAY_CODE_01 ?? this.SUBDELAY_CODE_01,
+      SUBDELAY_CODE_02: SUBDELAY_CODE_02 ?? this.SUBDELAY_CODE_02,
+      SUBDELAY_CODE_03: SUBDELAY_CODE_03 ?? this.SUBDELAY_CODE_03,
+      SUBDELAY_CODE_04: SUBDELAY_CODE_04 ?? this.SUBDELAY_CODE_04,
+      PAX_BOOKED_C: PAX_BOOKED_C ?? this.PAX_BOOKED_C,
+      PAX_BOOKED_Y: PAX_BOOKED_Y ?? this.PAX_BOOKED_Y,
+      PAX_BOOKED_TRS_C: PAX_BOOKED_TRS_C ?? this.PAX_BOOKED_TRS_C,
+      PAX_BOOKED_TRS_Y: PAX_BOOKED_TRS_Y ?? this.PAX_BOOKED_TRS_Y,
+      PAD_BOOKED_C: PAD_BOOKED_C ?? this.PAD_BOOKED_C,
+      PAD_BOOKED_Y: PAD_BOOKED_Y ?? this.PAD_BOOKED_Y,
+      OFFBLOCK_DT_A: OFFBLOCK_DT_A ?? this.OFFBLOCK_DT_A,
+      AIRBORNE_DT_A: AIRBORNE_DT_A ?? this.AIRBORNE_DT_A,
+      LANDING_DT_A: LANDING_DT_A ?? this.LANDING_DT_A,
+      ONBLOCK_DT_A: ONBLOCK_DT_A ?? this.ONBLOCK_DT_A,
+      OFFBLOCK_DT_F: OFFBLOCK_DT_F ?? this.OFFBLOCK_DT_F,
+      AIRBORNE_DT_F: AIRBORNE_DT_F ?? this.AIRBORNE_DT_F,
+      LANDING_DT_F: LANDING_DT_F ?? this.LANDING_DT_F,
+      ONBLOCK_DT_F: ONBLOCK_DT_F ?? this.ONBLOCK_DT_F,
+      OFFBLOCK_DT_M: OFFBLOCK_DT_M ?? this.OFFBLOCK_DT_M,
+      AIRBORNE_DT_M: AIRBORNE_DT_M ?? this.AIRBORNE_DT_M,
+      LANDING_DT_M: LANDING_DT_M ?? this.LANDING_DT_M,
+      ONBLOCK_DT_M: ONBLOCK_DT_M ?? this.ONBLOCK_DT_M,
+      EET: EET ?? this.EET,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return <String, dynamic>{
+      'LEG_NO': LEG_NO,
+      'FN_CARRIER': FN_CARRIER,
+      'FN_NUMBER': FN_NUMBER,
+      'FN_SUFFIX': FN_SUFFIX,
+      'DAY_OF_ORIGIN': DAY_OF_ORIGIN,
+      'AC_OWNER': AC_OWNER,
+      'AC_SUBTYPE': AC_SUBTYPE,
+      'AC_VERSION': AC_VERSION,
+      'AC_REGISTRATION': AC_REGISTRATION,
+      'DEP_AP_ACTUAL': DEP_AP_ACTUAL,
+      'DEP_AP_SCHED': DEP_AP_SCHED,
+      'DEP_DT_EST': DEP_DT_EST,
+      'DEP_SCHED_DT': DEP_SCHED_DT,
+      'ARR_AP_ACTUAL': ARR_AP_ACTUAL,
+      'ARR_AP_SCHED': ARR_AP_SCHED,
+      'ARR_DT_EST': ARR_DT_EST,
+      'ARR_SCHED_DT': ARR_SCHED_DT,
+      'SLOT_TIME_ACTUAL': SLOT_TIME_ACTUAL,
+      'LEG_TYPE': LEG_TYPE,
+      'STATUS': STATUS,
+      'EMPLOYER_COCKPIT': EMPLOYER_COCKPIT,
+      'EMPLOYER_CABIN': EMPLOYER_CABIN,
+      'CYCLES': CYCLES,
+      'DELAY_CODE_01': DELAY_CODE_01,
+      'DELAY_CODE_02': DELAY_CODE_02,
+      'DELAY_CODE_03': DELAY_CODE_03,
+      'DELAY_CODE_04': DELAY_CODE_04,
+      'DELAY_TIME_01': DELAY_TIME_01,
+      'DELAY_TIME_02': DELAY_TIME_02,
+      'DELAY_TIME_03': DELAY_TIME_03,
+      'DELAY_TIME_04': DELAY_TIME_04,
+      'SUBDELAY_CODE_01': SUBDELAY_CODE_01,
+      'SUBDELAY_CODE_02': SUBDELAY_CODE_02,
+      'SUBDELAY_CODE_03': SUBDELAY_CODE_03,
+      'SUBDELAY_CODE_04': SUBDELAY_CODE_04,
+      'PAX_BOOKED_C': PAX_BOOKED_C,
+      'PAX_BOOKED_Y': PAX_BOOKED_Y,
+      'PAX_BOOKED_TRS_C': PAX_BOOKED_TRS_C,
+      'PAX_BOOKED_TRS_Y': PAX_BOOKED_TRS_Y,
+      'PAD_BOOKED_C': PAD_BOOKED_C,
+      'PAD_BOOKED_Y': PAD_BOOKED_Y,
+      'OFFBLOCK_DT_A': OFFBLOCK_DT_A,
+      'AIRBORNE_DT_A': AIRBORNE_DT_A,
+      'LANDING_DT_A': LANDING_DT_A,
+      'ONBLOCK_DT_A': ONBLOCK_DT_A,
+      'OFFBLOCK_DT_F': OFFBLOCK_DT_F,
+      'AIRBORNE_DT_F': AIRBORNE_DT_F,
+      'LANDING_DT_F': LANDING_DT_F,
+      'ONBLOCK_DT_F': ONBLOCK_DT_F,
+      'OFFBLOCK_DT_M': OFFBLOCK_DT_M,
+      'AIRBORNE_DT_M': AIRBORNE_DT_M,
+      'LANDING_DT_M': LANDING_DT_M,
+      'ONBLOCK_DT_M': ONBLOCK_DT_M,
+      'EET': EET,
+    };
+  }
+
+  factory Acleg.fromList(List datalist) {
+    //print(datalist);
+    if (datalist.length >= 54) {
+      return Acleg(
+          LEG_NO: datalist[0],
+          FN_CARRIER: datalist[1],
+          FN_NUMBER: datalist[2],
+          FN_SUFFIX: datalist[3],
+          DAY_OF_ORIGIN: datalist[4],
+          AC_OWNER: datalist[5],
+          AC_SUBTYPE: datalist[6],
+          AC_VERSION: datalist[7],
+          AC_REGISTRATION: datalist[8],
+          DEP_AP_ACTUAL: datalist[9],
+          DEP_AP_SCHED: datalist[10],
+          DEP_DT_EST: datalist[11],
+          DEP_SCHED_DT: datalist[12],
+          ARR_AP_ACTUAL: datalist[13],
+          ARR_AP_SCHED: datalist[14],
+          ARR_DT_EST: datalist[15],
+          ARR_SCHED_DT: datalist[16],
+          SLOT_TIME_ACTUAL: datalist[17],
+          LEG_TYPE: datalist[18],
+          STATUS: datalist[19],
+          EMPLOYER_COCKPIT: datalist[20],
+          EMPLOYER_CABIN: datalist[21],
+          CYCLES: datalist[22],
+          DELAY_CODE_01: datalist[23],
+          DELAY_CODE_02: datalist[24],
+          DELAY_CODE_03: datalist[25],
+          DELAY_CODE_04: datalist[26],
+          DELAY_TIME_01: datalist[27],
+          DELAY_TIME_02: datalist[28],
+          DELAY_TIME_03: datalist[29],
+          DELAY_TIME_04: datalist[30],
+          SUBDELAY_CODE_01: datalist[31],
+          SUBDELAY_CODE_02: datalist[32],
+          SUBDELAY_CODE_03: datalist[33],
+          SUBDELAY_CODE_04: datalist[34],
+          PAX_BOOKED_C: datalist[35],
+          PAX_BOOKED_Y: datalist[36],
+          PAX_BOOKED_TRS_C: datalist[37],
+          PAX_BOOKED_TRS_Y: datalist[38],
+          PAD_BOOKED_C: datalist[39],
+          PAD_BOOKED_Y: datalist[40],
+          OFFBLOCK_DT_A: datalist[41],
+          AIRBORNE_DT_A: datalist[42],
+          LANDING_DT_A: datalist[43],
+          ONBLOCK_DT_A: datalist[44],
+          OFFBLOCK_DT_F: datalist[45],
+          AIRBORNE_DT_F: datalist[46],
+          LANDING_DT_F: datalist[47],
+          ONBLOCK_DT_F: datalist[48],
+          OFFBLOCK_DT_M: datalist[49],
+          AIRBORNE_DT_M: datalist[50],
+          LANDING_DT_M: datalist[51],
+          ONBLOCK_DT_M: datalist[52],
+          EET: datalist[53]);
+    } else {
+      return Acleg();
+    }
+  }
+
+  factory Acleg.fromMap(Map<String, dynamic> map) {
+    return Acleg(
+      LEG_NO: map['LEG_NO'] != null ? map['LEG_NO'] as String : null,
+      FN_CARRIER:
+          map['FN_CARRIER'] != null ? map['FN_CARRIER'] as String : null,
+      FN_NUMBER: map['FN_NUMBER'] != null ? map['FN_NUMBER'] as String : null,
+      FN_SUFFIX: map['FN_SUFFIX'] != null ? map['FN_SUFFIX'] as String : null,
+      DAY_OF_ORIGIN:
+          map['DAY_OF_ORIGIN'] != null ? map['DAY_OF_ORIGIN'] as String : null,
+      AC_OWNER: map['AC_OWNER'] != null ? map['AC_OWNER'] as String : null,
+      AC_SUBTYPE:
+          map['AC_SUBTYPE'] != null ? map['AC_SUBTYPE'] as String : null,
+      AC_VERSION:
+          map['AC_VERSION'] != null ? map['AC_VERSION'] as String : null,
+      AC_REGISTRATION: map['AC_REGISTRATION'] != null
+          ? map['AC_REGISTRATION'] as String
+          : null,
+      DEP_AP_ACTUAL:
+          map['DEP_AP_ACTUAL'] != null ? map['DEP_AP_ACTUAL'] as String : null,
+      DEP_AP_SCHED:
+          map['DEP_AP_SCHED'] != null ? map['DEP_AP_SCHED'] as String : null,
+      DEP_DT_EST:
+          map['DEP_DT_EST'] != null ? map['DEP_DT_EST'] as String : null,
+      DEP_SCHED_DT:
+          map['DEP_SCHED_DT'] != null ? map['DEP_SCHED_DT'] as String : null,
+      ARR_AP_ACTUAL:
+          map['ARR_AP_ACTUAL'] != null ? map['ARR_AP_ACTUAL'] as String : null,
+      ARR_AP_SCHED:
+          map['ARR_AP_SCHED'] != null ? map['ARR_AP_SCHED'] as String : null,
+      ARR_DT_EST:
+          map['ARR_DT_EST'] != null ? map['ARR_DT_EST'] as String : null,
+      ARR_SCHED_DT:
+          map['ARR_SCHED_DT'] != null ? map['ARR_SCHED_DT'] as String : null,
+      SLOT_TIME_ACTUAL: map['SLOT_TIME_ACTUAL'] != null
+          ? map['SLOT_TIME_ACTUAL'] as String
+          : null,
+      LEG_TYPE: map['LEG_TYPE'] != null ? map['LEG_TYPE'] as String : null,
+      EMPLOYER_COCKPIT: map['EMPLOYER_COCKPIT'] != null
+          ? map['EMPLOYER_COCKPIT'] as String
+          : null,
+      EMPLOYER_CABIN: map['EMPLOYER_CABIN'] != null
+          ? map['EMPLOYER_CABIN'] as String
+          : null,
+//      CYCLES: map['CYCLES'] != null ? map['CYCLES'] as String : null,
+      DELAY_CODE_01:
+          map['DELAY_CODE_01'] != null ? map['DELAY_CODE_01'] as String : null,
+      DELAY_CODE_02:
+          map['DELAY_CODE_02'] != null ? map['DELAY_CODE_02'] as String : null,
+      DELAY_CODE_03:
+          map['DELAY_CODE_03'] != null ? map['DELAY_CODE_03'] as String : null,
+      DELAY_CODE_04:
+          map['DELAY_CODE_04'] != null ? map['DELAY_CODE_04'] as String : null,
+      DELAY_TIME_01:
+          map['DELAY_TIME_01'] != null ? map['DELAY_TIME_01'] as String : null,
+      DELAY_TIME_02:
+          map['DELAY_TIME_02'] != null ? map['DELAY_TIME_02'] as String : null,
+      DELAY_TIME_03:
+          map['DELAY_TIME_03'] != null ? map['DELAY_TIME_03'] as String : null,
+      DELAY_TIME_04:
+          map['DELAY_TIME_04'] != null ? map['DELAY_TIME_04'] as String : null,
+      SUBDELAY_CODE_01: map['SUBDELAY_CODE_01'] != null
+          ? map['SUBDELAY_CODE_01'] as String
+          : null,
+      SUBDELAY_CODE_02: map['SUBDELAY_CODE_02'] != null
+          ? map['SUBDELAY_CODE_02'] as String
+          : null,
+      SUBDELAY_CODE_03: map['SUBDELAY_CODE_03'] != null
+          ? map['SUBDELAY_CODE_03'] as String
+          : null,
+      SUBDELAY_CODE_04: map['SUBDELAY_CODE_04'] != null
+          ? map['SUBDELAY_CODE_04'] as String
+          : null,
+      PAX_BOOKED_C:
+          map['PAX_BOOKED_C'] != null ? map['PAX_BOOKED_C'] as String : null,
+      PAX_BOOKED_Y:
+          map['PAX_BOOKED_Y'] != null ? map['PAX_BOOKED_Y'] as String : null,
+      PAX_BOOKED_TRS_C: map['PAX_BOOKED_TRS_C'] != null
+          ? map['PAX_BOOKED_TRS_C'] as String
+          : null,
+      PAX_BOOKED_TRS_Y: map['PAX_BOOKED_TRS_Y'] != null
+          ? map['PAX_BOOKED_TRS_Y'] as String
+          : null,
+      PAD_BOOKED_C:
+          map['PAD_BOOKED_C'] != null ? map['PAD_BOOKED_C'] as String : null,
+      PAD_BOOKED_Y:
+          map['PAD_BOOKED_Y'] != null ? map['PAD_BOOKED_Y'] as String : null,
+      OFFBLOCK_DT_A:
+          map['OFFBLOCK_DT_A'] != null ? map['OFFBLOCK_DT_A'] as String : null,
+      AIRBORNE_DT_A:
+          map['AIRBORNE_DT_A'] != null ? map['AIRBORNE_DT_A'] as String : null,
+      LANDING_DT_A:
+          map['LANDING_DT_A'] != null ? map['LANDING_DT_A'] as String : null,
+      ONBLOCK_DT_A:
+          map['ONBLOCK_DT_A'] != null ? map['ONBLOCK_DT_A'] as String : null,
+      OFFBLOCK_DT_F:
+          map['OFFBLOCK_DT_F'] != null ? map['OFFBLOCK_DT_F'] as String : null,
+      AIRBORNE_DT_F:
+          map['AIRBORNE_DT_F'] != null ? map['AIRBORNE_DT_F'] as String : null,
+      LANDING_DT_F:
+          map['LANDING_DT_F'] != null ? map['LANDING_DT_F'] as String : null,
+      ONBLOCK_DT_F:
+          map['ONBLOCK_DT_F'] != null ? map['ONBLOCK_DT_F'] as String : null,
+      OFFBLOCK_DT_M:
+          map['OFFBLOCK_DT_M'] != null ? map['OFFBLOCK_DT_M'] as String : null,
+      AIRBORNE_DT_M:
+          map['AIRBORNE_DT_M'] != null ? map['AIRBORNE_DT_M'] as String : null,
+      LANDING_DT_M:
+          map['LANDING_DT_M'] != null ? map['LANDING_DT_M'] as String : null,
+      ONBLOCK_DT_M:
+          map['ONBLOCK_DT_M'] != null ? map['ONBLOCK_DT_M'] as String : null,
+      EET: map['EET'] != null ? map['EET'] as String : null,
+    );
+  }
+
+  String toJson() => json.encode(toMap());
+
+  factory Acleg.fromJson(String source) =>
+      Acleg.fromMap(json.decode(source) as Map<String, dynamic>);
+
+  @override
+  String toString() {
+    return 'Acleg(LEG_NO: $LEG_NO, FN_CARRIER: $FN_CARRIER, FN_NUMBER: $FN_NUMBER, FN_SUFFIX: $FN_SUFFIX, DAY_OF_ORIGIN: $DAY_OF_ORIGIN, AC_OWNER: $AC_OWNER, AC_SUBTYPE: $AC_SUBTYPE, AC_VERSION: $AC_VERSION, AC_REGISTRATION: $AC_REGISTRATION, DEP_AP_ACTUAL: $DEP_AP_ACTUAL, DEP_AP_SCHED: $DEP_AP_SCHED, DEP_DT_EST: $DEP_DT_EST, DEP_SCHED_DT: $DEP_SCHED_DT, ARR_AP_ACTUAL: $ARR_AP_ACTUAL, ARR_AP_SCHED: $ARR_AP_SCHED, ARR_DT_EST: $ARR_DT_EST, ARR_SCHED_DT: $ARR_SCHED_DT, SLOT_TIME_ACTUAL: $SLOT_TIME_ACTUAL, LEG_TYPE: $LEG_TYPE, EMPLOYER_COCKPIT: $EMPLOYER_COCKPIT, EMPLOYER_CABIN: $EMPLOYER_CABIN, CYCLES: $CYCLES, DELAY_CODE_01: $DELAY_CODE_01, DELAY_CODE_02: $DELAY_CODE_02, DELAY_CODE_03: $DELAY_CODE_03, DELAY_CODE_04: $DELAY_CODE_04, DELAY_TIME_01: $DELAY_TIME_01, DELAY_TIME_02: $DELAY_TIME_02, DELAY_TIME_03: $DELAY_TIME_03, DELAY_TIME_04: $DELAY_TIME_04, SUBDELAY_CODE_01: $SUBDELAY_CODE_01, SUBDELAY_CODE_02: $SUBDELAY_CODE_02, SUBDELAY_CODE_03: $SUBDELAY_CODE_03, SUBDELAY_CODE_04: $SUBDELAY_CODE_04, PAX_BOOKED_C: $PAX_BOOKED_C, PAX_BOOKED_Y: $PAX_BOOKED_Y, PAX_BOOKED_TRS_C: $PAX_BOOKED_TRS_C, PAX_BOOKED_TRS_Y: $PAX_BOOKED_TRS_Y, PAD_BOOKED_C: $PAD_BOOKED_C, PAD_BOOKED_Y: $PAD_BOOKED_Y, OFFBLOCK_DT_A: $OFFBLOCK_DT_A, AIRBORNE_DT_A: $AIRBORNE_DT_A, LANDING_DT_A: $LANDING_DT_A, ONBLOCK_DT_A: $ONBLOCK_DT_A, OFFBLOCK_DT_F: $OFFBLOCK_DT_F, AIRBORNE_DT_F: $AIRBORNE_DT_F, LANDING_DT_F: $LANDING_DT_F, ONBLOCK_DT_F: $ONBLOCK_DT_F, OFFBLOCK_DT_M: $OFFBLOCK_DT_M, AIRBORNE_DT_M: $AIRBORNE_DT_M, LANDING_DT_M: $LANDING_DT_M, ONBLOCK_DT_M: $ONBLOCK_DT_M, EET: $EET)';
+  }
+
+  @override
+  bool operator ==(covariant Acleg other) {
+    if (identical(this, other)) return true;
+
+    return other.LEG_NO == LEG_NO &&
+        other.FN_CARRIER == FN_CARRIER &&
+        other.FN_NUMBER == FN_NUMBER &&
+        other.FN_SUFFIX == FN_SUFFIX &&
+        other.DAY_OF_ORIGIN == DAY_OF_ORIGIN &&
+        other.AC_OWNER == AC_OWNER &&
+        other.AC_SUBTYPE == AC_SUBTYPE &&
+        other.AC_VERSION == AC_VERSION &&
+        other.AC_REGISTRATION == AC_REGISTRATION &&
+        other.DEP_AP_ACTUAL == DEP_AP_ACTUAL &&
+        other.DEP_AP_SCHED == DEP_AP_SCHED &&
+        other.DEP_DT_EST == DEP_DT_EST &&
+        other.DEP_SCHED_DT == DEP_SCHED_DT &&
+        other.ARR_AP_ACTUAL == ARR_AP_ACTUAL &&
+        other.ARR_AP_SCHED == ARR_AP_SCHED &&
+        other.ARR_DT_EST == ARR_DT_EST &&
+        other.ARR_SCHED_DT == ARR_SCHED_DT &&
+        other.SLOT_TIME_ACTUAL == SLOT_TIME_ACTUAL &&
+        other.LEG_TYPE == LEG_TYPE &&
+        other.EMPLOYER_COCKPIT == EMPLOYER_COCKPIT &&
+        other.EMPLOYER_CABIN == EMPLOYER_CABIN &&
+        other.CYCLES == CYCLES &&
+        other.DELAY_CODE_01 == DELAY_CODE_01 &&
+        other.DELAY_CODE_02 == DELAY_CODE_02 &&
+        other.DELAY_CODE_03 == DELAY_CODE_03 &&
+        other.DELAY_CODE_04 == DELAY_CODE_04 &&
+        other.DELAY_TIME_01 == DELAY_TIME_01 &&
+        other.DELAY_TIME_02 == DELAY_TIME_02 &&
+        other.DELAY_TIME_03 == DELAY_TIME_03 &&
+        other.DELAY_TIME_04 == DELAY_TIME_04 &&
+        other.SUBDELAY_CODE_01 == SUBDELAY_CODE_01 &&
+        other.SUBDELAY_CODE_02 == SUBDELAY_CODE_02 &&
+        other.SUBDELAY_CODE_03 == SUBDELAY_CODE_03 &&
+        other.SUBDELAY_CODE_04 == SUBDELAY_CODE_04 &&
+        other.PAX_BOOKED_C == PAX_BOOKED_C &&
+        other.PAX_BOOKED_Y == PAX_BOOKED_Y &&
+        other.PAX_BOOKED_TRS_C == PAX_BOOKED_TRS_C &&
+        other.PAX_BOOKED_TRS_Y == PAX_BOOKED_TRS_Y &&
+        other.PAD_BOOKED_C == PAD_BOOKED_C &&
+        other.PAD_BOOKED_Y == PAD_BOOKED_Y &&
+        other.OFFBLOCK_DT_A == OFFBLOCK_DT_A &&
+        other.AIRBORNE_DT_A == AIRBORNE_DT_A &&
+        other.LANDING_DT_A == LANDING_DT_A &&
+        other.ONBLOCK_DT_A == ONBLOCK_DT_A &&
+        other.OFFBLOCK_DT_F == OFFBLOCK_DT_F &&
+        other.AIRBORNE_DT_F == AIRBORNE_DT_F &&
+        other.LANDING_DT_F == LANDING_DT_F &&
+        other.ONBLOCK_DT_F == ONBLOCK_DT_F &&
+        other.OFFBLOCK_DT_M == OFFBLOCK_DT_M &&
+        other.AIRBORNE_DT_M == AIRBORNE_DT_M &&
+        other.LANDING_DT_M == LANDING_DT_M &&
+        other.ONBLOCK_DT_M == ONBLOCK_DT_M &&
+        other.EET == EET;
+  }
+
+  @override
+  int get hashCode {
+    return LEG_NO.hashCode ^
+        FN_CARRIER.hashCode ^
+        FN_NUMBER.hashCode ^
+        FN_SUFFIX.hashCode ^
+        DAY_OF_ORIGIN.hashCode ^
+        AC_OWNER.hashCode ^
+        AC_SUBTYPE.hashCode ^
+        AC_VERSION.hashCode ^
+        AC_REGISTRATION.hashCode ^
+        DEP_AP_ACTUAL.hashCode ^
+        DEP_AP_SCHED.hashCode ^
+        DEP_DT_EST.hashCode ^
+        DEP_SCHED_DT.hashCode ^
+        ARR_AP_ACTUAL.hashCode ^
+        ARR_AP_SCHED.hashCode ^
+        ARR_DT_EST.hashCode ^
+        ARR_SCHED_DT.hashCode ^
+        SLOT_TIME_ACTUAL.hashCode ^
+        LEG_TYPE.hashCode ^
+        EMPLOYER_COCKPIT.hashCode ^
+        EMPLOYER_CABIN.hashCode ^
+        CYCLES.hashCode ^
+        DELAY_CODE_01.hashCode ^
+        DELAY_CODE_02.hashCode ^
+        DELAY_CODE_03.hashCode ^
+        DELAY_CODE_04.hashCode ^
+        DELAY_TIME_01.hashCode ^
+        DELAY_TIME_02.hashCode ^
+        DELAY_TIME_03.hashCode ^
+        DELAY_TIME_04.hashCode ^
+        SUBDELAY_CODE_01.hashCode ^
+        SUBDELAY_CODE_02.hashCode ^
+        SUBDELAY_CODE_03.hashCode ^
+        SUBDELAY_CODE_04.hashCode ^
+        PAX_BOOKED_C.hashCode ^
+        PAX_BOOKED_Y.hashCode ^
+        PAX_BOOKED_TRS_C.hashCode ^
+        PAX_BOOKED_TRS_Y.hashCode ^
+        PAD_BOOKED_C.hashCode ^
+        PAD_BOOKED_Y.hashCode ^
+        OFFBLOCK_DT_A.hashCode ^
+        AIRBORNE_DT_A.hashCode ^
+        LANDING_DT_A.hashCode ^
+        ONBLOCK_DT_A.hashCode ^
+        OFFBLOCK_DT_F.hashCode ^
+        AIRBORNE_DT_F.hashCode ^
+        LANDING_DT_F.hashCode ^
+        ONBLOCK_DT_F.hashCode ^
+        OFFBLOCK_DT_M.hashCode ^
+        AIRBORNE_DT_M.hashCode ^
+        LANDING_DT_M.hashCode ^
+        ONBLOCK_DT_M.hashCode ^
+        EET.hashCode;
+  }
+}
+
+extension StringExtensions on String {
+  String capitalize() {
+    if (isEmpty) {
+      return this;
+    } else {
+      return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
+    }
+  }
+
+  String capitalizeword() {
+    return split(' ').map((word) => word.capitalize()).join(' ');
+  }
+
+  Jiffy? parseddmmyyyyhhmm() => length >= 15
+      ? Jiffy.parse(
+          "${substring(6, 10)}-${substring(3, 5)}-${substring(0, 2)} ${substring(11, 13)}:${substring(13, 15)}",
+          pattern: 'yyyy-MM-dd HH:mm',
+          isUtc: true)
+      : null;
+  Jiffy? parseyyyymmddhhmm() => length >= 16
+      ? Jiffy.parse(this,
+          pattern: 'yyyy-MM-dd HH:mm:ss',
+          // "${substring(6, 10)}-${substring(3, 5)}-${substring(0, 2)} ${substring(11, 13)}${substring(13, 16)}",
+          // pattern: 'yyyy-MM-dd HH:mm',
+          isUtc: true)
+      : null;
+}

+ 109 - 0
lib/models/dtinterval.dart

@@ -0,0 +1,109 @@
+import 'package:jiffy/jiffy.dart';
+
+class DTInterval {
+  late Jiffy start;
+  late Jiffy end;
+  DTInterval(this.start, this.end);
+  @override
+  String toString() =>
+      "<${start.format(pattern: "ddMMMyy HH:mm")} - ${end.format(pattern: "ddMMMyy HH:mm")}>";
+
+  bool include(Jiffy x) {
+    return x.isSameOrAfter(start) && x.isSameOrBefore(end);
+  }
+
+  bool isOverlap(DTInterval x) {
+    return x.start.isSameOrBefore(end) && x.end.isSameOrAfter(start);
+  }
+
+  bool contains(DTInterval x) {
+    return include(x.start) && include(x.end);
+  }
+
+  DTInterval? intersection(DTInterval x) {
+    if (!isOverlap(x)) {
+      return null;
+    } else {
+      return DTInterval(start.max(x.start), end.min(x.end));
+    }
+  }
+
+  List<DTInterval> intersectionmany(List<DTInterval> x) {
+    return x.map((e) => intersection(e)).nonNulls.toList();
+  }
+
+  List<DTInterval> minus(DTInterval x) {
+    if (!isOverlap(x)) {
+      return [this];
+    } else if (x.include(start) && x.include(end)) {
+      return [];
+    } else if (x.include(start)) {
+      return [DTInterval(x.end, end)];
+    } else if (x.include(end)) {
+      return [DTInterval(start, x.start)];
+    } else {
+      return [DTInterval(start, x.start), DTInterval(x.end, end)];
+    }
+  }
+
+  // List<DTInterval> minus(DTInterval other) {
+  //   List<DTInterval> result = [];
+  //   if (start.isBefore(other.start) && end.isAfter(other.start)) {
+  //     result.add(DTInterval(start, other.start));
+  //   }
+  //   if (start.isBefore(other.end) && end.isAfter(other.end)) {
+  //     result.add(DTInterval(other.end, end));
+  //   }
+  //   return result;
+  // }
+
+  Duration get duration => end.dateTime.difference(start.dateTime);
+  // Duration get duration => Duration(
+  //     milliseconds: end.diff(start, unit: Unit.millisecond).abs().ceil());
+
+  bool isEmpty() {
+    return start.isSameOrAfter(end);
+  }
+
+  DTInterval toUtc() {
+    return DTInterval(start.toUtc(), end.toUtc());
+  }
+}
+
+extension JiffyExtensions on Jiffy? {
+  Jiffy? latest(Jiffy? val2) {
+    if (this == null) return val2;
+    if (val2 == null) return this;
+    if (this!.isBefore(val2)) {
+      return val2;
+    } else {
+      return this;
+    }
+  }
+
+  Jiffy? earliset(Jiffy? val2) {
+    if (this == null) return val2;
+    if (val2 == null) return this;
+    if (this!.isAfter(val2)) {
+      return val2;
+    } else {
+      return this;
+    }
+  }
+
+  Jiffy max(Jiffy val2) {
+    if (this!.isBefore(val2)) {
+      return val2;
+    } else {
+      return this!;
+    }
+  }
+
+  Jiffy min(Jiffy val2) {
+    if (this!.isAfter(val2)) {
+      return val2;
+    } else {
+      return this!;
+    }
+  }
+}

+ 138 - 10
pubspec.lock

@@ -22,6 +22,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "6.11.0"
+  archive:
+    dependency: "direct main"
+    description:
+      name: archive
+      sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.6.1"
   args:
     dependency: transitive
     description:
@@ -46,6 +54,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.2"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.2"
   collection:
     dependency: transitive
     description:
@@ -66,10 +82,10 @@ packages:
     dependency: transitive
     description:
       name: coverage
-      sha256: "88b0fddbe4c92910fefc09cc0248f5e7f0cd23e450ded4c28f16ab8ee8f83268"
+      sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5"
       url: "https://pub.dev"
     source: hosted
-    version: "1.10.0"
+    version: "1.11.0"
   crypto:
     dependency: transitive
     description:
@@ -94,6 +110,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.0.0"
+  functions_client:
+    dependency: transitive
+    description:
+      name: functions_client
+      sha256: "61597ed93be197b1be6387855e4b760e6aac2355fcfc4df6d20d2b4579982158"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.4.0"
   glob:
     dependency: transitive
     description:
@@ -102,6 +126,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.2"
+  gotrue:
+    dependency: transitive
+    description:
+      name: gotrue
+      sha256: b9541c62edc0ee1fddf2c95364251b8076a93bcdbc3ad27f14a633d187e89ccc
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.11.0"
+  http:
+    dependency: transitive
+    description:
+      name: http
+      sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.2"
   http_methods:
     dependency: transitive
     description:
@@ -126,6 +166,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.1.1"
+  intl:
+    dependency: transitive
+    description:
+      name: intl
+      sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.19.0"
   io:
     dependency: transitive
     description:
@@ -134,6 +182,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.0.4"
+  jiffy:
+    dependency: "direct main"
+    description:
+      name: jiffy
+      sha256: "3497caaa36d36a29033e66803c9739ce6bccbc7e241ca46070f76ee9e6f6eb0c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.3.1"
   js:
     dependency: transitive
     description:
@@ -142,6 +198,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.7.1"
+  jwt_decode:
+    dependency: transitive
+    description:
+      name: jwt_decode
+      sha256: d2e9f68c052b2225130977429d30f187aa1981d789c76ad104a32243cfdebfbb
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.3.1"
   lints:
     dependency: "direct dev"
     description:
@@ -222,6 +286,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.5.1"
+  postgrest:
+    dependency: transitive
+    description:
+      name: postgrest
+      sha256: "9f759ac497a24839addbed69d9569ea6d51d2e4834c672b8c2a73752fb6945c8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.4.0"
   pub_semver:
     dependency: transitive
     description:
@@ -230,6 +302,30 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.4"
+  realtime_client:
+    dependency: transitive
+    description:
+      name: realtime_client
+      sha256: "173c3dc40922bb0ae19a558ae1a0acf7b28ec8a458b54390c499bbe5ff15f049"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.4.0"
+  retry:
+    dependency: transitive
+    description:
+      name: retry
+      sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.2"
+  rxdart:
+    dependency: transitive
+    description:
+      name: rxdart
+      sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.28.0"
   shelf:
     dependency: "direct main"
     description:
@@ -266,18 +362,18 @@ packages:
     dependency: transitive
     description:
       name: shelf_static
-      sha256: "8584c0aa0f5756a61519b1a2fc2cd22ddbc518e9396bd33ebf06b9836bb23d13"
+      sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.0"
+    version: "1.1.3"
   shelf_web_socket:
     dependency: transitive
     description:
       name: shelf_web_socket
-      sha256: "520368a1a49798425310ca0ee28eb92b3c737e4e9d173c31b6c66fe090ebc6fc"
+      sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.0"
+    version: "2.0.1"
   source_map_stack_trace:
     dependency: transitive
     description:
@@ -310,6 +406,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.12.0"
+  storage_client:
+    dependency: transitive
+    description:
+      name: storage_client
+      sha256: "833666edcd804aaf434f3b13165fd553a8c6371a488618a58be8914856795c04"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.0"
   stream_channel:
     dependency: transitive
     description:
@@ -326,6 +430,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.4.0"
+  supabase:
+    dependency: "direct main"
+    description:
+      name: supabase
+      sha256: ecdfb226c483f05fd10425304de744144dfdda2f33d14151d2604cebe8c6d077
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.6.0"
   term_glyph:
     dependency: transitive
     description:
@@ -386,18 +498,26 @@ packages:
     dependency: transitive
     description:
       name: web
-      sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
+      sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
       url: "https://pub.dev"
     source: hosted
-    version: "0.5.1"
+    version: "1.1.0"
+  web_socket:
+    dependency: transitive
+    description:
+      name: web_socket
+      sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.1.6"
   web_socket_channel:
     dependency: transitive
     description:
       name: web_socket_channel
-      sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
+      sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
       url: "https://pub.dev"
     source: hosted
-    version: "2.4.5"
+    version: "3.0.1"
   webkit_inspection_protocol:
     dependency: transitive
     description:
@@ -414,5 +534,13 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.1.2"
+  yet_another_json_isolate:
+    dependency: transitive
+    description:
+      name: yet_another_json_isolate
+      sha256: "56155e9e0002cc51ea7112857bbcdc714d4c35e176d43e4d3ee233009ff410c9"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.3"
 sdks:
   dart: ">=3.6.0-334.3.beta <4.0.0"

+ 3 - 1
pubspec.yaml

@@ -9,10 +9,12 @@ environment:
 # Add regular dependencies here.
 dependencies:
   # path: ^1.8.0
-
+  supabase: #^2.0.0
   shelf: #^1.4.2
   shelf_multipart: #^2.0.0
   shelf_router: #^1.1.4
+  archive: #^3.4.10
+  jiffy: ^6.3.1
 
 dev_dependencies:
   lints: #^5.0.0