<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های امین گلی</title>
        <link>https://virgool.io/feed/@amingoli</link>
        <description>نوشتن برای من همانند فریاد زدن یک انسان خسته از زندگی بر روی یک قله کوه است</description>
        <language>fa</language>
        <pubDate>2026-06-16 08:17:11</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/230788/avatar/TspuLS.png?height=120&amp;width=120</url>
            <title>امین گلی</title>
            <link>https://virgool.io/@amingoli</link>
        </image>

                    <item>
                <title>بیت کوانتومی یا کیوبیت به زبان ساده</title>
                <link>https://virgool.io/@amingoli/%D8%A8%DB%8C%D8%AA-%DA%A9%D9%88%D8%A7%D9%86%D8%AA%D9%88%D9%85%DB%8C-%DB%8C%D8%A7-%DA%A9%DB%8C%D9%88%D8%A8%DB%8C%D8%AA-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-wg8hafxn8x4h</link>
                <description>همه ما کم‌ و بیش با تعریف بیت آشناییم و شاید چندین بار در طول روز از کلمه بیت استفاده کنیم. بیت کوچکترین واحد برای پردازش اطلاعات کلاسیکی بوده و فقط می‌تواند دو مقدار ثابت ۰ یا ۱ را داشته باشد. در‌واقع بیت عددی در دستگاه اعداد دودویی است. بیت‌ها توسط گیت‌هایی پردازش می‌شوند که اکثراً با خیلی از آن‌ها نظیر گیت AND ،OR ،NOT ،XOR و … آشناییم. یک بیت در هر لحظه فقط یکی از حالت های مشخص ۰ یا ۱ را می‌تواند داشته باشد. حال فرض کنید به جای بیت، موجودیت جدیدی در دست داشته باشیم که در هر لحظه بتواند هر دو مقدار ۰ و ۱ را به طور هم‌زمان داشته باشد؛ در این صورت چه اتفاقی رخ می‌داد؟! با من در ادامه این مقاله همراه باشید تا با واحدی شگفت‌انگیز به نام کیوبیت آشنا شوید.بیت کوانتومی یا کیوبیتبر اساس تعریفی مشابه با بیت کلاسیکی، می‌توانیم واحد پردازش اطلاعات کوانتومی را تعریف و واژه بیت کوانتومی یا «کیوبیت» (Qubit) را به آن اطلاق کنیم. از آنجا که در دنیای کوانتوم، حالت‌های کوانتومی (نظیر وضعیت اسپین یک الکترون) را با بردارها نمایش می‌دهند، کیوبیت نیز یک بردار حالت در فضای دوبعدی هیلبرت است. در تشابه با یک بیت کلاسیکی، کیوبیت می‌تواند دو حالت پایه |0⟩|0⟩ و |1⟩|1⟩ را داشته باشد (بخوانید کِت ۰ و کِت ۱). اما بر خلاف بیت کلاسیک که در هر لحظه فقط یکی از دو مقدار ۰ یا ۱ را می‌تواند داشته باشد، کیوبیت می‌تواند در حالت «برهمنهی» (Superposition) از حالت‌های پایه  |0⟩|0⟩ و  |1⟩|1⟩ به فرم زیر باشد. در مقاله درهمتنیدگی، دیدیم که وقتی حالت یک سیستم کوانتومی در زیرحالت‌هایی همبسته توزیع شده باشد، تا قبل از اندازه‌گیری نمی‌توانیم بگوییم که سیستم با چه احتمالی در کدام یک از زیر حالت‌ها قرار دارد.|ψ⟩=α|0⟩+β|1⟩|ψ⟩=α|0⟩+β|1⟩|0⟩=[10]|0⟩=[10]    ,    |1⟩=[01]|1⟩=[01]در رابطه فوق مربع قدرمطلق ضرایب (همان اعمال اندازه‌گیری)، احتمال یافتن کیوبیت در آن حالت را نتیجه می‌دهد. یعنی داریم:احتمال یافتن کیوبیت در حالت |0⟩|0⟩ برابر است با: |α|2|α|2احتمال یافتن کیوبیت در حالت |1⟩|1⟩ برابر است با: |β|2|β|2توجه داشته باشید که ضرایب α و β در حالت کلی اعدادی مختلط به فرم z=a+ibz=a+ib بوده که در آن i=√−1i=−1 است. می‌دانیم که جمع احتمالات یک سیستم یا پدیده باید ۱ باشد، پس این شرط ایجاب می‌کند که:|α|2+|β|2=1|α|2+|β|2=1مثالی از برهمنهیبرای اینکه درک ساده‌تری از مفهوم کیوبیت داشته باشید، مثال زیر را در نظر بگیرید. فرض کنید که یک سکه را درون جعبه‌ای انداخته و تکان می‌دهیم. به نظر شما وضعیت سکه به چه صورت است؟ احتمالاً پاسخ می‌دهید که حالت سکه یا شیر و یا خط است. اما از نقطه نظر مکانیک کوانتومی وضعیت سکه نه شیر است و نه خط، بلکه وضعیت آن به صورت برهمنهی از حالت شیر و خط است. در واقع تا قبل از باز کردن در جعبه نمی‌توانیم وضعیت سکه را با یک بیت کلاسیکی معادل سازی کنیم، بلکه وضعیت سکه در این حالت یک کیوبیت به فرم زیر است:|ψ⟩=α|heads⟩+β|tails⟩|ψ⟩=α|heads⟩+β|tails⟩وضعیت گربه داخل جعبه شرودینگر (زنده یا مرده!) هم ‌می تواند مثالی از یک کیوبیت باشد. در اینجا نیز قبل از اندازه‌گیری نمی‌توانیم به طور ۱۰۰٪ در مورد وضعیت گربه که آن را با یک کیوبیت معادل‌سازی کردیم، اظهار نظر کنیم.کره بلوخ (Bloch Sphere)برای درک شهودی از وضعیت یک کیوبیت، نمایش آن روی کره‌‌ بلوخ‌ می‌تواند مناسب باشد. در‌ واقع یک کیوبیت هر مکانی را روی سطح کره بلوخ می‌تواند به طور هم‌زمان اختیار کند. این در حالی است که یک بیت کلاسیکی تنها دو مقدار ۰ و ۱ را بر روی قطب‌های کره بلوخ دارد.با تعریف ضرایب α و β به فرم زیر می‌توان حالت یک کیوبیت را روی کره بلوخ نمایش داد. یادآور می‌شویم که قبل از اندازه‌گیری سیستم، مکان کیوبیت در هر نقطه‌ای روی سطح کره بلوخ می‌تواند باشد، در‌ واقع با اندازه‌گیری یعنی تعیین ضرایب می‌توان مکان و وضعیت دقیق کیوبیت را مشخص کرد.α=cos(θ2)α=cos(θ2)β=eiϕsin(θ2)حال به نظر می‌رسد پاسخ پرسشی که در مقدمه متن عنوان شد را با توجه به توضیحات فوق و کره سبز رنگ شکل فوق بتوان داد. بله، درست حدس زدید، پردازش موازی و سرعت بیشتر!تحقق فیزیکیپیاده‌سازی یک بیت کلاسیک به روش‌های مختلفی مثل روشن یا خاموش شدن یک پالس لیزری یا دو سطح مختلف ولتاژ مثل 0 و ۵ ولت صورت می‌گیرد. برای پیاده‌سازی یک کیوبیت نیز هر سیستم دو حالته ریز مقیاس فیزیکی، نظیر اسپین Up و Down یک الکترون یا قطبش افقی و عمودی یک فوتون می‌تواند مصداق یک کیوبیت باشد. به طور مثال برای کیوبیت‌های فوتونی، |0⟩|0⟩ را قطبش افقی و |1⟩|1⟩ را قطبش عمودی به شکل زیر تعریف می‌کنیم:|ψ⟩=α|H⟩+β|V⟩|ψ⟩=α|H⟩+β|V⟩یک سیستم کوانتومی به شدت نسبت به محیط اطراف خود نویز پذیر بوده و کوچک‌ترین اختلالی در سیستم، حالت‌های کوانتومی را دچار تغییر می‌کند، بنابراین سیستم باید به شدت از محیط بیرون ایزوله باشد که معمولا این کار را با اعمال خلأ بسیار بالا یا دماهایی خیلی پایین (نزدیک به صفر کلوین) انجام می‌دهند. در‌واقع همین مسئله تا به امروز گلوگاه تکنولوژیکی برای بهره بردن از مزایای کیوبیت و کامپیوترهای کوانتومی در شرایط عادی است.نمایی از تراشه کوانتومی ساخته شده توسط شرکت D-Wave
تاکنون روش‌های متعددی برای پیاده‌سازی کیوبیت‌ها معرفی شده است که هر کدام مزایا و معایب خاص خود را دارند. اما شاید در دسترس‌ترین گزینه‌ پیش رویمان، استفاده از فوتون و سیستم‌های اپتیکی است. چرا که فوتون‌ها در حالت عادی با یکدیگر برهمکنشی نداشته و نویزپذیر از محیط اطراف خود (البته در شرایط معمولی) نیستند. همچنین نیازی به خلأ یا سرد کردن ندارند. از طرفی دسترسی و کار با ادوات اپتیکی و لیزرها به عنوان منبعی برای تولید فوتون‌ها امری ساده‌تر نسبت به دیگر روش‌ها است. البته از مشکلات سیستم‌های اپتیکی می‌توان به نبود منبع تک فوتون ایده‌آل و همچنین احتمالی بودن برهمکنش فوتون‌ها در صورت نیاز، با یکدیگر اشاره کرد.کیوبیت‌ها نیز همانند بیت‌ها به وسیله گیت‌ها پردازش می‌شوند که در دنیای فیزیک کوانتوم به گیت‌های کوانتومی معروف‌اند. یک گیت کوانتومی در واقع همان اپراتور یا عملگری یکانی تحول زمانی در فیزیک کوانتوم است که با ماتریس‌های مربعی نمایش داده می‌شوند. جهت آشنایی با یکی از معروف‌ترین گیت‌های برگشت‌پذیر کوانتومی، پیاده‌سازی گیت‌های کوانتومی و در ادامه الگوریتم‌ و مدارهای کوانتومی به سادگی کار با بیت و مدارات منطقی کلاسیکی نبوده و بسیار دشوار است. اما تا به امروز روش‌هایی برای پیاده‌سازی گیت‌های کوانتومی با استفاده از اپتیک خطی و غیرخطی ارائه شده است. همچنین الگوریتم کوانتومی «گراور» (Grover) برای جست‌وجو در پایگاه‌های داده نیز توسط «محاسبات کوانتومی با اپتیک خطی» (Linear Optical Quantum Computing – LOQC) پیاده‌سازی شده است. امید است که در آینده‌ای نزدیک شاهد تجاری‌سازی کامپیوتر‌های کوانتومی باشیم.</description>
                <category>امین گلی</category>
                <author>امین گلی</author>
                <pubDate>Tue, 15 Feb 2022 03:34:31 +0330</pubDate>
            </item>
                    <item>
                <title>چطور با زبان GO یک RESTful API بسازیم</title>
                <link>https://virgool.io/@amingoli/%DA%86%D8%B7%D9%88%D8%B1-%D8%A8%D8%A7-%D8%B2%D8%A8%D8%A7%D9%86-go-%DB%8C%DA%A9-restful-api-%D8%A8%D8%B3%D8%A7%D8%B2%DB%8C%D9%85-rzdcphrdu6vv</link>
                <description>پیش‌نیازهافرض ما بر این است که شما از قبل با زبان Go آشنا شده‌اید و در حال حاضر این زبان برنامه‌نویسی بر روی سیستم شما نصب است.پس از نصب زبان Go باید در GOPATH که اکثر افراد تمام پروژه‌هایشان را در این مسیر نگهداری می‌کنند، پروژه‌ی فعلی را توسعه دهیم بنابراین در پوشه‌ی src می‌توانید یک فولدر خاص برای این پروژه ایجاد کنید یا برای ساماندهی بیشتر پروژه‌های مختلف یک پوشه با نام github.com ایجاد کنید و در آن پوشه‌ی دیگری ایجاد کنید و نام آن را همان نام کاربری خود در GitHub قرار دهید. در نهایت در مسیر GOPATH/src/github.com/&lt;Github username&gt; یک پوشه‌ی جدید برای پروژه‌ی فعلی با نام دلخواه ایجاد کنید.توسعه‌ی APIبرای پیاده‌سازی ساختار اولیه‌ی پروژه می‌توانید به شکل زیر عمل کنید:mkdir go-rest-api
cd go-rest-api
touch main.goپس از ایجاد کردن فایل main.go از یک ویرایشگر کد برای توسعه‌ی برنامه کمک می‌گیریم و کدهای زیر را در فایل ایجاد شده قرار می‌دهیم:package main

import &amp;quotfmt&amp;quot

func main() {
	fmt.Println(&amp;quotHello World!&amp;quot)
}برای کامپایل این برنامه ساده می‌توانید در Terminal فعلی دستور go build را اجرا کرده و درنهایت به شکل زیر برنامه‌ی کامپایل شده را اجرا کنید:./go-rest-apiانتظار می‌رود که خروجی زیر در Terminal شما چاپ شود:Hello World!راه‌اندازی سرور HTTP با استفاده از Gorilla MuxGorilla Mux یک پکیج است که به شما امکان می‌دهد routeهای مورد نیاز برنامه را ایجاد کرده و هر کدام از درخواست‌های ورودی را به Controller مربوطه ارجاع دهید. قبل از کار با پکیج Mux باید آن را به شکل زیر نصب کرده:go mod init
go get -u github.com/gorilla/muxو در مرحله‌ی بعد اولین endpoint برنامه را تعریف کنیم:package main

import (
	&amp;quotfmt&amp;quot
	&amp;quotlog&amp;quot
	&amp;quotnet/http&amp;quot

	&amp;quotgithub.com/gorilla/mux&amp;quot
)

func homeLink(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &amp;quotWelcome home!&amp;quot)
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc(&amp;quot/&amp;quot, homeLink)
	log.Fatal(http.ListenAndServe(&amp;quot:8080&amp;quot, router))
}مطمئنا پس از ایجاد هر تغییری در کدها باید برنامه را مجددا اجرا کنید. حال برای اجرای برنامه دو راه حل وجود دارد که یکی از آن‌ها کامپایل برنامه و اجرای برنامه‌ی کامپایل شده است اما برای سریع‌تر شدن فرایند تست برنامه می‌توانید دستور go run main.go را اجرا کنید که بدون نیاز به کامپایل، سرور توسعه داده شده را برای شما اجرا می‌کند.خروجی مورد انتظار پس از راه‌اندازی و ارسال درخواست GET به برنامه در آدرس localhost:8080 به شکل زیر است.شبیه‌سازی دیتابیسبرای شبیه‌سازی دیتابیس می‌توانیم رویداد‌ها را به شکل زیر در برنامه تعریف کنیم:type event struct {
	ID          string `json:&amp;quotID&amp;quot`
	Title       string `json:&amp;quotTitle&amp;quot`
	Description string `json:&amp;quotDescription&amp;quot`
}

type allEvents []event

var events = allEvents{
	{
		ID:          &amp;quot1&amp;quot,
		Title:       &amp;quotIntroduction to Golang&amp;quot,
		Description: &amp;quotCome join us for a chance to learn how golang works and get to eventually try it out&amp;quot,
	},
}در این ساختار فقط از ID، Title و Description برای ذخیره‌ی رویدادها استفاده کرده‌ایم و در ادامه کدهای مربوط به اضافه کردن، به‌روزرسانی و حذف رویدادها را پیاده‌سازی خواهیم کرد.اضافه کردن یک رویداد جدیدبرای ایجاد یک رویداد جدید باید داده‌های ارسال شده به‌صورت POST را دریافت کرده و به دیتابیس شبیه‌سازی شده اضافه کنیم. در مرحله‌ی بعد پس از اضافه شدن موفقیت‌آمیز رویداد به دیتابیس شبیه‌سازی شده، همان رویداد را با status code شماره‌ی 201 به کاربر برمی‌گردانیم:package main

import (
	&amp;quotencoding/json&amp;quot
	&amp;quotfmt&amp;quot
	&amp;quotio/ioutil&amp;quot
	&amp;quotlog&amp;quot
	&amp;quotnet/http&amp;quot

	&amp;quotgithub.com/gorilla/mux&amp;quot
)

type event struct {
	ID          string `json:&amp;quotID&amp;quot`
	Title       string `json:&amp;quotTitle&amp;quot`
	Description string `json:&amp;quotDescription&amp;quot`
}

type allEvents []event

var events = allEvents{
	{
		ID:          &amp;quot1&amp;quot,
		Title:       &amp;quotIntroduction to Golang&amp;quot,
		Description: &amp;quotCome join us for a chance to learn how golang works and get to eventually try it out&amp;quot,
	},
}

func createEvent(w http.ResponseWriter, r *http.Request) {
	var newEvent event
	// Convert r.Body into a readable formart
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, &amp;quotKindly enter data with the event id, title and description only in order to update&amp;quot)
	}

	json.Unmarshal(reqBody, &amp;newEvent)

	// Add the newly created event to the array of events
	events = append(events, newEvent)

	// Return the 201 created status code
	w.WriteHeader(http.StatusCreated)
	// Return the newly created event
	json.NewEncoder(w).Encode(newEvent)
}

func homeLink(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &amp;quotWelcome home!&amp;quot)
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc(&amp;quot/&amp;quot, homeLink)
	router.HandleFunc(&amp;quot/event&amp;quot, createEvent).Methods(&amp;quotPOST&amp;quot)
	log.Fatal(http.ListenAndServe(&amp;quot:8080&amp;quot, router))
}نمایش تمام رویداد‌هابرای نمایش تمام رویداد‌ها باید داده‌‌های events را نمایش دهیم:package main

import (
	&amp;quotencoding/json&amp;quot
	&amp;quotfmt&amp;quot
	&amp;quotio/ioutil&amp;quot
	&amp;quotlog&amp;quot
	&amp;quotnet/http&amp;quot

	&amp;quotgithub.com/gorilla/mux&amp;quot
)

type event struct {
	ID          string `json:&amp;quotID&amp;quot`
	Title       string `json:&amp;quotTitle&amp;quot`
	Description string `json:&amp;quotDescription&amp;quot`
}

type allEvents []event

var events = allEvents{
	{
		ID:          &amp;quot1&amp;quot,
		Title:       &amp;quotIntroduction to Golang&amp;quot,
		Description: &amp;quotCome join us for a chance to learn how golang works and get to eventually try it out&amp;quot,
	},
}

func homeLink(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &amp;quotWelcome home!&amp;quot)
}

func createEvent(w http.ResponseWriter, r *http.Request) {
	var newEvent event
	// Convert r.Body into a readable formart
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, &amp;quotKindly enter data with the event id, title and description only in order to update&amp;quot)
	}

	json.Unmarshal(reqBody, &amp;newEvent)

	// Add the newly created event to the array of events
	events = append(events, newEvent)

	// Return the 201 created status code
	w.WriteHeader(http.StatusCreated)
	// Return the newly created event
	json.NewEncoder(w).Encode(newEvent)
}

func getAllEvents(w http.ResponseWriter, r *http.Request) {
	json.NewEncoder(w).Encode(events)
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc(&amp;quot/&amp;quot, homeLink)
	router.HandleFunc(&amp;quot/event&amp;quot, createEvent).Methods(&amp;quotPOST&amp;quot)
	router.HandleFunc(&amp;quot/events&amp;quot, getAllEvents).Methods(&amp;quotGET&amp;quot)
	log.Fatal(http.ListenAndServe(&amp;quot:8080&amp;quot, router))
}نمایش یک رویداد خاصبرای نمایش یک رویداد خاص باید باید مقدار ID را به‌کمک Mux دریافت کنیم و درنهایت اگر ID ارسال شده با رویدادهای موجود در دیتابیس شبیه‌سازی شده همخوانی داشت، تمام داده‌های آن رویداد را نمایش دهیم:package main

import (
	&amp;quotencoding/json&amp;quot
	&amp;quotfmt&amp;quot
	&amp;quotio/ioutil&amp;quot
	&amp;quotlog&amp;quot
	&amp;quotnet/http&amp;quot

	&amp;quotgithub.com/gorilla/mux&amp;quot
)

type event struct {
	ID          string `json:&amp;quotID&amp;quot`
	Title       string `json:&amp;quotTitle&amp;quot`
	Description string `json:&amp;quotDescription&amp;quot`
}

type allEvents []event

var events = allEvents{
	{
		ID:          &amp;quot1&amp;quot,
		Title:       &amp;quotIntroduction to Golang&amp;quot,
		Description: &amp;quotCome join us for a chance to learn how golang works and get to eventually try it out&amp;quot,
	},
}

func homeLink(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &amp;quotWelcome home!&amp;quot)
}

func createEvent(w http.ResponseWriter, r *http.Request) {
	var newEvent event
	// Convert r.Body into a readable formart
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, &amp;quotKindly enter data with the event id, title and description only in order to update&amp;quot)
	}

	json.Unmarshal(reqBody, &amp;newEvent)

	// Add the newly created event to the array of events
	events = append(events, newEvent)

	// Return the 201 created status code
	w.WriteHeader(http.StatusCreated)
	// Return the newly created event
	json.NewEncoder(w).Encode(newEvent)
}

func getOneEvent(w http.ResponseWriter, r *http.Request) {
	// Get the ID from the url
	eventID := mux.Vars(r)[&amp;quotid&amp;quot]

	// Get the details from an existing event
	// Use the blank identifier to avoid creating a value that will not be used
	for _, singleEvent := range events {
		if singleEvent.ID == eventID {
			json.NewEncoder(w).Encode(singleEvent)
		}
	}
}

func getAllEvents(w http.ResponseWriter, r *http.Request) {
	json.NewEncoder(w).Encode(events)
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc(&amp;quot/&amp;quot, homeLink)
	router.HandleFunc(&amp;quot/event&amp;quot, createEvent).Methods(&amp;quotPOST&amp;quot)
	router.HandleFunc(&amp;quot/events&amp;quot, getAllEvents).Methods(&amp;quotGET&amp;quot)
	router.HandleFunc(&amp;quot/events/{id}&amp;quot, getOneEvent).Methods(&amp;quotGET&amp;quot)
	log.Fatal(http.ListenAndServe(&amp;quot:8080&amp;quot, router))
}به‌روزرسانی یک رویدادبرای به‌روزرسانی یک رویداد دقیقا شبیه بخش قبل عمل می‌کنیم و از Mux برای دریافت ID استفاده خواهیم کرد. اگر رویدادی با این ID وجود داشته باشد، به‌سراغ مقادیر ارسال شده در بدنه‌ی درخواست PATCH می‌رویم و آن‌ها را با مقادیر فعلی رویداد جایگزین می‌کنیم. درنهایت رویداد به‌روزرسانی شده را نمایش می‌دهیم:package main

import (
	&amp;quotencoding/json&amp;quot
	&amp;quotfmt&amp;quot
	&amp;quotio/ioutil&amp;quot
	&amp;quotlog&amp;quot
	&amp;quotnet/http&amp;quot

	&amp;quotgithub.com/gorilla/mux&amp;quot
)

type event struct {
	ID          string `json:&amp;quotID&amp;quot`
	Title       string `json:&amp;quotTitle&amp;quot`
	Description string `json:&amp;quotDescription&amp;quot`
}

type allEvents []event

var events = allEvents{
	{
		ID:          &amp;quot1&amp;quot,
		Title:       &amp;quotIntroduction to Golang&amp;quot,
		Description: &amp;quotCome join us for a chance to learn how golang works and get to eventually try it out&amp;quot,
	},
}

func homeLink(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &amp;quotWelcome home!&amp;quot)
}

func createEvent(w http.ResponseWriter, r *http.Request) {
	var newEvent event
	// Convert r.Body into a readable formart
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, &amp;quotKindly enter data with the event id, title and description only in order to update&amp;quot)
	}

	json.Unmarshal(reqBody, &amp;newEvent)

	// Add the newly created event to the array of events
	events = append(events, newEvent)

	// Return the 201 created status code
	w.WriteHeader(http.StatusCreated)
	// Return the newly created event
	json.NewEncoder(w).Encode(newEvent)
}

func getOneEvent(w http.ResponseWriter, r *http.Request) {
	// Get the ID from the url
	eventID := mux.Vars(r)[&amp;quotid&amp;quot]

	// Get the details from an existing event
	// Use the blank identifier to avoid creating a value that will not be used
	for _, singleEvent := range events {
		if singleEvent.ID == eventID {
			json.NewEncoder(w).Encode(singleEvent)
		}
	}
}

func getAllEvents(w http.ResponseWriter, r *http.Request) {
	json.NewEncoder(w).Encode(events)
}

func updateEvent(w http.ResponseWriter, r *http.Request) {
	// Get the ID from the url
	eventID := mux.Vars(r)[&amp;quotid&amp;quot]
	var updatedEvent event
	// Convert r.Body into a readable formart
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, &amp;quotKindly enter data with the event title and description only in order to update&amp;quot)
	}

	json.Unmarshal(reqBody, &amp;updatedEvent)

	for i, singleEvent := range events {
		if singleEvent.ID == eventID {
			singleEvent.Title = updatedEvent.Title
			singleEvent.Description = updatedEvent.Description
			events[i] = singleEvent
			json.NewEncoder(w).Encode(singleEvent)
		}
	}
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc(&amp;quot/&amp;quot, homeLink)
	router.HandleFunc(&amp;quot/event&amp;quot, createEvent).Methods(&amp;quotPOST&amp;quot)
	router.HandleFunc(&amp;quot/events&amp;quot, getAllEvents).Methods(&amp;quotGET&amp;quot)
	router.HandleFunc(&amp;quot/events/{id}&amp;quot, getOneEvent).Methods(&amp;quotGET&amp;quot)
	router.HandleFunc(&amp;quot/events/{id}&amp;quot, updateEvent).Methods(&amp;quotPATCH&amp;quot)
	log.Fatal(http.ListenAndServe(&amp;quot:8080&amp;quot, router))
}حذف یک رویدادحذف یک رویداد با متد DELETE انجام می‌شود بنابراین مقدار ID ارسال شده در درخواست‌هایی با متد DELETE را به کمک Mux دریافت خواهیم کرد و آن را با دیتابیس شبیه‌سازی شده مقایسه می‌کنیم. اگر در دیتابیس ما رویدادی با این ID وجود داشته باشد آن را حذف خواهیم کرد و درنهایت موفقیت‌آمیز بودن حذف رویداد را نمایش می‌دهیم:package main

import (
	&amp;quotencoding/json&amp;quot
	&amp;quotfmt&amp;quot
	&amp;quotio/ioutil&amp;quot
	&amp;quotlog&amp;quot
	&amp;quotnet/http&amp;quot

	&amp;quotgithub.com/gorilla/mux&amp;quot
)

type event struct {
	ID          string `json:&amp;quotID&amp;quot`
	Title       string `json:&amp;quotTitle&amp;quot`
	Description string `json:&amp;quotDescription&amp;quot`
}

type allEvents []event

var events = allEvents{
	{
		ID:          &amp;quot1&amp;quot,
		Title:       &amp;quotIntroduction to Golang&amp;quot,
		Description: &amp;quotCome join us for a chance to learn how golang works and get to eventually try it out&amp;quot,
	},
}

func homeLink(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &amp;quotWelcome home!&amp;quot)
}

func createEvent(w http.ResponseWriter, r *http.Request) {
	var newEvent event
	// Convert r.Body into a readable formart
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, &amp;quotKindly enter data with the event id, title and description only in order to update&amp;quot)
	}

	json.Unmarshal(reqBody, &amp;newEvent)

	// Add the newly created event to the array of events
	events = append(events, newEvent)

	// Return the 201 created status code
	w.WriteHeader(http.StatusCreated)
	// Return the newly created event
	json.NewEncoder(w).Encode(newEvent)
}

func getOneEvent(w http.ResponseWriter, r *http.Request) {
	// Get the ID from the url
	eventID := mux.Vars(r)[&amp;quotid&amp;quot]

	// Get the details from an existing event
	// Use the blank identifier to avoid creating a value that will not be used
	for _, singleEvent := range events {
		if singleEvent.ID == eventID {
			json.NewEncoder(w).Encode(singleEvent)
		}
	}
}

func getAllEvents(w http.ResponseWriter, r *http.Request) {
	json.NewEncoder(w).Encode(events)
}

func updateEvent(w http.ResponseWriter, r *http.Request) {
	// Get the ID from the url
	eventID := mux.Vars(r)[&amp;quotid&amp;quot]
	var updatedEvent event
	// Convert r.Body into a readable formart
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, &amp;quotKindly enter data with the event title and description only in order to update&amp;quot)
	}

	json.Unmarshal(reqBody, &amp;updatedEvent)

	for i, singleEvent := range events {
		if singleEvent.ID == eventID {
			singleEvent.Title = updatedEvent.Title
			singleEvent.Description = updatedEvent.Description
			events[i] = singleEvent
			json.NewEncoder(w).Encode(singleEvent)
		}
	}
}

func deleteEvent(w http.ResponseWriter, r *http.Request) {
	// Get the ID from the url
	eventID := mux.Vars(r)[&amp;quotid&amp;quot]

	// Get the details from an existing event
	// Use the blank identifier to avoid creating a value that will not be used
	for i, singleEvent := range events {
		if singleEvent.ID == eventID {
			events = append(events[:i], events[i+1:]...)
			fmt.Fprintf(w, &amp;quotThe event with ID %v has been deleted successfully&amp;quot, eventID)
		}
	}
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc(&amp;quot/&amp;quot, homeLink)
	router.HandleFunc(&amp;quot/event&amp;quot, createEvent).Methods(&amp;quotPOST&amp;quot)
	router.HandleFunc(&amp;quot/events&amp;quot, getAllEvents).Methods(&amp;quotGET&amp;quot)
	router.HandleFunc(&amp;quot/events/{id}&amp;quot, getOneEvent).Methods(&amp;quotGET&amp;quot)
	router.HandleFunc(&amp;quot/events/{id}&amp;quot, updateEvent).Methods(&amp;quotPATCH&amp;quot)
	router.HandleFunc(&amp;quot/events/{id}&amp;quot, deleteEvent).Methods(&amp;quotDELETE&amp;quot)
	log.Fatal(http.ListenAndServe(&amp;quot:8080&amp;quot, router))
}</description>
                <category>امین گلی</category>
                <author>امین گلی</author>
                <pubDate>Wed, 02 Feb 2022 21:00:50 +0330</pubDate>
            </item>
                    <item>
                <title>گریدل برای توسعه دهندگان اندروید</title>
                <link>https://virgool.io/@amingoli/%DA%AF%D8%B1%DB%8C%D8%AF%D9%84-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%AF%D9%87%D9%86%D8%AF%DA%AF%D8%A7%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-jubd4n97coda</link>
                <description>در gradle می‌تونیم دو نوع متغیر تعریف کنیم.این دو نوع به صورت buildConfigField و resValue هستند.buildConfigField رو وقتی تعریف می‌کنیم داخل کلاس BuildConfig یک متغیر استاتیک تعریف میشه که داخل کد جاوا قابل دسترسی هست.در عوض resValue بصورت کد جاوا تولید نمیشه بلکه به صورت resource می‌باشد.خب کاربرد این متغیرها چیه؟به عنوان یک تجربه کاری،اپلیکیشن من قرار بود برای نسخه debug که به واحد تست تحویل داده می‌شد،از وب سرویس‌های سرور A استفاده کنه و برای نسخه release که به کارفرما تحویل می‌دادیم از سرور B دیتا بگیره.در ابتدا اومدم یک کلاس Constant به صورت زیر ساختم: وقتیمی‌خواستمبهکارفرمااپلیکیشنروبدم،آدرسreleaseروازحالتکامنتدرمی‌آوردموخروجیمی‌گرفتم.خبکاراشتباهیبودولیکارراهاندازبود.البتهاحتمالخطابالابود. بعد از مدتی با متغیر‌های gradle آشنا شدم و در فایل build.gradle به صورت زیر اول دو نوع buildType ساختم:یکی برای release و یکی برای debug.در مرحله بعدی یک متغیر به اسم BASE_URL تعریف کردم به این صورت:وقتی gradle رو sync کردم،داخل کلاس BuildConfig دیدم متغیر BASE_URL اضافه شده.حالا برای دسترسی به این متغیر کافی بود بصورت زیر ازش استفاده کنم و در کنارش از منو BuildVariants نوع buildType مورد نظر رو انتخاب کنیم:دیگه دردسر کامنت کردن برطرف شد و مطمئن بودم نسخه ای که به کارفرما میدم،با آدرس درست خروجی گرفته شده است.از کاربردهای دیگه ، مثلا API_KEY رو میشه داخل فایل gradle ذخیره کرد و مثلا داخل AndroidManifest بهش دسترسی داشت،به این شکل:استفاده در فایل manifestممنون از دوست عزیزم آقای الیاس محمدی</description>
                <category>امین گلی</category>
                <author>امین گلی</author>
                <pubDate>Fri, 08 Oct 2021 16:30:06 +0330</pubDate>
            </item>
                    <item>
                <title>اطلاعات کاربردی برای ارتقاء دانش XML در اندروید استودیو</title>
                <link>https://virgool.io/@amingoli/%D8%A7%D8%B7%D9%84%D8%A7%D8%B9%D8%A7%D8%AA-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF%DB%8C-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%A7%D8%B1%D8%AA%D9%82%D8%A7%D8%A1-%D8%AF%D8%A7%D9%86%D8%B4-xml-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D8%A7%D8%B3%D8%AA%D9%88%D8%AF%DB%8C%D9%88-dfqpidaipwgw</link>
                <description>آشنایی با امکانات فضای نام tools در Android Studio برگرفته از وبلاگ دوست عزیزم آقای مسعود فلاح‌پورقبل از شروع مطلب این موضوع رو ذکر کنم که در ادامه از معادل های فارسی زیر استفاده می‌کنم:فضای نام = name spaceخصیصه = attributeفضای نام tools یکی از اون مواردی هست که معمولا برنامه‌نویسای اندروید ازش استفاده نمیکنن در حالیکه امکانات جالبی داره. کاربرد اصلی این فضای نام، زمان طراحی layout هستش. اما بعضی از امکاناتش تو فایل‌های دیگه  XML مثل strings.xml استفاده میشه.تو این پست به تعدادی از امکانات پرکاربرد این فضای نام اشاره میکنم. برای آشنایی با تمام امکانات این فضای نام میتونید به منابعی که انتهای همین پست قرار دادم مراجعه کنید.یک مثال از کاربرد فضای نام tools میزنم و بعد میریم سراغ اصل مطلب. فرض کنید توی یک  layout یک TextView وجود داره و متن این TextView موقع طراحی مشخص نیست و موقع اجرا، از سرور گرفته میشه. حالا برای اینکه یک متن رو به صورت تستی داخل این TextView نمایش بدیم تا ظاهر، محل قرارگیری و موارد دیگه رو چک کنیم دو تا راه داریم:استفاده از خصیصه android:text. مشکل این روش اینه که اگر به هر دلیلی موقع اجرای برنامه، متنی که باید تو TextView نمایش داده بشه از سرور دریافت نشه (حالا به هر دلیلی) اونوقت اون متن تستی به کاربر نمایش داده میشه. حالا فکر کنید اون متن یه چیز ناجور باشه! در این صورت خیلی بد میشه.استفاده از خصیصه tools:text. وقتی از این خصیصه استفاده بشه موقع طراحی layout متن مورد نظر شما نمایش داده میشه اما این متن موقع اجرای اپ نمایش داده نمیشه و مشکلی که بالا بهش اشاره شد حل میشه.اضافه کردن فضای نام toolsبرای اینکه بتونیم از امکانات فضای نام tools استفاده کنیم باید این فضای نام رو به صورت زیر به بالاترین (یا به عبارت دیگه خارجی ترین) تگ داخل یک فایل XML اضافه کنیم.&lt;RootTag xmlns:tools=&amp;quothttp://schemas.android.com/tools&amp;quot &gt;منظور از RootTag، بالاترین تگ داخل فایل XML هستش.خصیصه‌های مربوط به کنترل خطاخصیصه tools:ignoreاین خصیصه توسط Lint مورد استفاده قرار میگیره و تو تمام تگ های XML میشه ازش استفاده کرد.با استفاده از این خصیصه میتونیم به Lint بگیم که یک سری اخطارها در مورد یک تگ رو نادیده بگیره. مثلا اگر شما داخل یک فایل layout از تگ ImageView استفاده کنید و خصیصه android:contentDescription رو وارد نکرده باشید  Lint اخطار زیر رو نمایش میده.Missing contentDescription attribute on imageحالا برای اینکه به Lint بگیم این اخطار رو نادیده بگیر باید خصیصه tools:ignore رو به صورت زیر به ImageView اضافه کنیم.tools:ignore=&quot;ContentDescription&quot;اگر نیاز دارید بیشتر از یک اخطار نادیده گرفته بشه باید لیست اون اخطارها رو به صورت جداشده با ویرگول از هم به صورت زیر وارد کنید.tools:ignore=&quot;ContentDescription, MissingTranslation&quot;خصیصه tools:targetApiمثل خصیصه قبلی، این خصیصه هم توسط Lint مورد استفاده قرار میگیره و تو تمام تگ های XML کاربرد داره.کاربرد این تگ دقیقا مثل @TargetApi هستش. در واقع میشه اینطوری گفت که tools:targetApi معادل XMLای @TargetApi هستش. کاربرد این خصیصه اینه که به Lint اعلام کنیم تگی که این خصیصه رو داره فقط و فقط روی یک API level خاص و بالاتر از اون استفاده خواهد شد و در نتیجه خطایی در اجرای اپ رخ نخواهد داد.فرض کنید minSdkVersion پروژه شما ۱۲ باشه و شما از تگ GridLayout استفاده کردید. با توجه به اینکه GridLayout از API level شماره ۱۴ به بعد در دسترسه در نتیجه Lint اخطار زیر رو نمایش میده:View requires API level 14برای اینکه این اخطار رو حذف کنیم باید خصیصه tools:targetApi رو به صورت زیر به خصیصه‌های GridLayout اضافه کنیم.tools:targetApi=&quot;14&quot;خصیصه tools:localeاندروید استودیو به صورت پیش فرض زبان تمام اپ ها رو انگلیسی در نظر میگیره. حالا فرض کنید زبان اصلی اپ شما فارسی هستش و در نتیجه متنهای داخل فایل strings.xml فارسی خواهد بود. توی این حالت ممکنه Lint یه سری اخطارهای بی مورد نمایش بده چون خبر نداره که شما متنهای داخل strings.xml رو به زبانی غیر از انگلیسی نوشتید. برای اینکه به Lint بگیم زبان این فایل فارسی هستش باید به صورت زیر از خصیصه tools:locale استفاده کنیم.&lt;resources xmlns:tools=&quot;http://schemas.android.com/tools&quot;tools:locale=&quot;fa&quot;&gt;خصیصه‌های مربوط به زمان طراحی layoutخصیصه‌های این قسمت فقط زمان طراحی layout تو اندروید استودیو اعمال میشن و در زمان اجرا نادیده گرفته میشن.ا- tools: به جای androidبه طور کلی هر جا که شما یک view تعریف کردید (مثلا TextView یا EditText و سایر viewها) و خصیصه‌ای رو ست کردید که با android: شروع میشه میتونید به جای android: از tools: استفاده کنید. با این کار خصیصه مورد نظر فقط تو حالت layout preview اعمال میشه و وقتی اپ روی امولاتور یا یک دستگاه اندرویدی اجرا بشه دیگه اون خصیصه‌ها اعمال نمیشن.برای مثال فرض کنید یک layout داریم که شامل چنتا view هستش. موقع اجرای اپ یکی از این viewها باید invisible باشه اما زمان طراحی layout میخوایم اون view رو ببینیم. تو چنین حالتی باید خصیصه visibility رو به صورت زیر ست کنیم.&lt;Viewtools:visibility=&quot;visible&quot;android:visibility=&quot;invisible&quot;/&gt;خصیصه tools:contextبا استفاده از این خصیصه تعیین میکنیم که layout تعریف شده مربوط به کدوم activity هستش. برای استفاده از این خصیصه باید اون رو به خارجی‌ترین تگ یک فایل layout به صورت زیر اضافه کنیم.&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;xmlns:tools=&quot;http://schemas.android.com/tools&quot;android:layout_width=&quot;match_parent&quot;android:layout_height=&quot;match_parent&quot;tools:context=&quot;.ui.activity.MainActivity&quot;&gt;مقدار خصیصه tools:context مسیر قرارگیری و نام activity مورد نظر خواهد بود.کاربرد این خصیصه زمانی مشخص میشه که شما داخل layout نیاز به انجام کاری دارید و برای انجام اون کار Android Studio باید بدونه این layout مربوط به کدوم activity هستش.برای مثال فرض کنید شما داخل layout یه button دارید و خصیصه  اون رو ست کردید تا وقتی دکمه کلیک شد متدی به نام onButtonClicked فراخوانی بشه. حالا اگر شما خصیصه tools:context رو ست کرده باشید و activity مورد نظر رو تعریف کرده باشید Android Studio متوجه میشه که اگر قراره متد onButtonClicked تعریف بشه محل تعریفش داخل activity مشخص شده هستش. این موضوع تو شکل زیر نشون داده شده.خصیصه tools:itemCountخصیصه tools:itemCountاین خصیصه مربوط به RecyclerView هستش. اگر یک RecyclerView رو به یک layout اضافه کنید و تو layout preview اون layout رو ببینید متوجه میشید که اندروید استودیو به صورت پیش فرض تعدادی سطر رو به صورت تستی داخل RecyclerView نمایش میده. تعداد این سطرها به صورت پیش فرض ۱۰ تا هست. با استفاده از خصیصه tools:itemCount میتونید تعداد سطرها رو تعیین کنید. مثلا بگید به جای ۱۰ سطر، ۴ سطر نمایش داده بشه.خصیصه tools:layoutاز این خصیصه برای تگ fragment استفاده میشه. به وسیله این خصیصه میتونیم تعیین کنیم که تو layout preview کدوم layout به عنوان layout یک fragment نمایش داده بشه. برای این کار باید از خصیصه tools:layout به شکل زیر استفاده کنیم.&lt;fragmentandroid:id=&quot;@+id/fragment&quot;android:layout_width=&quot;match_parent&quot;android:layout_height=&quot;match_parent&quot;tools:layout=&quot;@layout/fragment_layout&quot; /&gt;خصیصه‌های tools:listitem, tools:listheader, tools:listfooterاین سه تا خصیصه برای کلاس AdapterView (و کلاسهای مشتق از اون مثل ListView) کاربرد داره.وقتی یک ListView رو به یک layout اضافه کنید چندتا سطر به صورت تستی داخل ListView نمایش داده میشه. حالا اگر شما بخواید به جای اون سطرهای تستی سطر مورد نظر شما نمایش داده بشه باید از خصیصه tools:listitem استفاده کنید و layout مورد نظرتون که میخواید به عنوان هر سطر از ListView نمایش داده بشه رو وارد کنید. تو شکل زیر میتونید تفاوت بین حالتی که از خصیصه tools:listitem استفاده شده (شکل سمت راست) و حالتی که از این خصیصه استفاده نشده (شکل سمت چپ) رو ببینید.?خصیصه‌های tools:listheader و tools:listfooter هم کاربرد مشابه tools:listitem دارن و از اونها به ترتیب برای تعیین layout سرصفحه و پاصفحه استفاده میشه.خصیصه tools:showInفرض کنید یک layout تعریف کردید به نام partial_layout و داخل یک layout دیگه به نام main_layout از partial_layout به کمک تگ include استفاده کردید. اگر خصیصه tools:showIn رو به خارجی‌ترین تگ partial_layout اضافه کنید اونوقت تو layout preview میتونید partial_layout رو در حالیکه داخل main_layout داره نمایش داده میشه ببینید.روش استفاده از خصیصه tools:showIn به صورت زیر هستش. در واقع باید خصیصه زیر رو به خارجی‌ترین تگ فایل partial_layout اضافه کنید.tools:showIn=&quot;@layout/main_layout&quot;خصیصه tools:menuاگر شما داخل یک layout  یک app bar دارید که یک منو هم داره میتونیم با استفاده از خصیصه tools:menu تعیین کنیم که چه منویی تو layout preview نمایش داده بشه. خصیصه tools:menu باید به خارجی‌ترین تگ layout اضافه بشه. اگر فرض کنیم خارجی‌ترین تگ فایل layout یک LinearLayout باشه اونوقت باید از خصیصه tools:menu به شکل زیر استفاده کنیم:&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;xmlns:tools=&quot;http://schemas.android.com/tools&quot;android:orientation=&quot;vertical&quot;android:layout_width=&quot;match_parent&quot;android:layout_height=&quot;match_parent&quot;tools:menu=&quot;menu1&quot; /&gt;تو قطعه کد بالا فرض شده  menu1 نام یک menu resource هستش که داخل پوشه menu تعریف شده. نکته‌ای که وجود داره اینه که لازم نیست پیشوند @menu رو ابتدای menu1 بیاریم.خصیصه tools:openDrawerبه کمک خصیصه tools:openDrawer میتونیم وضعیت باز یا بسته بودن یک DrawerLayout رو تو layout preview مشخص کنیم. مقادیری که این خصیصه میتونه داشته باشه عبارت‌اند از:endleftrightstartبه استفاده از مقادیر بالا میتونیم تعیین کنیم DrawerLayout تو layout preview از کدوم سمت صفحه به صورت باز شده نشون داده بشه.متن و عکس تستیاگر در جایی از یک layout نیاز به متن یا عکس تستی داشتید میتونید از resourceهایی که به صورت پیش‌فرض تعریف شده هستند استفاده کنید. بعضی از این resourceها عبارت‌اند از:tools:sample/first_name: یک نام تصادفی نمایش میدهtools:sample/last_name: یک نام خانوادگی تصادفی نمایش میدهtools:sample/full_names: یک نام و نام خانوادگی تصادفی نمایش میدهtools:sample/avatars: یک عکس پروفایل تصادفی که به صورت vector هست نمایش میدهtools:sample/backgrounds/scenic: یک عکس تصادفی که به عنوان پس‌زمینه میشه ازش استفاده کرد.فرض کنید داخل یک TextView بخوایم نام و نام خانوادگی تستی نمایش بدیم. برای این کار میتونیم به صورت زیر عمل کنیم.&lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;xmlns:tools=&quot;http://schemas.android.com/tools&quot;android:layout_width=&quot;wrap_content&quot;android:layout_height=&quot;wrap_content&quot;tools:text=&quot;@tools:sample/full_names&quot; /&gt;خصیصه‌های مربوط به کاهش حجم resourceهاتعدادی خصیصه تو فضای نام tools وجود دارن که از اونها برای کنترل shrink شدن یا نشدن resourceها استفاده میشه. این خصیصه‌ها عبارت‌اند از:tools:shrinkModetools:keeptools:discardبرای اطلاع از کاربرد هر کدوم از خصیصه‌های بالا میتونید به منابع انتهای پست مراجعه کنید.دسترسی به اپ تستیبرای آشنایی بیشتر با روش استفاده از هر کدوم از خصیصه‌های مطرح شده یک اپ تستی آماده کردم و روی گیت‌هاب قرار دادم. برای دسترسی به اپ میتونید از این لینک استفاده کنید.</description>
                <category>امین گلی</category>
                <author>امین گلی</author>
                <pubDate>Sun, 27 Jun 2021 20:52:07 +0430</pubDate>
            </item>
                    <item>
                <title>my dependencies</title>
                <link>https://virgool.io/@amingoli/my-dependencies-wlhxnlwlnyxd</link>
                <description>dependencies {
    implementation &#039;androidx.appcompat:appcompat:1.2.0&#039;
    implementation &#039;androidx.constraintlayout:constraintlayout:2.0.4&#039;
    testImplementation &#039;junit:junit:4.13.2&#039;
    androidTestImplementation &#039;androidx.test.ext:junit:1.1.2&#039;
    androidTestImplementation &#039;androidx.test.espresso:espresso-core:3.3.0&#039;

//    require for view
    implementation &#039;com.google.android.material:material:1.3.0&#039;
    implementation &#039;androidx.cardview:cardview:1.0.0&#039;
    implementation &#039;androidx.recyclerview:recyclerview:1.2.0&#039;
    implementation &#039;androidx.legacy:legacy-support-v4:1.0.0&#039;

//    size manager for display android
    implementation &#039;com.intuit.sdp:sdp-android:1.0.6&#039;
    implementation &#039;com.intuit.ssp:ssp-android:1.0.6&#039;

//    ripple view in  and onLongClick
    implementation &#039;com.balysv:material-ripple:1.0.2&#039;

//    connection to server
    implementation &#039;com.squareup.retrofit2:retrofit:2.6.2&#039;
    implementation &#039;com.squareup.retrofit2:converter-gson:2.6.2&#039;
    implementation &#039;com.squareup.okhttp3:logging-interceptor:3.12.1&#039;

//    for decode and incode to json
    implementation &#039;com.google.code.gson:gson:2.8.5&#039;
}</description>
                <category>امین گلی</category>
                <author>امین گلی</author>
                <pubDate>Fri, 30 Apr 2021 16:14:09 +0430</pubDate>
            </item>
                    <item>
                <title>ذخیره اسم دلخواه بجای app-release.apk در خروجی اندروید</title>
                <link>https://virgool.io/@amingoli/%D8%B0%D8%AE%DB%8C%D8%B1%D9%87-%D8%A7%D8%B3%D9%85-%D8%AF%D9%84%D8%AE%D9%88%D8%A7%D9%87-%D8%A8%D8%AC%D8%A7%DB%8C-app-releaseapk-%D8%AF%D8%B1-%D8%AE%D8%B1%D9%88%D8%AC%DB%8C-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-f4l2hlox23z7</link>
                <description>سلامخیلی پیش میاد، وقتی از اپلیکیشن‌تون در اندروید استودیو خروجی میگیرید نام اپ بصورت app-release.apk ذخیره میشه.برای اینکه اپلیکیشن‌تون نام انتخابی خودتون رو داشته باشه کافی کد زیر رو داخل فایل build.gradle  و تگ android -&gt; buildTypes -&gt; release اپلیکیشن‌تون بنویسیدبجای YOUR_APP_NAME اسم اپلیکیشن رو بنویسیدapplicationVariants.all { variant -&gt;
    variant.outputs.all {
        def appName = &amp;quotYOUR_APP_NAME&amp;quot
        if (outputFileName != null &amp;&amp; outputFileName.endsWith(&#039;.apk&#039;)) {
            outputFileName = appName + &amp;quot &amp;quot + defaultConfig.versionName + &amp;quot.apk&amp;quot
        }
    }
}در نهایت کدهای فایل build.gradle به این صورت درمیادapply plugin: &#039;com.android.application&#039;

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId &amp;quotamingoli.com.myapp&amp;quot
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName &amp;quot1.0.0&amp;quot
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile&#40;&#039;proguard-android.txt&#039;&#41;, &#039;proguard-rules.pro&#039;
            signingConfig getSigningConfig()
            applicationVariants.all { variant -&gt;
                variant.outputs.all {
                    def appName = &amp;quotYOUR_APP_NAME&amp;quot
                    if (outputFileName != null &amp;&amp; outputFileName.endsWith(&#039;.apk&#039;)) {
                        outputFileName = appName + &amp;quot &amp;quot + defaultConfig.versionName + &amp;quot.apk&amp;quot
                    }
                }
            }
        }
    }
}

dependencies {
    implementation fileTree(dir: &#039;libs&#039;, include: [&#039;*.jar&#039;])
    implementation &#039;androidx.appcompat:appcompat:1.1.0&#039;
    implementation &#039;androidx.cardview:cardview:1.0.0&#039;
    implementation &#039;androidx.recyclerview:recyclerview:1.1.0&#039;
    implementation &#039;com.google.android.material:material:1.1.0&#039;
    implementation &#039;androidx.legacy:legacy-support-v4:1.0.0&#039;
    implementation &#039;com.balysv:material-ripple:1.0.2&#039;
}</description>
                <category>امین گلی</category>
                <author>امین گلی</author>
                <pubDate>Tue, 14 Jul 2020 21:17:53 +0430</pubDate>
            </item>
            </channel>
</rss>