Go: package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

var (
	readString func() string
	readBytes  func() []byte
	stdout     *bufio.Writer
)

func init() {
	readString, readBytes = newReadString(os.Stdin)
	stdout = bufio.NewWriter(os.Stdout)
}

func newReadString(ior io.Reader) (func() string, func() []byte) {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), math.MaxInt32)
	r.Split(bufio.ScanWords)

	f1 := func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
	f2 := func() []byte {
		return []byte(f1())
	}
	return f1, f2
}

func readInt() int {
	return int(readInt64())
}

func readInt64() int64 {
	i, err := strconv.ParseInt(readString(), 10, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

func readFloat64() float64 {
	f, err := strconv.ParseFloat(readString(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

func printf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(stdout, f, args...)
}

func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(stdout, args...)
}

func eprintln(args ...interface{}) (int, error) {
	return fmt.Fprintln(os.Stderr, args...)
}

func eprintf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(os.Stderr, f, args...)
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func min64(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func max64(a, b int64) int64 {
	if a < b {
		return b
	}
	return a
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

func abs64(a int64) int64 {
	if a < 0 {
		return -a
	}
	return a
}

func gcd(a, b int) int {
	if b == 0 {
		return a
	}
	return gcd(b, a%b)
}

func gcd64(a, b int64) int64 {
	if b == 0 {
		return a
	}
	return gcd64(b, a%b)
}

// readString() string
// readInt() int
// readInt64() int64
// readFloat64() float64

// -----------------------------------------------------------------------------

func main() {
	defer stdout.Flush()

	for {
		ans, ok := solve()
		if !ok {
			break
		}
		println(ans)
	}

}

func solve() (int, bool) {
	w := readInt()
	h := readInt()
	if w == 0 && h == 0 {
		return 0, false
	}

	c := make([][]int, h+2)
	c[0] = make([]int, w+2)
	c[h+1] = make([]int, w+2)
	for i := 1; i-1 < h; i++ {
		c[i] = make([]int, w+2)
		for j := 1; j-1 < w; j++ {
			c[i][j] = readInt()
		}
	}

	var ans int
	for i := 1; i-1 < h; i++ {
		for j := 1; j-1 < w; j++ {
			if 0 < c[i][j] {
				ans++
				dfs(c, i, j)
			}
		}
	}
	return ans, true
}

func dfs(c [][]int, y, x int) {
	c[y][x] = 0
	dx := []int{-1, 0, 1, -1, 1, -1, 0, 1}
	dy := []int{-1, -1, -1, 0, 0, 1, 1, 1}
	for i := range dx {
		nx := x + dx[i]
		ny := y + dy[i]
		if 0 < c[ny][nx] {
			dfs(c, ny, nx)
		}
	}
}

// -----------------------------------------------------------------------------

C++: #include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <cassert>
#include <cfloat>
#include <complex>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>

using namespace std;

#define chmax(x, y) x = max(x, y)
#define chmin(x, y) x = min(x, y)
#define rep(i, n) for (ll i = 0; i < (n); ++i)
#define Sort(v) sort(v.begin(), v.end())
#define Reverse(v) reverse(v.begin(), v.end())
#define Lower_bound(v, x) \
  distance(v.begin(), lower_bound(v.begin(), v.end(), x))
#define Upper_bound(v, x) \
  distance(v.begin(), upper_bound(v.begin(), v.end(), x))

using ll = long long;
using ull = unsigned long long;
using P = pair<ll, ll>;
using T = tuple<ll, ll, ll>;
using vll = vector<ll>;
using vP = vector<P>;
using vT = vector<T>;
using vvll = vector<vector<ll>>;
using vvP = vector<vector<P>>;
using dqll = deque<ll>;

ll dx[9] = {-1, 1, 0, 0, -1, -1, 1, 1, 0};
ll dy[9] = {0, 0, -1, 1, -1, 1, -1, 1, 0};

const ll INF = 1LL << 50;

const ll mod = 1e9 + 7;

int main() {
  ll w, h;
  while (true) {
    cin >> w >> h;
    if (w == 0 && h == 0) break;
    vvll mp(h, vll(w, -1));
    vvll mk(h, vll(w, -1));
    rep(i, h) rep(j, w) cin >> mp[i][j];

    ll ans = 0;
    queue<P> que;
    bool pushcond;
    rep(i, h) {
      rep(j, w) {
        pushcond = mk[i][j] == -1 && mp[i][j] == 1;
        if (pushcond) {
          ans++;
          mk[i][j] = ans;
          que.emplace(i, j);
        }
        while (!que.empty()) {
          ll x, y;
          tie(y, x) = que.front();
          que.pop();
          mk[i][j] = ans;
          rep(k, 9) {
            ll nx = x + dx[k];
            ll ny = y + dy[k];
            bool insidecond = 0 <= nx && nx < w && 0 <= ny && ny < h;
            if (!insidecond) continue;
            pushcond = mk[ny][nx] == -1 && mp[ny][nx] == 1;
            if (pushcond) {
              mk[ny][nx] = ans;
              que.emplace(ny, nx);
            }
          }  // k
        }    // while
      }      // j
    }        // i

    cout << ans << endl;
  }
  return 0;
}

C++: #include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
#include <tuple>
#include <sstream>
#include <set>

struct Node
{
  int data;
  Node* parent;
  int rank;
  Node() : data(-1), parent(this), rank(0){}
  Node& operator=(int data){ this->data = data; return *this; }
  Node* Find(){
    if (this == this->parent){
      return this;
    } else {
      auto root = this->parent->Find();
      this->parent = root;
      return root;
    }
  }
  static void Union(Node& lhs, Node& rhs){
    Node* lhs_root = lhs.Find();
    Node* rhs_root = rhs.Find();
    if (lhs_root->rank > rhs_root->rank){
      rhs_root->parent = lhs_root;
    } else if (rhs_root->rank > lhs_root->rank){
      lhs_root->parent = rhs_root;
    } else if (rhs_root != lhs_root){
      lhs_root->parent = rhs_root;
      rhs_root->rank += 1;
    }
    return;
  }
};

bool is_not_space(int c){ return c != ' '; }
std::string& ltrim(std::string& str){
  str.erase(str.begin(), std::find_if(str.begin(), str.end(), is_not_space));
  return str;
}
std::string& rtrim(std::string& str){
  str.erase(std::find_if(str.rbegin(), str.rend(), is_not_space).base(), str.end());
  return str;
}
std::string trim(std::string& str){ return ltrim(rtrim(str)); }
std::vector<std::pair<int, int>> const delta = {{-1,1}, {0,1}, {1,1}, {1,0}};

int main(void)
{
  std::string buff;
  while(true){
    std::getline(std::cin, buff);
    int w, h;
    {
      std::stringstream ss(buff);
      ss >> w;
      ss >> h;
    }
    if(w == 0 && h == 0){ break; }
    std::vector<Node> V((w+2)*(h+2));
    auto to_index = [=](int i, int j) -> size_t { return i*(w+2) + j; };
    std::vector<std::vector<int>> C(h+2, std::vector<int>(w+2, 0));
    for(int i=1; i<=h; ++i){
      std::getline(std::cin, buff);
      std::stringstream ss(buff);
      for(int j=1; j<=w; ++j){
        ss >> C[i][j];
        if(C[i][j] == 1){ V[to_index(i,j)].data = to_index(i,j); }
      }
    }
    for(int i=1; i<=h; ++i){
      for(int j=1; j<=w; ++j){
        if(C[i][j] == 0){ continue; }
        for(auto& d: delta){
          int di = d.first, dj = d.second;
          if(C[i+di][j+dj] == 1){ Node::Union(V[to_index(i,j)], V[to_index(i+di, j+dj)]); }
        }
      }
    }
    std::set<int> cluster;
    for(int i=1; i<=h; ++i){
      for(int j=1; j<=w; ++j){
        cluster.insert(V[to_index(i,j)].Find()->data);
      }
    }
    cluster.erase(-1);
    std::cout << cluster.size() << std::endl;

  }

  return 0;
}