From 7d4445bb9bad3d6c945503086a07bd882536e5f6 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Mon, 19 May 2025 11:02:19 +0700
Subject: <miqdad> fix unresponsive cart select

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 170 +++++++++++++++------
 1 file changed, 126 insertions(+), 44 deletions(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index d4a1b537..733ee64d 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -1,56 +1,138 @@
-import { Checkbox, Spinner } from '@chakra-ui/react'
-import React, { useState } from 'react'
-
-import { getAuth } from '~/libs/auth'
-import { CartItem } from '~/types/cart'
-import { upsertUserCart } from '~/services/cart'
-
-import { useCartStore } from '../stores/useCartStore'
+import { Checkbox } from '@chakra-ui/react';
+import React, { useState, useCallback, useEffect } from 'react';
+import { getAuth } from '~/libs/auth';
+import { CartItem } from '~/types/cart';
+import { upsertUserCart } from '~/services/cart';
+import { useCartStore } from '../stores/useCartStore';
+import { toast } from 'react-hot-toast';
+import {
+  getSelectedItemsFromCookie,
+  updateSelectedItemInCookie,
+} from '~/utils/cart';
 
 type Props = {
-  item: CartItem
-}
+  item: CartItem;
+};
 
 const CartItemSelect = ({ item }: Props) => {
-  const auth = getAuth()
-  const { updateCartItem, cart } = useCartStore()
+  const auth = getAuth();
+  const { updateCartItem, cart, loadCart } = useCartStore();
+  const [isUpdating, setIsUpdating] = useState<boolean>(false);
+  const [localSelected, setLocalSelected] = useState<boolean>(item.selected);
+
+  // Initialize local state from cookie or server
+  useEffect(() => {
+    if (isUpdating) return; // Skip if we're currently updating
+
+    // Check cookie first
+    const selectedItems = getSelectedItemsFromCookie();
+    const storedState = selectedItems[item.id];
+
+    if (storedState !== undefined) {
+      // Only update local state if it differs from current state
+      if (localSelected !== storedState) {
+        setLocalSelected(storedState);
+      }
+
+      // If cookie state differs from server state and we're not in the middle of an update,
+      // synchronize the item state with cookie
+      if (storedState !== item.selected) {
+        // Update cart item silently to match cookie
+        if (cart) {
+          const updatedCartItems = cart.products.map((cartItem) =>
+            cartItem.id === item.id
+              ? { ...cartItem, selected: storedState }
+              : cartItem
+          );
+
+          const updatedCart = { ...cart, products: updatedCartItems };
+          updateCartItem(updatedCart);
+        }
+      }
+    } else {
+      // Fall back to server state if no cookie exists
+      setLocalSelected(item.selected);
+
+      // Save this state to cookie for future use
+      updateSelectedItemInCookie(item.id, item.selected);
+    }
+  }, [item.id, item.selected, localSelected, cart, updateCartItem, isUpdating]);
+
+  const handleChange = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (typeof auth !== 'object' || !cart || isUpdating) {
+        return;
+      }
+
+      const newSelectedState = e.target.checked;
+
+      // Update local state immediately for responsiveness
+      setLocalSelected(newSelectedState);
+      setIsUpdating(true);
+
+      try {
+        // Update cookie immediately
+        updateSelectedItemInCookie(item.id, newSelectedState);
+
+        // Update cart state immediately for UI responsiveness
+        const updatedCartItems = cart.products.map((cartItem) =>
+          cartItem.id === item.id
+            ? { ...cartItem, selected: newSelectedState }
+            : cartItem
+        );
+
+        const updatedCart = { ...cart, products: updatedCartItems };
+        updateCartItem(updatedCart);
+
+        // Save to server
+        await upsertUserCart({
+          userId: auth.id,
+          type: item.cart_type,
+          id: item.id,
+          qty: item.quantity,
+          selected: newSelectedState,
+        });
 
-  const [isLoad, setIsLoad] = useState<boolean>(false)
+        // Reload cart to ensure consistency
+        await loadCart(auth.id);
+      } catch (error) {
+        console.error('Failed to update item selection:', error);
+        toast.error('Gagal memperbarui pilihan barang');
 
-  const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
-    if (typeof auth !== 'object' || !cart) return
-    
-    setIsLoad(true);
-    const updatedCartItems = cart.products.map(cartItem =>
-      cartItem.id === item.id
-        ? { ...cartItem, selected: e.target.checked }
-        : cartItem
-    );
+        // Revert local state on error
+        setLocalSelected(!newSelectedState);
 
-    // Update the entire cart
-    const updatedCart = { ...cart, products: updatedCartItems };
-    updateCartItem(updatedCart);
+        // Update cookie back
+        updateSelectedItemInCookie(item.id, !newSelectedState);
 
-    setIsLoad(false);
-  }
+        // Reload cart to get server state
+        loadCart(auth.id);
+      } finally {
+        setIsUpdating(false);
+      }
+    },
+    [auth, cart, item, isUpdating, updateCartItem, loadCart]
+  );
 
   return (
-    <div className='w-6 my-auto'>
-      {isLoad && (
-        <Spinner className='my-auto' size='sm' />
-      )}
-
-      {!isLoad && (
-        <Checkbox
-          borderColor='gray.600'
-          colorScheme='red'
-          size='lg'
-          isChecked={item.selected}
-          onChange={handleChange}
-        />
-      )}
+    <div className='w-6 my-auto relative'>
+      <Checkbox
+        borderColor='gray.600'
+        colorScheme='red'
+        size='lg'
+        isChecked={localSelected}
+        onChange={handleChange}
+        isDisabled={isUpdating}
+        opacity={isUpdating ? 0.5 : 1}
+        cursor={isUpdating ? 'not-allowed' : 'pointer'}
+        _disabled={{
+          opacity: 0.5,
+          cursor: 'not-allowed',
+          backgroundColor: 'gray.100',
+        }}
+      />
     </div>
-  )
-}
+  );
+};
 
-export default CartItemSelect
\ No newline at end of file
+export default CartItemSelect;
-- 
cgit v1.2.3


From 09cebc9020c4f1995a73305187bc1576e339d183 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Thu, 22 May 2025 10:05:09 +0700
Subject: <miqdad> disable button when updating checkboxes and change summary
 design

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 43 ++++++++++++++++++----
 1 file changed, 35 insertions(+), 8 deletions(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index 733ee64d..70b656ec 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -8,6 +8,7 @@ import { toast } from 'react-hot-toast';
 import {
   getSelectedItemsFromCookie,
   updateSelectedItemInCookie,
+  checkboxUpdateState,
 } from '~/utils/cart';
 
 type Props = {
@@ -19,6 +20,20 @@ const CartItemSelect = ({ item }: Props) => {
   const { updateCartItem, cart, loadCart } = useCartStore();
   const [isUpdating, setIsUpdating] = useState<boolean>(false);
   const [localSelected, setLocalSelected] = useState<boolean>(item.selected);
+  const [isGlobalUpdating, setIsGlobalUpdating] = useState<boolean>(false);
+
+  // Subscribe to global checkbox update state
+  useEffect(() => {
+    const handleUpdateStateChange = (isUpdating) => {
+      setIsGlobalUpdating(isUpdating);
+    };
+
+    checkboxUpdateState.addListener(handleUpdateStateChange);
+
+    return () => {
+      checkboxUpdateState.removeListener(handleUpdateStateChange);
+    };
+  }, []);
 
   // Initialize local state from cookie or server
   useEffect(() => {
@@ -54,7 +69,7 @@ const CartItemSelect = ({ item }: Props) => {
       setLocalSelected(item.selected);
 
       // Save this state to cookie for future use
-      updateSelectedItemInCookie(item.id, item.selected);
+      updateSelectedItemInCookie(item.id, item.selected, false); // don't notify for initial sync
     }
   }, [item.id, item.selected, localSelected, cart, updateCartItem, isUpdating]);
 
@@ -70,9 +85,12 @@ const CartItemSelect = ({ item }: Props) => {
       setLocalSelected(newSelectedState);
       setIsUpdating(true);
 
+      // Start the update - notify global state with this checkbox's ID
+      checkboxUpdateState.startUpdate(item.id);
+
       try {
-        // Update cookie immediately
-        updateSelectedItemInCookie(item.id, newSelectedState);
+        // The cookie update is now handled inside the function with notification
+        updateSelectedItemInCookie(item.id, newSelectedState, false); // We already started above
 
         // Update cart state immediately for UI responsiveness
         const updatedCartItems = cart.products.map((cartItem) =>
@@ -91,6 +109,7 @@ const CartItemSelect = ({ item }: Props) => {
           id: item.id,
           qty: item.quantity,
           selected: newSelectedState,
+          purchase_tax_id: item.purchase_tax_id || null, // Ensure null for numeric fields
         });
 
         // Reload cart to ensure consistency
@@ -102,18 +121,26 @@ const CartItemSelect = ({ item }: Props) => {
         // Revert local state on error
         setLocalSelected(!newSelectedState);
 
-        // Update cookie back
-        updateSelectedItemInCookie(item.id, !newSelectedState);
+        // Revert cookie change
+        updateSelectedItemInCookie(item.id, !newSelectedState, false);
 
         // Reload cart to get server state
         loadCart(auth.id);
       } finally {
         setIsUpdating(false);
+
+        // End the update - notify global state with this checkbox's ID
+        checkboxUpdateState.endUpdate(item.id);
       }
     },
     [auth, cart, item, isUpdating, updateCartItem, loadCart]
   );
 
+  // Determine if THIS specific checkbox should be disabled - only disable
+  // if this specific checkbox is updating
+  const isDisabled =
+    isUpdating || checkboxUpdateState.isCheckboxUpdating(item.id);
+
   return (
     <div className='w-6 my-auto relative'>
       <Checkbox
@@ -122,9 +149,9 @@ const CartItemSelect = ({ item }: Props) => {
         size='lg'
         isChecked={localSelected}
         onChange={handleChange}
-        isDisabled={isUpdating}
-        opacity={isUpdating ? 0.5 : 1}
-        cursor={isUpdating ? 'not-allowed' : 'pointer'}
+        isDisabled={isDisabled}
+        opacity={isDisabled ? 0.5 : 1}
+        cursor={isDisabled ? 'not-allowed' : 'pointer'}
         _disabled={{
           opacity: 0.5,
           cursor: 'not-allowed',
-- 
cgit v1.2.3


From 4904573845478e7e9648735d008153728870a123 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Fri, 23 May 2025 09:37:46 +0700
Subject: <miqdad> fix cookie not updating when delete an item

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index 70b656ec..f580f81d 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -109,7 +109,7 @@ const CartItemSelect = ({ item }: Props) => {
           id: item.id,
           qty: item.quantity,
           selected: newSelectedState,
-          purchase_tax_id: item.purchase_tax_id || null, // Ensure null for numeric fields
+          // purchase_tax_id: item.purchase_tax_id || null, // Ensure null for numeric fields
         });
 
         // Reload cart to ensure consistency
-- 
cgit v1.2.3


From 1a247903bf7bb87e0a43b4e5e338ea67ec90e6de Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Mon, 26 May 2025 14:39:39 +0700
Subject: <miqdad> cleaning code

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index f580f81d..00c7be43 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -68,8 +68,8 @@ const CartItemSelect = ({ item }: Props) => {
       // Fall back to server state if no cookie exists
       setLocalSelected(item.selected);
 
-      // Save this state to cookie for future use
-      updateSelectedItemInCookie(item.id, item.selected, false); // don't notify for initial sync
+      // Save state to cookie for future
+      updateSelectedItemInCookie(item.id, item.selected, false);
     }
   }, [item.id, item.selected, localSelected, cart, updateCartItem, isUpdating]);
 
-- 
cgit v1.2.3


From 3feaad9127ff429b27f0eb69fa6ea539de2f2e8c Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Mon, 26 May 2025 20:00:17 +0700
Subject: <miqdad> Cleaning code

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 76 +++++++---------------
 1 file changed, 25 insertions(+), 51 deletions(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index 00c7be43..8dbfe2bc 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -20,124 +20,98 @@ const CartItemSelect = ({ item }: Props) => {
   const { updateCartItem, cart, loadCart } = useCartStore();
   const [isUpdating, setIsUpdating] = useState<boolean>(false);
   const [localSelected, setLocalSelected] = useState<boolean>(item.selected);
-  const [isGlobalUpdating, setIsGlobalUpdating] = useState<boolean>(false);
 
   // Subscribe to global checkbox update state
   useEffect(() => {
     const handleUpdateStateChange = (isUpdating) => {
-      setIsGlobalUpdating(isUpdating);
+      // This component doesn't need to react to global state changes
+      // Individual checkboxes are managed independently
     };
 
     checkboxUpdateState.addListener(handleUpdateStateChange);
-
-    return () => {
-      checkboxUpdateState.removeListener(handleUpdateStateChange);
-    };
+    return () => checkboxUpdateState.removeListener(handleUpdateStateChange);
   }, []);
 
-  // Initialize local state from cookie or server
+  // Sync local state with cookie and server data
   useEffect(() => {
-    if (isUpdating) return; // Skip if we're currently updating
+    if (isUpdating) return;
 
-    // Check cookie first
     const selectedItems = getSelectedItemsFromCookie();
     const storedState = selectedItems[item.id];
 
     if (storedState !== undefined) {
-      // Only update local state if it differs from current state
+      // Update local state if cookie differs
       if (localSelected !== storedState) {
         setLocalSelected(storedState);
       }
 
-      // If cookie state differs from server state and we're not in the middle of an update,
-      // synchronize the item state with cookie
-      if (storedState !== item.selected) {
-        // Update cart item silently to match cookie
-        if (cart) {
-          const updatedCartItems = cart.products.map((cartItem) =>
-            cartItem.id === item.id
-              ? { ...cartItem, selected: storedState }
-              : cartItem
-          );
-
-          const updatedCart = { ...cart, products: updatedCartItems };
-          updateCartItem(updatedCart);
-        }
+      // Sync cart state with cookie if needed
+      if (storedState !== item.selected && cart) {
+        const updatedCartItems = cart.products.map((cartItem) =>
+          cartItem.id === item.id
+            ? { ...cartItem, selected: storedState }
+            : cartItem
+        );
+        updateCartItem({ ...cart, products: updatedCartItems });
       }
     } else {
-      // Fall back to server state if no cookie exists
+      // Initialize cookie with server state
       setLocalSelected(item.selected);
-
-      // Save state to cookie for future
       updateSelectedItemInCookie(item.id, item.selected, false);
     }
   }, [item.id, item.selected, localSelected, cart, updateCartItem, isUpdating]);
 
   const handleChange = useCallback(
     async (e: React.ChangeEvent<HTMLInputElement>) => {
-      if (typeof auth !== 'object' || !cart || isUpdating) {
-        return;
-      }
+      if (typeof auth !== 'object' || !cart || isUpdating) return;
 
       const newSelectedState = e.target.checked;
 
-      // Update local state immediately for responsiveness
+      // Update local state immediately
       setLocalSelected(newSelectedState);
       setIsUpdating(true);
-
-      // Start the update - notify global state with this checkbox's ID
       checkboxUpdateState.startUpdate(item.id);
 
       try {
-        // The cookie update is now handled inside the function with notification
-        updateSelectedItemInCookie(item.id, newSelectedState, false); // We already started above
+        // Update cookie immediately for responsive UI
+        updateSelectedItemInCookie(item.id, newSelectedState, false);
 
-        // Update cart state immediately for UI responsiveness
+        // Update cart state optimistically
         const updatedCartItems = cart.products.map((cartItem) =>
           cartItem.id === item.id
             ? { ...cartItem, selected: newSelectedState }
             : cartItem
         );
+        updateCartItem({ ...cart, products: updatedCartItems });
 
-        const updatedCart = { ...cart, products: updatedCartItems };
-        updateCartItem(updatedCart);
-
-        // Save to server
+        // Send update to server
         await upsertUserCart({
           userId: auth.id,
           type: item.cart_type,
           id: item.id,
           qty: item.quantity,
           selected: newSelectedState,
-          // purchase_tax_id: item.purchase_tax_id || null, // Ensure null for numeric fields
+          purchase_tax_id: item.purchase_tax_id || null,
         });
 
-        // Reload cart to ensure consistency
+        // Reload cart for consistency
         await loadCart(auth.id);
       } catch (error) {
         console.error('Failed to update item selection:', error);
         toast.error('Gagal memperbarui pilihan barang');
 
-        // Revert local state on error
+        // Revert changes on error
         setLocalSelected(!newSelectedState);
-
-        // Revert cookie change
         updateSelectedItemInCookie(item.id, !newSelectedState, false);
-
-        // Reload cart to get server state
         loadCart(auth.id);
       } finally {
         setIsUpdating(false);
-
-        // End the update - notify global state with this checkbox's ID
         checkboxUpdateState.endUpdate(item.id);
       }
     },
     [auth, cart, item, isUpdating, updateCartItem, loadCart]
   );
 
-  // Determine if THIS specific checkbox should be disabled - only disable
-  // if this specific checkbox is updating
   const isDisabled =
     isUpdating || checkboxUpdateState.isCheckboxUpdating(item.id);
 
-- 
cgit v1.2.3


From 2732c04b36f98a25895826b28003b1e2c56ad952 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Tue, 27 May 2025 09:05:10 +0700
Subject: <miqdad> remove purchase_tax_id and vendor_id

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index 8dbfe2bc..72ab49aa 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -91,7 +91,8 @@ const CartItemSelect = ({ item }: Props) => {
           id: item.id,
           qty: item.quantity,
           selected: newSelectedState,
-          purchase_tax_id: item.purchase_tax_id || null,
+          // purchase_tax_id: item.purchase_tax_id,
+          // vendor_id: item.vendor_id
         });
 
         // Reload cart for consistency
-- 
cgit v1.2.3


From 3f992f62c54e09254c48d653c2cd138df1cbd8e2 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Sat, 31 May 2025 14:33:24 +0700
Subject: <miqdad> fix error deployment

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index 72ab49aa..f95ee36c 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -11,11 +11,11 @@ import {
   checkboxUpdateState,
 } from '~/utils/cart';
 
-type Props = {
+interface Props {
   item: CartItem;
-};
+}
 
-const CartItemSelect = ({ item }: Props) => {
+const CartItemSelect: React.FC<Props> = ({ item }) => {
   const auth = getAuth();
   const { updateCartItem, cart, loadCart } = useCartStore();
   const [isUpdating, setIsUpdating] = useState<boolean>(false);
@@ -23,7 +23,7 @@ const CartItemSelect = ({ item }: Props) => {
 
   // Subscribe to global checkbox update state
   useEffect(() => {
-    const handleUpdateStateChange = (isUpdating) => {
+    const handleUpdateStateChange = (isUpdating: boolean): void => {
       // This component doesn't need to react to global state changes
       // Individual checkboxes are managed independently
     };
@@ -36,7 +36,10 @@ const CartItemSelect = ({ item }: Props) => {
   useEffect(() => {
     if (isUpdating) return;
 
-    const selectedItems = getSelectedItemsFromCookie();
+    const selectedItems = getSelectedItemsFromCookie() as Record<
+      number,
+      boolean
+    >;
     const storedState = selectedItems[item.id];
 
     if (storedState !== undefined) {
@@ -62,7 +65,7 @@ const CartItemSelect = ({ item }: Props) => {
   }, [item.id, item.selected, localSelected, cart, updateCartItem, isUpdating]);
 
   const handleChange = useCallback(
-    async (e: React.ChangeEvent<HTMLInputElement>) => {
+    async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
       if (typeof auth !== 'object' || !cart || isUpdating) return;
 
       const newSelectedState = e.target.checked;
@@ -70,7 +73,7 @@ const CartItemSelect = ({ item }: Props) => {
       // Update local state immediately
       setLocalSelected(newSelectedState);
       setIsUpdating(true);
-      checkboxUpdateState.startUpdate(item.id);
+      checkboxUpdateState.startUpdate();
 
       try {
         // Update cookie immediately for responsive UI
@@ -107,14 +110,13 @@ const CartItemSelect = ({ item }: Props) => {
         loadCart(auth.id);
       } finally {
         setIsUpdating(false);
-        checkboxUpdateState.endUpdate(item.id);
+        checkboxUpdateState.endUpdate();
       }
     },
     [auth, cart, item, isUpdating, updateCartItem, loadCart]
   );
 
-  const isDisabled =
-    isUpdating || checkboxUpdateState.isCheckboxUpdating(item.id);
+  const isDisabled: boolean = isUpdating;
 
   return (
     <div className='w-6 my-auto relative'>
-- 
cgit v1.2.3

