コード例 #1
0
long long num_divisible_sets(int *num_vals) {
  long long result;
  long long *num_sets;
  long long *temp_array;
  int j, k;

  // initialize num_sets to start with the empty set
  // (there is only 1 empty set, so there's 1 set who's sum
  //  of it's terms is 0 or divisible by 250)
  num_sets = (long long *)malloc(2 * 250 * sizeof(num_sets[0]));
  temp_array = &num_sets[250];
  memset(num_sets, 0, 250 * sizeof(num_sets[0]));
  num_sets[0] = 1LL;

  for (j = 0; j < 250; j++) {
    for (k = 0; k < num_vals[j]; k++) {
      next_row(num_sets, temp_array, j);
    }
  }

  result = num_sets[0];
  free(num_sets);

  return result;
}
コード例 #2
0
ファイル: common.cpp プロジェクト: phantasea/fim
int fim_common_test()
{	
	/*
	 * this function should test the correctness of the functions in this file.
	 * it should be used for debug purposes, for Fim maintainance.
	 * */
	printf("%d\n",0==lines_count("" ,6));
	printf("%d\n",0==lines_count("aab" ,6));
	printf("%d\n",1==lines_count("aaaaba\nemk" ,6));
	printf("%d\n",2==lines_count("aaaaba\nemk\n" ,6));
	printf("%d\n",3==lines_count("aaaabaa\nemk\n" ,6));
	printf("%d\n",*next_row("123\n",3)=='\0');
	printf("%d\n",*next_row("123\n4",3)=='4');
	printf("%d\n",*next_row("12",3)=='\0');
	printf("%d\n",*next_row("1234",3)=='4');
	return 0;
}
コード例 #3
0
ファイル: contact_table.cpp プロジェクト: cui-shuhai/projs
void contact_table::get_contact_records( string source, string &result ){
		string sql = "SELECT "
		"status AS contact_satus, first_name, last_name, contact_from AS contact_source , "
		"address, primary_phone, alt_phone, mobile_phone, fax, email, "
		"twitter, linkedin, facebook, job_title, company_id, "
		"when_met, where_met, time_zone, main_contact, "
		"out_of_marketing, out_of_billing, extra_info , contact_id "
		"FROM contact ";

		if(!source.empty()){
			sql.append("WHERE contact_from = ");
			sql.append("'").append(source).append("'");
		}

			query q(*conn, sql);
			LOG("sql", sql);
			auto res = q.emit_result();
		
			stringstream ss;

			bool first = true;
			ss << "{ \"contact\":[ ";
			do{
				if(first)
					first = false;
				else{
					ss << ", ";
				}
				ss << "{";
				ss << "\"contact_status\"" << ":" << "\"" << res->get_string(0) << "\"" << "," ;
				ss << "\"first_name\"" << ":" << "\"" << res->get_string(1) << "\"" << "," ;
				ss << "\"last_name\"" << ":" << "\"" << res->get_string(2) << "\"" << "," ;
				ss << "\"contact_source \"" << ":" << "\"" << res->get_string(3) << "\"" << "," ;
				ss << "\"address\"" << ":" << "\"" << res->get_string(4) << "\"" << "," ;
				ss << "\"primary_phone\"" << ":" << "\"" << res->get_string(5) << "\"" << "," ;
				ss << "\"alt_phone\"" << ":" << "\"" << res->get_string(6) << "\"" << "," ;
				ss << "\"mobile_phone\"" << ":" << "\"" << res->get_string(7) << "\"" << "," ;
				ss << "\"fax\"" << ":" << "\"" << res->get_string(8) << "\"" << "," ;
				ss << "\"email\"" << ":" << "\"" << res->get_string(9) << "\"" << "," ;
				ss << "\"twitter\"" << ":" << "\"" << res->get_string(10) << "\"" << "," ;
				ss << "\"linkedin\"" << ":" << "\"" << res->get_string(11) << "\"" << "," ;
				ss << "\"facebook\"" << ":" << "\"" << res->get_string(12) << "\"" << "," ;
				ss << "\"job_title\"" << ":" << "\"" << res->get_string(13) << "\"" << "," ;
				ss << "\"company_id\"" << ":" << "\"" << res->get_string(14) << "\"" << "," ;
			ss << "\"when_met\"" << ":" << "\"" << res->get_string(15) << "\"" << "," ;
			ss << "\"where_met\"" << ":" << "\"" << res->get_string(16) << "\"" << "," ;
			ss << "\"time_zone\"" << ":" << "\"" << res->get_string(17) << "\"" << "," ;
			ss << "\"main_contact\"" << ":" << "\"" << res->get_string(18) << "\"" << "," ;
			ss << "\"out_of_marketing\"" << ":" << "\"" << res->get_string(19) << "\"" << "," ;
			ss << "\"out_of_billing\"" << ":" << "\"" << res->get_string(20) << "\"" << "," ;
			ss << "\"extra_info\"" << ":" << "\"" << res->get_string(21) << "\"" << "," ;
			ss << "\"contact_id\"" << ":" << "\"" << res->get_string(22) << "\"" ;  
			ss << "}";
		} while(res->next_row());

		ss << " ] }";
		result = ss.str();
}
コード例 #4
0
ファイル: DebugConsole.cpp プロジェクト: phantasea/fim
		int MiniConsole::add(const char* cso)
		{
			char *s=NULL,*b=NULL;
			int nc;
			int nl,ol=cline;
			char *cs=NULL;/* using co would mean provoking the compiler */

			cs=dupstr(cso);

			if(!cs)goto rerr;
			nc=strlen(cs);
			if(!nc)goto rerr;
			nl=lines_count(cs,lwidth);
			// we count exactly the number of new entries needed in the arrays we have
			if((s=const_cast<char*>(strchr(cs,'\n')))!=NULL && s!=cs)nl+=(ccol+(s-cs-1))/lwidth;// single line with \n or multiline
			else nl+=(strlen(cs)+ccol)/lwidth;	// single line, with no terminators

			/*
			 * we check for room (please note that nl >= the effective new lines introduced , while
			 * nc amounts to the exact extra room needed )
			 * */
			if(nc+1+(int)(bp-buffer)>bsize || nl+1+cline>lsize)return -2;//no room : realloc needed ; 1 is for secur1ty
			scroll=scroll-nl<0?0:scroll-nl;

			// we copy the whole new string in our buffer
			strcpy(bp,cs);
			fim_free(cs); cs=NULL;
			sanitize_string_from_nongraph_except_newline(bp,0);
			s=bp-ccol;// we will work in our buffer space now on
			b=s;
			while(*s && (s=(char*)next_row(s,lwidth))!=NULL && *s)
			{
				line[++cline]=s;// we keep track of each new line
				ccol=0;
				bp=s;
			}// !s || !*s
			if(!*s && s-b==lwidth){line[++cline]=(bp=s);}// we keep track of the last line too
			

			if(ol==cline)
			{
				ccol=strlen(line[cline]);	// we update the current (right after last) column
				bp+=strlen(bp);	// the buffer points to the current column
			}
			else
			{
				ccol=strlen(bp);	// we update the current (right after last) column
				bp+=ccol;	// the buffer points to the current column
			}
			return 0;
rerr:
			fim_free(cs);
			return -1;
		}
コード例 #5
0
ファイル: activity_table.cpp プロジェクト: cui-shuhai/projs
void activity_table::get_activity_records( string source, string &result ){

		string count_sql = "SELECT count(1) "
			" FROM activity ";

		if(!source.empty())
			count_sql.append("WHERE activity_type = ").append(source);

		query count_query(*conn, count_sql);
		auto count_res = count_query.emit_result();
		if( count_res->get_int(0) == 0)
			return;
		

		string sql = "SELECT activity_id, activity_name, activity_type, activity_status, "
			" activity_priority, who_preside, when_created, note "
			" FROM activity ";

			
		if(!source.empty())
			sql.append("WHERE activity_type = ").append(source);

		query q(*conn, sql);
		LOG("sql", sql);
		auto res = q.emit_result();

		stringstream ss;

		//XXX should check count in case it is 0. there is a bug form sqlite count doesn't work

		bool first = true;
		ss << "{ \"activity\":[ ";
		do{
			if(first)
				first = false;
			else{
				ss << ", ";
			}

			ss << "{" ;
			ss << "\"activity_id\"" << ":" << "\"" << res->get_string(0) << "\"" << ",";
			ss << "\"activity_name\"" << ":" << "\"" << res->get_string(1) << "\"" << ",";
			ss << "\"activity_type\"" << ":" << "\"" << res->get_string(2) << "\"" << ",";
			ss << "\"activity_status\"" << ":" << "\"" << res->get_string(3) << "\"" << ",";
			ss << "\"activity_priority\"" << ":" << "\"" << res->get_string(4) << "\"" << ",";
			ss << "\"who_preside\"" << ":" << "\"" << res->get_string(5) << "\"" << ",";
			ss << "\"when_created\"" << ":" << "\"" << res->get_string(6) << "\"" << ",";
			ss << "\"note\"" << ":" << "\"" << res->get_string(7) << "\"" ;
			ss << "}";
		} while(res->next_row());

		ss << " ] }";
		result = ss.str();
}
コード例 #6
0
ファイル: simple_ctable.cpp プロジェクト: nathansgreen/anvil
bool simple_ctable::iter::advance(bool initial)
{
	for(;;)
	{
		if(!next_row(initial))
			return false;
		if(next_column(true))
			return true;
		if(!initial)
			source->next();
	}
}
コード例 #7
0
ファイル: reflbin.c プロジェクト: reflectometry/reduction
/* Assumes that v is initialized to 0 beyond last column */
void save_row(mxtype *v, int n)
{
  int i, w;

#ifdef DEBUG
  printf(";\n");
#endif

  /* Add the next line of the frame to the current row */
  if (frame_r >= ystart && frame_r <= ystop) {
    mxtype *row_data = matrix + frame_h*frame_w;
    int bin;
    bin = w = 0;
    for (i = 0; i < xstart && i < n; i++) ignored_counts += v[i];
    for (i = xstart; i < n && i <= xstop; i++) {
      row_data[bin] += v[i];
      recorded_counts += v[i];
      if (++w == width) { bin++; w=0; }
    }
    for (i = xstop+1; i < n; i++) ignored_counts += v[i];

    /* Decide what to do with partial bins */
    if (save_partial) {
      if (w != 0) bin++; /* Keep partial bin always */
    } else if (bin == 0 && w != 0) 
      bin++; /* Keep partial bin if it is the only one */
    else { 
      /* Ignore partial bin; update accounting */
      recorded_counts -= row_data[bin]; 
      ignored_counts += row_data[bin]; 
    }

    // printf("; columns=%d, n=%d\n", columns, n);
    /* Check the number of columns in the datafile. */
    if (columns == 0) { 
      columns = bin; 
    } else if (warn_dims && bin != columns) {
      warn_dims = 0;
      fprintf(stderr, "ignoring inconsistent number of columns\n");
      bin = columns; /* Assume remainder of v is zero */
    }
    frame_w = bin;

    /* Move to next row if at the end of vertical accumulation. */
    if (++rows_accumulated == height) next_row();
  } else {
    for (i = 0; i < n; i++) ignored_counts += v[i];
  }
  frame_r++;
}
コード例 #8
0
ファイル: raster.c プロジェクト: rashadkm/grass_cmake
/*!
  \brief Draw raster row

  \param n number of cells
  \param row raster row (starts at 0)
  \param red,grn,blu,nul red,green,blue and null value

  \return next row
*/
int PNG_raster(int n, int row,
	       const unsigned char *red, const unsigned char *grn,
	       const unsigned char *blu, const unsigned char *nul)
{
    int d_y0 = scale_fwd_y(row + 0);
    int d_y1 = scale_fwd_y(row + 1);
    int d_rows = d_y1 - d_y0;
    int x0 = max(png.clip_left - dst[0][0], 0);
    int x1 = min(png.clip_rite - dst[0][0], ncols);
    int y0 = max(png.clip_top - d_y0, 0);
    int y1 = min(png.clip_bot - d_y0, d_rows);
    int x, y;

    if (y1 <= y0)
	return next_row(row, d_y1);

    for (x = x0; x < x1; x++) {
	int xx = dst[0][0] + x;
	int j = trans[x];
	int c;

	if (masked && nul && nul[j])
	    continue;

	c = png_get_color(red[j], grn[j], blu[j], 0);

	for (y = y0; y < y1; y++) {
	    int yy = d_y0 + y;

	    png.grid[yy * png.width + xx] = c;
	}
    }

    png.modified = 1;

    return next_row(row, d_y1);
}
コード例 #9
0
ファイル: quickblob.c プロジェクト: keenerd/quickblob
int extract_image(void* user_struct)
{
    struct stream_state stream;
    struct blob_list blist;
    struct blob* blob_now = NULL;
    struct blob* blob_prev = NULL;

    if (init_pixel_stream(user_struct, &stream))
        {printf("init malloc error!\n"); return 1;}
    if (stream.row == NULL)
        {printf("row malloc error!\n"); return 1;}
    blist.length = stream.w + 5;
    if (malloc_blobs(&blist))
        {printf("blob malloc error!\n"); return 1;}

    while (!next_frame(user_struct, &stream))
    {
        init_blobs(&blist);
        while (!next_row(user_struct, &stream))
        {
            blob_prev = blist.head->next;
            while (!stream.wrap)
            {
                blob_now = empty_blob(&blist);
                if (scan_segment(&stream, blob_now))
                    {blob_reap(&blist, blob_now); continue;}
                blob_update(blob_now, blob_now->x1, blob_now->x2, stream.y);
                // update structure
                sib_find(blist.head->next, blob_now);
                blob_insert(blob_prev, blob_now);
                flush_incremental(user_struct, &blist, blob_now);
                blob_prev = blob_now;
            }
            flush_old_blobs(user_struct, &blist, stream.y);
            //show_status(blist.head, &stream);
            //show_dead_sibs(blist.head);
            //show_blobs(blist.head);
            //printf("----------\n");
        }
        flush_old_blobs(user_struct, &blist, stream.h - 1);
    }

    close_pixel_stream(user_struct, &stream);
    free(blist.head);
    free(blist.empties);
    blist.head = NULL;
    blist.empties = NULL;
    return 0; 
}
コード例 #10
0
ファイル: world_impl.cpp プロジェクト: Ryuuke/desperion
void world::impl::load_game_servers()
{
    auto time = std::chrono::system_clock::now();
    auto qr = g_database.query({ sql_database::prepare("load") });
    if (!qr)
        return;
    do
    {
        auto && fields = qr.fetch();
        auto id = fields.at("id").get<int16_t>();
        _game_servers.emplace(std::piecewise_construct,
                              std::forward_as_tuple(id),
                              std::forward_as_tuple(id, fields));
    } while (qr.next_row());
    std::cout << _game_servers.size() << " game server(s) loaded in "
        << (std::chrono::system_clock::now() - time).count() << " microseconds" << std::endl;
}
コード例 #11
0
ファイル: adjacency_matrix.cpp プロジェクト: fons/graph-repl
adjacency_matrix::row_then_coll_iterator::iter_state_t&
adjacency_matrix::row_then_coll_iterator::next(size_t size, size_t width, iter_state_t& i) {
      if (row(i) < width) {                        
            next_row(i);                 
      }
      if (row(i) == width && coll(i) < width) {
            next_coll(i);                                          
            if (coll(i) < width) {
                  i = iter_state_t(0, coll(i));                     
            }                        
      }     
      
      if ((row(i) == width) && (coll(i) == width)) {
            i = iter_state_t(size, size);   
      }
      
      return i;
}
コード例 #12
0
ファイル: xapp.cpp プロジェクト: Mokosha/COMP590
static void fill_circle(const GBitmap& bm) {
    int w = bm.width();
    int h = bm.height();
    int r = (w < h ? w : h) >> 1;
    float cx = w/2;
    float cy = h/2;
    float rr = (float)r * r;

    GPixel* row = bm.fPixels;
    for (int y = 0; y < h; ++y) {
        float dy2 = (y - cy) * (y - cy);
        for (int x = 0; x < w; ++x) {
            float dx2 = (x - cx) * (x - cx);
            if (dx2 + dy2 > rr) {
                row[x] = 0;
            }
        }
        row = next_row(bm, row);
    }
}
コード例 #13
0
ファイル: virtterm.c プロジェクト: AnupreetKJohar/weenix
void
vt_provide_char(tty_driver_t *ttyd, char c)
{
        KASSERT(NULL != ttyd);

        virtterm_t *vt = driver_to_vt(ttyd);

        /* Store for optimizing */
        int old_cursor = vt->vt_cursor;
        int old_top = vt->vt_top;
        int can_write_char;

        /* If cursor is not on the screen, we move top */
        if (circ_dist(vt->vt_cursor, vt->vt_top) >= DISPLAY_SIZE) {
                /* Cursor should be on the last row in this case */

                vt->vt_top = next_row(vt->vt_cursor);
                buf_add(vt->vt_top, -DISPLAY_SIZE);
        }

        can_write_char = vt_handle_char(vt, c);

        /* Redraw if it's the current terminal */
        if (vt_curterm == vt) {
                /*
                 * Check if we can optimize (just put 1 char instead
                 * of redrawing screen)
                 */
                if (old_top == vt->vt_top) {
                        if (can_write_char) {
                                int rel_cursor = circ_dist(old_cursor, vt->vt_top);
                                screen_putchar(c, rel_cursor %
                                               DISPLAY_WIDTH,
                                               rel_cursor / DISPLAY_WIDTH);
                        }
                        vt_cursor_redraw();
                } else {
                        vt_redraw();
                }
        }
}
コード例 #14
0
void opportunity_table::get_opportunity_records( string source, string &result ){

	string sql = "SELECT opportunity_name, assign_to, "
		"contact_id, creator_id, close_date, pipeline, amount, probablity , opportunity_id  "
	" FROM opportunity "; 

		if(!source.empty())
		sql.append("WHERE opportunity_id = ").append(source);
		query q(*conn, sql);
		LOG("sql", sql);
		auto res = q.emit_result();
	
		stringstream ss;

		bool first = true;
		ss << "{ \"opportunity\":[ ";
		do{
			if(first)
				first = false;
			else{
				ss << ", ";
			}
			ss << "{" ;
			ss << "\"opportunity_id\"" << ":" << "\"" <<  res->get_string(8) << "\"" << ","; 
			ss << "\"opportunity_name\"" << ":" << "\"" <<  res->get_string(0) << "\"" << ",";
			ss << "\"assign_to\"" << ":" << "\"" <<  res->get_string(1) << "\"" << ",";
			ss << "\"contact_id\"" << ":" << "\"" <<  res->get_string(2) << "\"" << ",";
			ss << "\"creator_id\"" << ":" << "\"" <<  res->get_string(3) << "\"" << ",";
			ss << "\"close_date\"" << ":" << "\"" <<  res->get_string(4) << "\"" << ",";
			ss << "\"pipeline\"" << ":" << "\"" <<  res->get_string(5) << "\"" << ",";
			ss << "\"amount\"" << ":" << "\"" <<  to_string(res->get_double(6)) << "\"" << ",";
			ss << "\"probablity\"" << ":" << "\"" <<  res->get_string(7) << "\""; 
			ss << "}";
		} while(res->next_row());

		ss << " ] }";
		result = ss.str();
}
コード例 #15
0
ファイル: contact_table.cpp プロジェクト: cui-shuhai/projs
void contact_table::get_contact_list(std::map<string, string> &contacts){
	auto count_sql = "SELECT count(1) FROM contact";

	query count_query(*conn, count_sql);
	auto count_res = count_query.emit_result();
	auto rows = count_res->get_int(0);

	if(rows == 0)
		return;

	string sql = "SELECT contact_id, first_name, last_name, contact_from.description "
		"FROM contact INNER JOIN contact_from ON contact.contact_from = contact_from.contact_from";
	
	query q(*conn, sql);

	LOG("sql", sql);
	auto res = q.emit_result();

	do{
		string contact_item = res->get_string(1) + " " + res->get_string(2) +": " + res->get_string(3);
		contacts[res->get_string(0)] = contact_item;
	} while(res->next_row());
}
コード例 #16
0
 int ObSSTableBlockScanner::store_and_advance_row()
 {
   int ret = OB_SUCCESS;
   if (OB_UNLIKELY(row_cursor_ < row_start_index_ || row_cursor_ > row_last_index_))
   {
     TBSYS_LOG(ERROR, "internal error, current row cursor=%d,%d < start=%p, >last=%p.",
         row_cursor_->offset_, row_cursor_->size_, row_start_index_, row_last_index_);
     ret = OB_ERROR;
   }
   else if (OB_SUCCESS != (ret = 
         reader_.get_row(static_cast<int>(sstable_data_store_style_),
           row_cursor_, is_full_row_scan_, query_column_indexes_, 
           current_rowkey_, current_row_))) 
   {
     TBSYS_LOG(ERROR, "read current row error, store style=%ld, current row cursor=%d,%d",
         sstable_data_store_style_, row_cursor_->offset_, row_cursor_->size_);
   }
   else
   {
     next_row();
   }
   return ret;
 }
コード例 #17
0
ファイル: virtterm.c プロジェクト: AnupreetKJohar/weenix
/* Puts the given char into the given terminal's buffer, moving the
 * cursor accordingly for control chars Returns 1 if char can be
 * echoed (non-control char), 0 otherwise */
static int
vt_handle_char(virtterm_t *vt, char c)
{
        KASSERT(NULL != vt);

        /* Start where the cursor currently is located */
        int new_cursor = vt->vt_cursor;
        int ret = 0;
        switch (c) {
                case '\b': /* Move cursor back one space */
                        /* the user can't backspace past the beginning */
                        if (new_cursor != vt->vt_head)
                                buf_dec(new_cursor);
                        break;
                case '\r':
                        new_cursor = (new_cursor / DISPLAY_WIDTH) * DISPLAY_WIDTH;
                        break;

                        /* In the next two cases, the cursor advances, and we
                         * need to compare it with the end of the buffer to
                         * determine whether or not to advance the buffer
                         * tail */

                case '\n': /* To beginning of next line */
                        new_cursor = next_row(new_cursor);
                        goto handle_tail;
                default:
                        /* Actually put a char into the buffer */
                        vt->vt_buf[new_cursor] = c;
                        /* And increment */
                        buf_inc(new_cursor);
                        ret = 1;

handle_tail: /* Yuck */
                        if (circ_dist(new_cursor, vt->vt_cursor) >=
                            circ_dist(vt->vt_tail, vt->vt_cursor)) {
                                /* Current cursor pos past tail of the current
                                 * buffer, so advance tail */
                                int new_tail = next_row(new_cursor);
                                /* Check for head adjusting (if we write
                                 * enough that the scroll buffer fills up, we
                                 * sacrifice chars near the head) */
                                if (circ_dist(vt->vt_tail, vt->vt_head) >=
                                    circ_dist(vt->vt_tail, new_tail)) {
                                        vt->vt_head = next_row(new_tail);
                                }

                                /* Remember to clear space we may have acquired */
                                if (vt->vt_tail <= new_tail) {
                                        memset(vt->vt_buf + vt->vt_tail,
                                               0, new_tail - vt->vt_tail);
                                } else {
                                        memset(vt->vt_buf + vt->vt_tail,
                                               0, SCROLL_BUFSIZE - vt->vt_tail);
                                        memset(vt->vt_buf, 0, new_tail);
                                }
                                /* Finally, set the new tail */
                                vt->vt_tail = new_tail;
                        }
                        break;
        }
        vt->vt_cursor = new_cursor;
        return ret;
}
コード例 #18
0
ファイル: list_io.hpp プロジェクト: cran/Boom
 void stream() override { callback_->put_vector(next_row()); }
コード例 #19
0
ファイル: main.c プロジェクト: jaseg/fw-vfd
int main(void) {
     /* pin map:
      *
      * PB0 hardware shift (r/l, TODO: split r/l)
      * PB1 row data out (to 74HC595)
      * PB2 row shift (same)
      * PB3 row X8 direct output
      * PB4 col in  Y9
      * PB5 col in  Y8
      * PB6 XTAL
      * PB7 XTAL
      *
      * PC0 col in  Y5
      * PC1 col in  Y0
      * PC2 col in  Y1
      * PC3 col in  Y2
      * PC4 col in  Y3
      * PC5 col in  Y4
      * PC6 !RESET
      *
      * PD0 RXD
      * PD1 TXD
      * PD2 col in  Y6
      * PD3 col in  Y7
      * PD4 NC
      * PD5 NC
      * PD6 NC
      * PD7 NC
      *
      * We're not un-scrambling the rows here, we are just using them directly to index the lookup table.
      *
      * The device outputs 9N1 (!) data on its uart. The 9th bit indicates key press (1) or release (0), the remaining 8
      * bits the USB HID keycode.
      */
    DDRB   = 0x0f; /* row outputs, shift */

    /* uart setup */
    DDRD  |= 0x02;
    UBRR0  = F_CPU/16/(BAUDRATE-1);
    UCSR0B = (1<<TXEN0) | (1<<UCSZ02);
    UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);

    int ridx = 0;
    reset_row();
    while (23) {
        uint16_t cols = read_cols();

        uint8_t cidx = ridx;
        if (ridx == 30)
            cols |= (PINB&1)<<1; /* map hard shift to keycode 0x1f (31) */
        while (cidx < ridx+10) {
            if (keystate[cidx] > 1) {
                keystate[cidx]--;
            } else if (keystate[cidx] < 0) {
                keystate[cidx]++;
            } else {
                uint8_t c = keymap[cidx];
                if (cols & 1) {
                    if (!keystate[cidx]) {
                        keystate[cidx] = DEBOUNCE_TIME;
                        report_down(c);
                    }
                } else {
                    if (keystate[cidx]) {
                        keystate[cidx] = -DEBOUNCE_TIME;
                        report_up(c);
                    }
                }
            }
            cidx ++;
            cols >>= 1;
        }

        if (ridx == 80) {
            ridx = 0;
            reset_row();
        } else {
            ridx += 10;
            next_row();
        }
        _delay_us(100);
    }
}