#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include<vector>
#include<cstring>
#include<set>
#include <cstdio>
#include<queue>
#include<map>


#define endl '\n'
#define forup(i,a,n) for( int i =a; i < n; i++)
#define llforup(i,a,n) for( ll i =a; i < n; i++)
#define fordown(i,a,n) for( int i =a; i >= n; i--)
#define fornot(i,a,n) for( int i=a;!n;i++)
#define mod  (ll)(1e9+7)
#define putnum(a) printf("%d\n",a)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

inline int readnum()
{
	int p, data = 0; char ch = 0;
	while ((ch != '-') &&( ch < '0' || ch>'9') )//注意运算优先级，逻辑与大于逻辑非
		ch = getchar();//相当于正则表达式的搜索，跳过不需要的字符
	if (ch == '-')
		p = -1, ch = getchar();//不能与if平行放置，不懂为什么，可能是bug
	else p = 1;
	while (ch >= '0' && ch <= '9') data = data * 10 + ch - '0', ch = getchar();//搜索需要的字符
	return data * p;
}
inline int ReadPossitive()
{
	char ch; int data = 0;
	ch = getchar();
	while (ch == ' ' || ch == '\n')ch = getchar();
	while (ch != ' ' && ch != '\n' && ch != EOF)
	{
		data = data * 10 + ch - '0';
		ch = getchar();
	}
	return data;
}
//并查集模板
class DisjointSet {
private:
	vector<int>rank, parent;
public:
	DisjointSet(){}
	DisjointSet(int size)
	{
		rank.resize(size, 0);//默认初始化为0，养成习惯写完整
		parent.resize(size, 0);
		forup(i, 0, size)MakeSet(i);
	}
	void MakeSet(int x)
	{
		parent[x] = x;
		rank[x] = 0;
	}
	bool same(int x, int y)
	{
		return Findroot(x) == Findroot(y);
	}
	void unite(int x, int y)
	{
		link(Findroot(x), Findroot(y));
	}
	inline int Findroot(int x)
	{
		while (x != parent[x])
		{
			x = parent[x];
		}
		return x;
	}
	void link(int rootx, int rooty)
	{
		if (rank[rootx] < rank[rooty])parent[rootx] = parent[rooty];
		else
		{
			parent[rooty] = parent[rootx];
			if (rank[rootx] == rank[rooty])
				rank[rootx]++;
		}
	}
};
//Rabin-Karp哈希模板
class RKhush {
public:
	ull* positiveHush=NULL, *invertedHush=NULL;//野指针不能用delete
	ull* p=NULL;//指数
	const int base = 131;
    int str_len=0;
public:
	RKhush() {};
	
	RKhush(char* str,int control)
	{//如何更安全更便捷？
#define All 0
#define Positive 1
#define Inverted -1
		str_len = strlen(str+1) + 10;//加一这种细节要注意
		if (control == All)
		{
			p = new ull[str_len + 10]; p[0] = 1;
			positiveHush = new ull[str_len + 10]; positiveHush[0] = 0;
			invertedHush = new ull[str_len + 10]; invertedHush[0] = 0;
			for (int i = 1, j = str_len; i < str_len + 1; i++, j--)
			{
				positiveHush[i] = positiveHush[i - 1] * base + str[i] - 'a' + 1;//外部str必须从下标1开始存
				invertedHush[i] = invertedHush[i - 1] * base + str[i] - 'a' + 1;
				p[i] = p[i - 1] * base;
			}
		}
		else if (control == Positive)
		{
			p = new ull[str_len + 10]; p[0] = 1;
			positiveHush = new ull[str_len + 10]; positiveHush[0] = 0;
			for (int i = 1; i < str_len; i++)
			{
				positiveHush[i] = positiveHush[i - 1] * base + str[i] - 'a' + 1;
				
				p[i] = p[i - 1] * base;
			}
		}
		else if (control ==Inverted)
		{
			p = new ull[str_len + 10]; p[0] = 1;
			invertedHush = new ull[str_len + 10]; invertedHush[0] = 0;
			for (int i = 1, j = str_len; i < str_len + 1; i++, j--)
			{
				invertedHush[i] = invertedHush[i - 1] * base + str[i] - 'a' + 1;
				p[i] = p[i - 1] * base;
			}
		}
#undef All
#undef Positive
#undef Inverted
	}
	~RKhush()
	{
		delete[]positiveHush;
		delete[]invertedHush;
		delete[]p;
	}
	ull getHushKey_positive(char*str, int l, int r)//l,r代表字符串最左边、最右边字符出现的位置，注意下标从1开始
	{
		return  positiveHush[r] -positiveHush[l - 1] * p[r - l + 1];
	}
	ull getHushKey_inverted(char* str, int l, int r)//str应该有更多样的操作，所以不把str封存到RK中，RK可能只是处理str的其中一样操作
	{
		return invertedHush[r] - invertedHush[l - 1] * p[r - l + 1];//hush[r]与hush[l-1]不同点在于多了hush[r-l]的部分并且继承过来的hush[l-1]部分的指数升高了r-l+1（区间长度）个单位大小
	}
};
//KMP目标模板
class KMP {
public:
	int *nextMatch=NULL;
	int str_len;
	int backto, cur;//也可以理解为backto是前缀，cur是后缀
public:
	KMP() {};
	KMP(char str[])
	{
		initial(str);
		while (cur < str_len)
		{
			if (str[cur] == str[backto])
			{
				cur++;
				backto++;
				nextMatch[cur] = backto;//注意前k位第匹配结果影响第k+1位的回溯12341235,5回溯到4，大抵如此	
			}//最后多出来的一位用于查找多个匹配，每次匹配完成后的回溯
			else
			{
				if (backto!= 0)
				{//寻找更小子串,一个小动态规划，不断用更小子串进行自身匹配，直到找到合适的子串。
					backto = nextMatch[backto];
				}
				else
				{
					nextMatch[++cur] = 0;//影响的是后一位的结果
				}
			}
		}
	}
private:
	inline void initial(char str[])
	{
	    str_len = strlen(str);
		nextMatch = new int[str_len + 1];
		nextMatch[0] =0;
		nextMatch[1] = 0;
		backto = 0;
		cur = 1;
		//Next中存储的是从0开始到k的最长合适前缀的长度，我们将其减一就得了回溯坐标：第k个位置匹配失败时下次匹配的位置
	}
public:
	void regainNext(char str[])
	{
		initial(str);
		while (cur < str_len)
		{
			if (str[cur] == str[backto])
			{
				if (str[cur])
					nextMatch[cur] = backto;
				cur++;
				backto++;
			}
			else
			{
				if (backto != 0)
				{//自身匹配,寻找更小子串
					backto = nextMatch[backto];
				}
				else
				{
					nextMatch[cur] = 0;
					cur++;
				}
			}
		}
	}
	int KMPMatch(char txt[],char pattern[])
	{
		int txt_len = strlen(txt), pattern_len = strlen(txt);
		int i = 0, j = 0;
		while (i < txt_len && j < pattern_len)
		{
			if (txt[i] == pattern[j])
			{
				i++;
				j++;
			}
			else
			{
				if (j != 0)
				{
					j = nextMatch[j];
				}
				else i++;
			}
		}
		if (j == pattern_len)return i-pattern_len;
		else return -1;
	}
	void KMPSearch(char txt[], char pattern[], vector<int>& save)
	{
		int txt_len = strlen(txt), pattern_len = strlen(pattern);
		int i = 0, j = 0;
		while (i < txt_len)
		{
			if (txt[i] == pattern[j])
			{
				i++;
				j++;
				if (j == pattern_len)
				{
					save.push_back(i - j);
					//i不变
					j = nextMatch[j];
				}
			}
			else
			{
				if (j != 0)
				{
					j = nextMatch[j];
				}
				else i++;
			}
		}
	}
};
//计算几何模板
#define EPS (1e-10)//注意：<EPS代表数据<=0,>EPS代表数据>0,若要求数据<0请使用<-EPS进行判断
#define equals(a,b) (fabs((a)-(b))<EPS)//保留整数0
class Point {
public:
	double x, y;
public://p不能为引用的问题怎么解决？答用右值引用解决,两个以上的参数要都装载左右引用要四套板子，麻烦，所以引用的方法我们只对单参数使用
	Point() {};
	Point(double x,double y):x(x),y(y){}
	Point operator +(const Point &p) const{ return Point(x + p.x, y + p.y);}
	Point operator -(const Point &p) const{ return Point(x - p.x, y - p.y);}
	Point operator *(double a) const{ return Point(a * x, a * y); }
	Point operator /(double a) const{ return Point(x / a, y / a); }
	inline double abs() { return sqrt(norm()); }
	inline double norm() { return x * x + y * y; }
	bool operator <(const Point& p)const {
		return x != p.x ? x < p.x : y < p.y;
	}
	bool operator ==(const Point& p)const {
		return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
	}
	//右值组
	Point operator +(Point&& p) const{ return Point(x + p.x, y + p.y); }
	Point operator -(Point&& p) const{ return Point(x - p.x, y - p.y); }
};
typedef Point Vector;

class Line {
public:
	Point p1, p2;
public:
	Line() {};
	Line(int p1x, int p1y, int p2x, int p2y)
	{
		p1.x = p1x; p1.y = p1y;
		p2.x = p2x; p2.y = p2y;
	}
};

class Circle {
public:
	Point c; double r;
public:
	Circle() {}
	Circle(Point c,double r):c(c),r(r){}
	Circle(double cx, double cy, double cr)
	{
		c.x = cx; c.y = cy; r = cr;
	}
};

typedef vector<Point> _Polygon;

typedef vector<Point> PointSet;

class VectorOperation {//操作符不必继承
public:
	double dot(Point a, Point b)const//点乘
	{
		return a.x * b.x + a.y * b.y;
	}
	double cross(Point a, Point b)const//叉乘
	{
		return a.x * b.y - a.y * b.x;
	}
	double abs(Vector s)
	{
		return sqrt(s.norm());
	}
	double getDistance(Point a, Point b)
	{
		return abs(a - b);
	}
	int PositionPL(Point p0, Point p1, Point p2)
	{
#define COUNTER_CLOCKWISE -1
#define CLOCKWISE 1
#define ONLINE_BACK -2
#define ONLINE_FRONT 2
#define ON_SEGMENT 0
		Vector a = p1 - p0;Vector b = p2 - p0;
		double Cross = cross(a, b);
		if (Cross > 0.0)return COUNTER_CLOCKWISE;
		if (Cross < 0.0)return CLOCKWISE;
		if (dot(a, b) < 0.0)return ONLINE_BACK;
		if (a.norm() < b.norm())return ONLINE_FRONT;

		return ON_SEGMENT;
#undef COUNTER_CLOCKWISE 
#undef CLOCKWISE 
#undef ONLINE_BACK 
#undef ONLINE_FRONT 
#undef ON_SEGMENT 
	}
	double inclination(Vector s)
	{
		return atan2(s.y, s.x);//取值范围-pi~pi
	}
	Vector Polar(double a, double r) { return Vector(cos(a) * r, sin(a) * r); }
	Vector rotate(Point a, double rad)//逆时针旋转
	{
		return Vector(a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad));
	}
};

class LineOperation :public VectorOperation{
public:	
	bool isOrthogonal(Line s1, Line s2)
	{
		return equals(dot(s1.p2-s1.p1, s2.p2 - s2.p1), 0.0);//操作符重载的返回值的内存分配机制尚不可知，似乎返回值没有分配内存，dot的参数不能用引用，否则报错。
	}
	bool isParallel(Line s1, Line s2)
	{
		return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);//外积判断平行，内积判断垂直。
	}
	bool intersectSS(Line s1, Line s2)
	{
		return (PositionPL(s1.p1, s1.p2, s2.p1) * PositionPL(s1.p1, s1.p2, s2.p2) <= 0 &&
			    PositionPL(s2.p1, s2.p2, s1.p1) * PositionPL(s2.p1, s2.p2, s1.p2) <= 0);//即对两条线段都有另一条线段的两个端点必须在当前线段的两侧
	}//可以证明如果一条线段的计算结果是负二，另一个线段的计算结果必定大于0
	Point projection(Line s, Point p)
	{
		Vector base = s.p1 - s.p2;
		double r = dot(p - s.p1, base) /base.norm();
		return s.p1 + base * r;
	}
	Point reflection(Line s, Point p)
	{
		return p + (projection(s, p)-p) * 2.0;
	}
	double getDistanceLP(Line s, Point p)//点与直线
	{
		return fabs(cross(s.p2 - s.p1, p - s.p1)) / abs(s.p2 - s.p1);
	}
	double getDistanceSP(Line s, Point p)//点与线段
	{
		if (dot(s.p2 - s.p1, p - s.p1) < 0.0)return abs(p - s.p1);//与点p1成钝角
		else if (dot(s.p2 - s.p1, p - s.p2) > 0.0)return abs(p - s.p2);
		else return getDistanceLP(s, p);
	}
	double getDistanceSS(Line s1, Line s2)//线段与线段
	{
		//考虑
		// --
		//----
		if (intersectSS(s1, s2))return 0.0;//如果枚举优化需要16次逻辑，采用分治法的效率和直接使用min函数一样
		else
			return min(min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)), min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2)));
	}
	Point getCrossPointSS(Line s1, Line s2)
	{
		Vector base = s2.p2 - s2.p1;
		double d1 = fabs(cross(base, s1.p1 - s2.p1));//除以abs(base)这步因为在t中base被消去所以没有写，提升效率
		double d2 = fabs(cross(base, s1.p2 - s2.p1));
		double t = d1 / (d1 + d2);
		return s1.p1 + (s1.p2 - s1.p1) * t;
	}
	Point getCrossPointLL(Line s1, Line s2)
	{
		Vector a = s1.p2 - s1.p1;
		Vector b = s2.p2 - s2.p1;
		return (s1.p1 + a*(cross(b, s2.p1 - s1.p1)) / cross(b, a));
	}
};

class CircleOperation :public VectorOperation{
public:
	int intersectCL(Line s,Circle c)
	{
		LineOperation op;
		double distance = op.getDistanceLP(s, c.c);
		double comparation = distance - c.r;
		if (comparation < EPS)return 1;
		if (comparation < 0.0)return 2;
		if (comparation > 0.0)return 0;
	}
	int intersectCC(Circle c1, Circle c2)
	{
		double distanceR = c1.r + c2.r;
		double distancePR = getDistance(c1.c, c2.c);
		double comparation = distancePR - distanceR;
		if (comparation < EPS)return 1;
		if (comparation > 0.0)return 0;
		if (comparation < 0.0)return 2;
	}
	pair<Point,Point> getCrossPointCL(Circle c,Line s)
	{
		LineOperation op;
		Point CLprojection = op.projection(s, c.c);
		Vector CL = CLprojection - c.c;
		Vector e = (s.p2 - s.p1) / abs(s.p2 - s.p1);
		double base = sqrt(c.r * c.r - CL.norm());
		return make_pair(CLprojection + e * base, CLprojection - e * base);
		//可以处理仅有一个交点的情况base是0产生两个同解。sqrt要求必须是正数，使用前必须进行有解性判断。
	}
	pair<Point, Point> getCrossPointCC(Circle c1, Circle c2)
	{
		double CC = abs(c1.c - c2.c);
		double a = acos((c1.r * c1.r + CC * CC - c2.r * c2.r) / (2 * c1.r * CC));//余弦定理
		double t = inclination(c2.c - c1.c);
		return make_pair(c1.c + Polar(t + a, c1.r), c1.c + Polar(t - a, c1.r));
	}
};


class PolygonOperation :public VectorOperation{
public:
	int PointsContainment(_Polygon &g,Point p)//ON_SEGMENT 0 IN 1 OUT 2
	{
#define ON_SEGMENT 0
#define IN 1
#define OUT 2
		int size = g.size();
		bool x = false;
		Vector a, b;
		forup(i, 0, size)
		{
			a = g[i] - p; b = g[(i+1)%size] - p;//用取模创造循环
			if (fabs(cross(a, b)) < EPS && dot(a, b) < EPS)return ON_SEGMENT;//<EPS包含了内积为负数的情况
			if (a.y < b.y)
			{
				double test = cross(a, b);
				if (a.y < EPS && EPS<b.y && cross(a, b)>EPS)x = !x;
			}
			else
			{
				if (b.y < EPS && EPS<a.y && cross(b, a)>EPS)x = !x;//射线平行x轴指向x轴正向,如果是.----平行的情况跳过，不会更改x值EPS<a.y不成立
			}//如果是-----.的情况，则会“触碰“到两条边，该判断方法仍然正确：触碰到偶数条边时点在多边形外部
		}
		return x ? IN : OUT;
#undef ON_SEGMENT
#undef IN
#undef OUT
	}
	_Polygon andrewScan(_Polygon s)
	{
#define COUNTER_CLOCKWISE -1
#define CLOCKWISE 1
#define ONLINE_BACK -2
#define ONLINE_FRONT 2
#define ON_SEGMENT 0
		_Polygon u, l;
		if (s.size() < 3)return s;
		sort(s.begin(), s.end());
		u.push_back(s[0]);
		u.push_back(s[1]);
		l.push_back(s[s.size() - 1]);
		l.push_back(s[s.size() - 2]);
		for (int i = 2; i < s.size(); i++)
		{
			for (int n = u.size(); n >= 2 ; n--) {
				int test = PositionPL(u[n - 2], u[n - 1], s[i]);
				if (test == COUNTER_CLOCKWISE)
				u.pop_back();
				else break;
			}
				
			u.push_back(s[i]);
			
		}
		for (int i = s.size() - 3; i >= 0; i--)
		{
			
			for (int n = l.size(); n >= 2 ; n--)
			{
				int test = PositionPL(l[n - 2], l[n - 1], s[i]);
				if(test==COUNTER_CLOCKWISE)//如果即将新加入的点与倒数第二、倒数第一个点组成的向量成逆时针方向（倒数第二指向倒数第一），就删除倒数第一个点
				l.pop_back();
				else break;
			}
			l.push_back(s[i]);
		}
#undef COUNTER_CLOCKWISE 
#undef CLOCKWISE 
#undef ONLINE_BACK 
#undef ONLINE_FRONT 
#undef ON_SEGMENT 
		reverse(l.begin(), l.end());//按最小横坐标为起点逆时针方向输出
		for (int i = u.size() - 2; i >= 1; i--)l.push_back(u[i]);//除掉首尾
		return l;
	}
};
//E-mail 374656045@qq.com
char txt[1000000 + 10];
char pattern[10000 + 10];
class solve {
private:
	int q;
	int l1, r1, l2, r2;
public://采用邻接表建图,带权无向图
	solve()
	{
		scanf("%s%s", txt, pattern);
		KMP op(pattern);
		vector<int>save;
		op.KMPSearch(txt, pattern, save);
		forup(i, 0, save.size())
		{
			putnum(save[i]);
		}
	}

};
int main(void)
{
	ios_base::sync_with_stdio(0); cin.tie(0);//慎用，cin和scanf混用会导致非MSC++WA
#ifdef DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	solve solution;
#ifdef DEBUG
	fclose(stdin);//关闭文件 
	fclose(stdout);//关闭文件 
#endif
	return 0;

}




Measured memory_bytes: 8044