Thursday, September 29, 2016

Mailing list manager

I needed a simple mailing list manager for a sports club I'm in. We wanted it to be of the type where an administrator manages the lists (not the type where any random person can subscribe him- or herself). Couldn't find any decent looking free service offering this, so I decided to make one: mailgroup.io .

These are its features:
  • Free for noncommercial use.
  • Your own custom domain.
  • Or @mailgroup.io as domain if you prefer.
  • Your choice of members-only mailing lists, or everyone-may-write.
  • Detailed Postfix delivery reports for each mail for each recipient.
  • Max 50 recipients per account (negotiable).
  • Mail triggers. These are special email addresses that trigger HTTP POSTs with the email content to a defined URL when they receive email. Useful if you want some logic on your website to be triggered by email.


Wednesday, September 14, 2016

GLaDOS-like sound pack for Taranis

Here's a soundpack for the FrSky Taranis, based on the original, but run through Melodyne so it sounds like GLaDOS from Portal: https://acoby.com/fpv/gladosStyleTaranisSounds.zip

Sunday, May 01, 2016

Heap sort implementation in C#

Here's a heap sort implementation in C#:

  1. class HeapSort  
  2. {  
  3.     public void Sort(int[] a)  
  4.     {  
  5.         // Turn the array into a max heap  
  6.         for (int i = (a.Length / 2) - 1; i >= 0; i--)  
  7.         {  
  8.             MaxHeapify(a, i, a.Length);  
  9.         }  
  10.   
  11.         // Remove the largest element from the max heap and put it on the end,  
  12.         // and then max heapify the heap which is now 1 smaller  
  13.         for (int i = a.Length - 1; i >= 1; i--)  
  14.         {  
  15.             Swap(a, 0, i);  
  16.             MaxHeapify(a, 0, i);  
  17.         }  
  18.     }  
  19.   
  20.     private void MaxHeapify(int[] a, int i, int n)  
  21.     {  
  22.         int idxLeft  = (i + 1) * 2 - 1;  
  23.         int idxRight = (i + 1) * 2 - 1 + 1;  
  24.   
  25.         int largest = i;  
  26.   
  27.         if (idxLeft < n && a[idxLeft] > a[largest])  
  28.         {  
  29.             largest = idxLeft;  
  30.         }  
  31.   
  32.         if (idxRight < n && a[idxRight] > a[largest])  
  33.         {  
  34.             largest = idxRight;  
  35.         }  
  36.   
  37.         if (largest != i)  
  38.         {  
  39.             Swap(a, i, largest);  
  40.             MaxHeapify(a, largest, n);  
  41.         }  
  42.     }  
  43.   
  44.     private void Swap(int[] a, int i, int j)  
  45.     {  
  46.         int tmp = a[i];  
  47.         a[i] = a[j];  
  48.         a[j] = tmp;  
  49.     }  
  50. }  

Friday, March 25, 2016

Segment tree implementation in Java

Inspired by Kartik Kukreja's implementation, but storing all data in a tree node class, rather than an array. I find it a lot easier to comprehend this way.
class SegmentTreeNode {
    public int aggregateValue;
    public SegmentTreeNode left;
    public SegmentTreeNode right;
    public int origLowIndex;
    public int origHighIndex;
}

class SegmentTreeTest {

    public static SegmentTreeNode buildSegmentTree(int[] a, int low, int high) {
        SegmentTreeNode n = new SegmentTreeNode();
        n.origLowIndex = low;
        n.origHighIndex = high;

        if(low == high) {
            n.aggregateValue = a[low];
            return n;
        }

        int mid = (high - low)/2 + low;

        n.left = buildSegmentTree(a, low, mid);
        n.right = buildSegmentTree(a, mid+1, high);

        // This segment tree is for summation. Could also be min, max, or any other associative func.
        n.aggregateValue = n.left.aggregateValue + n.right.aggregateValue;

        return n;
    }

    public static SegmentTreeNode getAggregateValue(SegmentTreeNode n, int low, int high) {
        if(n.origLowIndex == low && n.origHighIndex == high) {
            return n;
        }

        // The interval is fully contained within the left node
        if(low >= n.left.origLowIndex && high <=  n.left.origHighIndex) {
            return getAggregateValue(n.left, low, high);
        }

        // The interval is fully contained within the right node
        if(low >= n.right.origLowIndex && high <=  n.right.origHighIndex) {
            return getAggregateValue(n.right, low, high);
        }

        // Split into queries on the left subtree and the right subtree
        SegmentTreeNode leftResult = getAggregateValue(n.left, low, n.left.origHighIndex);
        SegmentTreeNode rightResult = getAggregateValue(n.right, n.right.origLowIndex, high);
        SegmentTreeNode result = new SegmentTreeNode();
        result.origLowIndex = low;
        result.origHighIndex  = high;

        // This segment tree is for summation. Could also be min, max, or any other associative func.
        result.aggregateValue = leftResult.aggregateValue + rightResult.aggregateValue;

        return result;
    }

    public static void update(SegmentTreeNode n, int index, int val) {
        if(n.origLowIndex == index && n.origHighIndex == index) {
            n.aggregateValue = val;
            return;
        }

        if(n.left.origLowIndex <= index && index <= n.left.origHighIndex) {
            update(n.left, index, val);
        } else {
            update(n.right, index, val);
        }

        // This segment tree is for summation. Could also be min, max, or any other associative func.
        n.aggregateValue = n.left.aggregateValue + n.right.aggregateValue;
    }

    public static void main(String[] args) {
        //                    0  1  2  3  4  5  6  7  8   9  10
        int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
        SegmentTreeNode r = buildSegmentTree(a, 0, a.length-1);
        System.out.println(r.aggregateValue);

        System.out.println(getAggregateValue(r, 1, 3).aggregateValue);
        System.out.println(getAggregateValue(r, 4, 7).aggregateValue);

        update(r, 2, 10);
        System.out.println(r.aggregateValue);

        System.out.println(getAggregateValue(r, 4, 7).aggregateValue);
        System.out.println(getAggregateValue(r, 1, 3).aggregateValue);
    }
}