// dp[i][bit] := i番目までレシピを選んだ時、使った材料のxorがbitになるような場合のレシピの種類の最大数
// レシピbiを選んだ時
//      dp[i][bit xor b[i]] = max(dp[i][bit xor b[i]], dp[i-1][bit] + 1)
// 選ばなかったとき
//      dp[i][bit] = max(dp[i][bit], dp[i-1][bit])

// 1 <= n × m <= 500
// n <= 20 → 2^n の全探索できそう
// n > 20 → DP?

// m = 20 DPの要素数は、25 × 2^20 = 2×10^7 
// 直前の配列とその次の配列の二つだけにする？

#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1<<25;
int X1[MAX_N];
int X2[MAX_N];
bool Y1[MAX_N];
bool Y2[MAX_N];


// num := 選んだ数
// うまくいかなかった。。。。
int rec(vector<int> &b, int num, int cur, int bits) {
    if(cur >= b.size()) {
        if(bits == 0) return num;
        else return 0;
    }

    int res = 0;
    // cur番目を選ばない
    res = max(res, rec(b, num, cur+1, bits));
    // cur番目を選ぶ
    res = max(res, rec(b, num+1, cur+1, bits ^ b[cur]));

    return res;
}

int main()
{
    int n, m;
    while(cin >> n >> m, n | m) {
        // デバッグ
        // for(int i = 0; i < n; ++i) {
        //     cout << b[i] << endl;
        // }
        if(n <= 20) {
            vector<vector<int>> b(n, vector<int>(m, 0));
            for (int i = 0; i < n; ++i)
            {
                string s;
                cin >> s;
                for (int bit = 0; bit < m; ++bit)
                {
                    b[i][bit] = int(s[bit] - '0');
                }
            }
            // 全探索
            //cout << rec(b, 0, 0, 0) << endl;
            vector<int> state(m, 0);
            int res = 0;
            for(int bit = 0; bit < (1<<n); ++bit) {
                int tmp = 0;
                for(int i = 0; i < n; ++i) {
                    if((bit >> i) & 1) {
                        // 材料iを使う
                        for(int j = 0; j < m; ++j) {
                            state[j] += b[i][j];
                        }
                        ++tmp;
                    }
                }
                bool flg = true; // 偶奇チェック
                for(int i = 0; i < m; ++i) {
                    if(state[i]%2) flg = false;
                }
                if(flg) res = max(res, tmp);

                // state配列を初期化
                for(int i = 0; i < m; ++i) state[i] = 0;
            }
            cout << res << endl;
        }
        else {
            vector<int> b(n,0);
            for (int i = 0; i < n; ++i)
            {
                string s;
                cin >> s;
                for (int bit = 0; bit < m; ++bit)
                {
                    b[i] |= int(s[bit] - '0') << (m - 1 - bit);
                }
            }
            // DP
            int *prev = X1, *nxt = X2;
            bool *used1 = Y1, *used2 = Y2;
            // 初期化
            for(int i = 0; i < (1<<m); ++i) X1[i] = X2[i] = 0, used1[i] = used2[i] = false;
            used1[0] = true;

            for(int i = 0; i < n; ++i) {
                for(int bit = 0; bit < (1<<m); ++bit) {
                    nxt[bit] = prev[bit];
                }
                // レシピiを選んだとき
                for(int bit = 0; bit < (1<<m); ++bit) {
                    if(used1[bit]){
                        nxt[bit ^ b[i]] = max(nxt[bit ^ b[i]], prev[bit] + 1);
                        used2[bit ^ b[i]] = true;
                        used2[bit] = true;
                    }
                }

                // prevとnxtをスワップ
                swap(prev, nxt);
                swap(used1, used2);

                // nxtを初期化
                for (int bit = 0; bit < (1 << m); ++bit)
                    nxt[bit] = 0;
            }

            cout << prev[0] << endl;
        }
    }
    return 0;
}
