Prompt:
Answer the question based on the given passages. Only give me the answer and do not output any other words.

The following are given passages.
Passage 1:
Where Was I
"Where Was I?" may refer to:

Books
"Where Was I?", essay by David Hawley Sanford from The Mind's I
Where Was I?, book by John Haycraft 2006
Where was I?!, book by Terry Wogan 2009

Film and TV
Where Was I? (film), 1925 film directed by William A. Seiter. With Reginald Denny, Marian Nixon, Pauline Garon, Lee Moran.
Where Was I? (2001 film), biography about songwriter Tim Rose
Where Was I? (TV series) 1952–1953 Quiz show with the panelists attempting to guess a location by looking at photos
"Where Was I?" episode of Shoestring (TV series) 1980

Music
"Where was I", song by W. Franke Harling and Al Dubin performed by Ruby Newman and His Orchestra  with vocal chorus by  Larry Taylor and Peggy McCall  1939
"Where Was I", single from Charley Pride discography 1988
"Where Was I" (song), a 1994 song by Ricky Van Shelton
"Where Was I (Donde Estuve Yo)", song by Joe Pass from Simplicity (Joe Pass album)
"Where Was I?", song by Guttermouth from The Album Formerly Known as a Full Length LP (Guttermouth album)
"Where Was I", song by Sawyer Brown (Billy Maddox, Paul Thorn, Anne Graham) from Can You Hear Me Now 2002
"Where Was I?", song  by  Kenny Wayne Shepherd from Live On  1999
"Where Was I", song by Melanie Laine (Victoria Banks, Steve Fox) from Time Flies (Melanie Laine album)
"Where Was I", song by Rosie Thomas from With Love (Rosie Thomas album)
Passage 2:
Beaulieu-sur-Loire
Beaulieu-sur-Loire (French pronunciation: [boljø syʁ lwaʁ], literally Beaulieu on Loire) is a commune in the Loiret department in north-central France. It is the place of death of Jacques MacDonald, a French general who served in the Napoleonic Wars.

Population
See also
Communes of the Loiret department
Passage 3:
Dance of Death (disambiguation)
Dance of Death, also called Danse Macabre, is a late-medieval allegory of the universality of death.
Dance of Death or The Dance of Death may also refer to:

Books
Dance of Death, a 1938 novel by Helen McCloy
Dance of Death (Stine novel), a 1997 novel by R. L. Stine
Dance of Death (novel), a 2005 novel by Douglas Preston and Lincoln Child

Theatre and film
The Dance of Death (Strindberg play), a 1900 play by August Strindberg
The Dance of Death, a 1908 play by Frank Wedekind
The Dance of Death (Auden play), a 1933 play by W. H. Auden

Film
The Death Dance, a 1918 drama starring Alice Brady
The Dance of Death (1912 film), a German silent film
The Dance of Death (1919 film), an Austrian silent film
The Dance of Death (1938 film), crime drama starring Vesta Victoria; screenplay by Ralph Dawson
The Dance of Death (1948 film), French-Italian drama based on Strindberg's play, starring Erich von Stroheim
The Dance of Death (1967 film), a West German drama film
Dance of Death or House of Evil, 1968 Mexican horror film starring Boris Karloff
Dance of Death (1969 film), a film based on Strindberg's play, starring Laurence Olivier
Dance of Death (1979 film), a Hong Kong film featuring Paul Chun

Music
Dance of Death (album), a 2003 album by Iron Maiden, or the title song
The Dance of Death & Other Plantation Favorites, a 1964 album by John Fahey
The Dance of Death (Scaramanga Six album)
"Death Dance", a 2016 song by Sevendust

See also
Dance of the Dead (disambiguation)
Danse Macabre (disambiguation)
Bon Odori, a Japanese traditional dance welcoming the spirits of the dead
La danse des morts, an oratorio by Arthur Honegger
Totentanz (disambiguation)
Passage 4:
Place of origin
In Switzerland, the place of origin (German: Heimatort or Bürgerort, literally "home place" or "citizen place"; French: Lieu d'origine; Italian: Luogo di attinenza) denotes where a Swiss citizen has their municipal citizenship, usually inherited from previous generations. It is not to be confused with the place of birth or  place of residence, although two or all three of these locations may be identical depending on the person's circumstances.

Acquisition of municipal citizenship
Swiss citizenship has three tiers. For a person applying to naturalise as a Swiss citizen, these tiers are as follows:

Municipal citizenship, granted by the place of residence after fulfilling several preconditions, such as sufficient knowledge of the local language, integration into local society, and a minimum number of years lived in said municipality.
Cantonal (state) citizenship, for which a Swiss municipal citizenship is required. This requires a certain number of years lived in said canton.
Country citizenship, for which both of the above are required, also requires a certain number of years lived in Switzerland (except for people married to a Swiss citizen, who may obtain simplified naturalisation without having to reside in Switzerland), and involves a criminal background check.The last two kinds of citizenship are a mere formality, while municipal citizenship is the most significant step in becoming a Swiss citizen.
Nowadays the place of residence determines the municipality where citizenship is acquired, for a new applicant, whereas previously there was a historical reason for preserving the municipal citizenship from earlier generations in the family line, namely to specify which municipality held the responsibility of providing social welfare. The law has now been changed, eliminating this form of allocating responsibility to a municipality other than that of the place of residence. Care needs to be taken when translating the term in Swiss documents which list the historical "Heimatort" instead of the usual place of birth and place of residence.
However, any Swiss citizen can apply for a second, a third or even more municipal citizenships for prestige reasons or to show their connection to the place they currently live – and thus have several places of origin. As the legal significance of the place of origin has waned (see below), Swiss citizens can often apply for municipal citizenship for no more than 100 Swiss francs after having lived in the same municipality for one or two years. In the past, it was common to have to pay between 2,000 and 4,000 Swiss francs as a citizenship fee, because of the financial obligations incumbent on the municipality to grant the citizenship.
A child born to two Swiss parents is automatically granted the citizenship of the parent whose last name they hold, so the child gets either the mother's or the father's place of origin. A child born to one Swiss parent and one foreign parent acquires the citizenship, and thus the place of origin, of the Swiss parent.

International confusion
Almost uniquely in the world (with the exception of Japan, which lists one's Registered Domicile; and Sweden, which lists the mother's place of domicile as place of birth), the Swiss identity card, passport and driving licence do not show the holder's birthplace, but only their place of origin. The vast majority of countries show the holder's actual birthplace on identity documents. This can lead to administrative issues for Swiss citizens abroad when asked to demonstrate their actual place of birth, as no such information exists on any official Swiss identification documents. Only a minority of Swiss citizens have a place of origin identical to their birthplace. More confusion comes into play through the fact that people can have more than one place of origin.

Significance and history
A citizen of a municipality does not enjoy a larger set of rights than a non-citizen of the same municipality. To vote in communal, cantonal or national matters, only the current place of residence matters – or in the case of citizens abroad, the last Swiss place of residence.
The law previously required that a citizen's place of origin continued to bear all their social welfare costs for two years after the citizen moved away. In 2012, the National Council voted by 151 to 9 votes to abolish this law. The place of domicile is now the sole payer of welfare costs.In 1923, 1937, 1959 and 1967, more cantons signed treaties that assured that the place of domicile had to pay welfare costs instead of the place of origin, reflecting the fact that fewer and fewer people lived in their place of origin (1860: 59%, in 1910: 34%).In 1681, the Tagsatzung – the then Swiss parliament – decided that beggars should be deported to their place of origin, especially if they were insufficiently cared for by their residential community.In the 19th century, Swiss municipalities even offered free emigration to the United States if the Swiss citizen agreed to renounce municipal citizenship, and with that the right to receive welfare.

See also
Ancestral home (Chinese)
Bon-gwan
Registered domicile

== Notes and references ==
Passage 5:
Maria Pietersdr Olycan
Portrait of Maria Pietersdochter Olycan is an oil-on-canvas painting by the Dutch Golden Age painter Frans Hals, painted in 1638, now in the São Paulo Museum of Art. It is considered a pendant to the portrait of Maria's husband Andries van Hoorn.

Life
Maria Pietersdr Olycan was born in Haarlem in 1607 as the daughter of the wealthy brewers Pieter Jacobsz Olycan and Maritge Claesdr. Voogt. She was the younger sister of the brewer Jacob Pietersz Olycan. Maria's older sister Dorothea married Cornelis van Loo, the son of another brewer, Claes van Loo. Her brother Nicolaes van Olycan married Agatha Dicx, the daughter of the brewer and mayor, Dirk Dicx. Maria's younger sister Hester married the brewer Tyman Oosdorp.
On 25 July 1638 Maria married the widower Andries van Hoorn, also a brewer. He had a daughter Christine by his first marriage and a brewery of his own. His sister Agatha had married the brewer Cornelis Guldewagen. Andries and Maria had a daughter of their own, also called Maria, in 1639, but Maria Pietersdr Olycan died only five years later in 1655. Andries survived his second wife by 22 years and lived to see his daughter Christine's wedding in 1657 to Adriaan Noirot, and his daughter Maria's wedding in 1662 to the diplomat jhr. mr. Cornelis Ascanius van Sypesteyn. He also lived to see the Sypesteyn house be searched by a mob in 1672 on suspicion of hiding Johan de Witt, and though nothing was found, C.A. van Sypesteyn continued to be mistrusted and was stabbed to death in 1673 in Gorinchem. Maria van Hoorn outlived both her parents and her husband and died in 1704.

Painting
Maria's dress reflects the height of fashion in 1638. The millstone collar has made way for layers of intricate lace that edge see-through linen collars that come together with a brooch in a manner that suggests a decolleté. She is holding a fan and wears matching pearl bracelets and a pearl necklace. Her hair is wrapped around a diadem that is studded with gold dangles. This portrait was documented by Hofstede de Groot in 1910, before the sitter was identified. He wrote "384. PORTRAIT OF A WOMAN. M. 206. Half-length. She is turned slightly to the left, and looks at the spectator. Her left hand is at her breast ; her right hand holds her fan. She wears a black dress trimmed with lace, a close-fitting cap, a white lace collar and wristbands, and a pearl necklace. Grey background. Painted about the years 1635-40. Canvas, 31 1/2 inches by 25 1/2 inches. Exhibited in the Royal Academy Winter Exhibition, London, 1903, No. 45. Exhibited at the Hudson-Fulton Celebration, Metropolitan Museum, New York, 1909, No. 31. Purchased in the Isle of Wight, 1896, from the grandson of George IV.'s cook, who had formerly owned it, by the London dealers Dowdeswell. In the possession, successively, of the London dealer C. Wertheimer ; of the Paris dealer C. Sedelmeyer ; and the London dealers T. Agnew and Sons. In the collection of J. Pierpont Morgan, London."
Of this portrait's pendant, Hofstede de Groot noted that it did not resemble the wedding portrait of Michiel de Wael that he included as #242. Of this portrait of an as yet unidentified man, he wrote:282. PORTRAIT OF A MAN SEATED. M. 135. Half-length. He faces right, and leans his left hand on a stick. He has a moustache and slight imperial. He wears a large black felt hat, a black costume, a white ruff, and yellowish-grey gloves. Doubtfully identified as a portrait of Michiel de Wael. [Compare 242.] Inscribed, "AETAT SVAE 32 AN 1638" (the last numeral is not clear); canvas, 34 inches by 26 1/2 inches. Exhibited at the Hudson-Fulton Celebration, Metropolitan Museum, New York, 1909, No. 30. Bought in Paris by an elder Seymour (for .40). Sale. Arthur Seymour, London, April I, 1897, No. 113 (T. Agnew and Sons). In the collection of J. Pierpont Morgan, London.
In 1974 Seymour Slive tried to trace the remark about the king's cook but there is no reference in the Royal collections of such a statement. He remarked on Andries' portrait bearing an inscription and coat of arms while Maria's portrait lacks this, but notes that coats of arms were generally added by later descendants.

Wedding pendant
See also
List of paintings by Frans Hals
Passage 6:
Sennedjem
Sennedjem was an Ancient Egyptian artisan who was active during the reigns of Seti I and Ramesses II. He lived in Set Maat (translated as "The Place of Truth"), contemporary Deir el-Medina, on the west bank of the Nile, opposite Thebes. Sennedjem had the title "Servant in the Place of Truth". He was buried along with his wife, Iyneferti, and members of his family in a tomb in the village necropolis. His tomb was discovered January 31, 1886. When Sennedjem's tomb was found, it contained furniture from his home, including a stool and a bed, which he used when he was alive.His titles included Servant in the Place of Truth, meaning that he worked on the excavation and decoration of the nearby royal tombs.

See also

TT1 – (Tomb of Sennedjem, family and wife)
Passage 7:
Boris I of Bulgaria
Knyaz Boris I (also Bogoris), venerated as Saint Tsar Boris I (Mihail) the Baptizer  (Church Slavonic: Борисъ А҃  / Борисъ-Михаилъ Bulgarian: Борис I / Борис-Михаил; died 2 May 907), was the ruler of the First Bulgarian Empire in 852–889. At the time of his baptism in 864, Boris was named Michael after his godfather, Emperor Michael III. The historian Steven Runciman called him one of the greatest persons in history.Despite a number of military setbacks, the reign of Boris I was marked with significant events that shaped Bulgarian and European history. With the Christianization of Bulgaria in 864 paganism (i.e. Tengrism) was abolished. A skillful diplomat, Boris I successfully exploited the conflict between the Patriarchate of Constantinople and the Papacy to secure an autocephalous Bulgarian Church, thus dealing with the nobility's concerns about Byzantine interference in Bulgaria's internal affairs.
When in 885 the disciples of Saints Cyril and Methodius were banished from Great Moravia, Boris I gave them refuge and provided assistance which saved the Glagolithic and later promoted the development of the Cyrillic script in Preslav and the Slavic literature. After he abdicated in 889, his eldest son and successor tried to restore the old pagan religion but was deposed by Boris I. During the Council of Preslav which followed that event, the Byzantine clergy was replaced with Bulgarian, and the Greek language was replaced with what is now known as Old Church Slavonic.
He is regarded as a saint in the Orthodox Church, as the Prince and baptizer of Bulgaria, and as Equal-to-the-Apostles, with his feast day observed on May 2 and in Synaxis of all venerable and holy Fathers of Bulgaria (movable holiday on the 2nd Sunday of Pentecost).

Name and titles
The most common theory is that the name Boris is of Bulgar origin. After his official act of conversion to Christianity, Boris adopted the Christian name Michael. He is sometimes called Boris-Michael in historical research.
The only direct evidence of Boris's title are his seals and the inscription found near the town of Ballsh, modern Albania, and at Varna. There he is called by the Byzantine title "Archon of Bulgaria", which is usually translated as "ruler", and in the 10-11th centuries also as "Knyaz" (Кнѧзъ, Bulg.). In the Bulgarian sources from that period, Boris I is called "Knyaz" or "Tsar" ("Царь", Bulg.), and during the Second Bulgarian Empire, "Tsar".In modern historiography Boris is called by different titles. Most historians accept that he changed his title after his conversion to Christianity. According to them, before the baptism he had the title Khan or Kanasubigi, and after that Knyaz.

Reign
Central Europe in the 9th century
The early 9th century marked the beginning of a fierce rivalry between the Greek East and Latin West, which would ultimately lead to the schism between the Orthodox Church in Constantinople and the Catholic Church in Rome.
As early as 781, the Empress Irene began to seek a closer relationship with the Carolingian dynasty and the Papacy. She negotiated a marriage between her son, Constantine, and Rotrude, a daughter of Charlemagne by his third wife Hildegard. Irene went as far as to send an official to instruct the Frankish princess in Greek; however, Irene herself broke off the engagement in 787, against her son's wishes. When the Second Council of Nicaea of 787 reintroduced the veneration of icons under Empress Irene, the result was not recognized by Charlemagne since no Frankish emissaries had been invited even though Charlemagne was by then ruling more than three provinces of the old Roman empire. While this improved relations with the Papacy, it did not prevent the outbreak of a war with the Franks, who took over Istria and Benevento in 788.
When Charlemagne was proclaimed Emperor of the Holy Roman Empire by Leo III, the Pope was effectively nullifying the legitimacy of Irene. He certainly desired to increase the influence of the papacy and to honour his protector Charlemagne. Irene, like many of her predecessors since Justinian I, was too weak to protect Rome and its much reduced citizenry and the city was not being ruled by any emperor. Thus, Charlemagne's assumption of the imperial title was not seen as an usurpation in the eyes of the Franks or Italians. It was, however, seen as such in Byzantium, but protests by Irene and her successor Nicephorus I had no great effect.
Mojmír I managed to unite some Slavic princes and established Great Moravia in 833. His successor, Rastislav, also fought against the Germans. Both states tried to maintain good relations with Bulgaria on account of its considerable military power.

Military campaigns
Boris I was the son and successor of Presian I of Bulgaria. In 852 he sent emissaries to Eastern Francia to confirm the peace treaty of 845. At the time of his accession he threatened the Byzantines with an invasion, but his armies did not attack, and he received a small area in Strandzha to the southeast. The peace treaty was not signed, however, although both states exchanged temporary delegations. In 854 the Moravian Prince Rastislav persuaded Boris I to help him against East Francia. According to some sources, some Franks bribed the Bulgarian monarch to attack Louis the German. The Bulgarian-Slav campaign was a disaster, and Louis scored a great victory and invaded Bulgaria. At the same time the Croats waged a war against the Bulgarians. Both peoples had coexisted peacefully up to that time, suggesting that the Croats were paid by Louis to attack Bulgaria and distract Boris' attention from his alliance with Great Moravia. Kanasubigi Boris could not achieve any success, and both sides exchanged gifts and settled for peace. As a result of the military actions in 855, the peace between Bulgaria and Eastern Francia was restored, and Rastislav was forced to fight against Louis alone. In the meantime, a conflict between the Byzantines and Bulgarians had started in 855–856, and Boris, distracted by his conflict with Louis, lost Philippopolis (Plovdiv), the region of Zagora, and the ports around the Gulf of Burgas on the Black Sea to the Byzantine army led by Michael III and the caesar Bardas.

Serbia
After the death of Knez Vlastimir of Serbia circa 850, his state was divided between his sons. Vlastimir and Boris' father had fought against each other in the Bulgarian-Serbian War of 839–842, which resulted in a Serbian victory, and Boris sought to avenge that defeat. In 853 or 854, the Bulgarian army led by Vladimir-Rasate, the son of Boris I, invaded Serbia, with the aim of replacing the Byzantine overlordship over the Serbs. The Serbian army was led by Mutimir and his two brothers; they defeated the Bulgarians, capturing Vladimir and 12 boyars. Boris I and Mutimir agreed to peace (and perhaps an alliance), and Mutimir sent his sons Pribislav and Stefan to the border to escort the prisoners, where they exchanged items as a sign of peace. Boris himself gave them "rich gifts", while he was given "two slaves, two falcons, two dogs, and 80 furs". An internal conflict among the Serbian brothers resulted in Mutimir banishing the two younger brothers to the Bulgarian court. Mutimir, however, kept a nephew, Petar, at his court for political reasons. The reason for the feud is not known, though it is postulated that it was a result of treachery. Petar would later defeat Pribislav, Mutimir's son, and take the Serbian throne.

Motivations for baptism and conversion to Christianity
There are a number of versions as to why Boris converted to Christianity. Some historians attribute it to the intervention of his sister who had already converted while being at Constantinople.  Another story mentions a Greek slave in the ruler's court.  A more mythological version is the one in which Boris is astonished and frightened by an icon of Judgement day and thus decides to adopt Christianity. Richard B. Spence sees the decision as deliberate, practical, and politic.For a variety of diplomatic reasons, Boris became interested in converting to Christianity. In order to both extend his control over the Slavic world and gain an ally against one of the most powerful foes of the Bulgars, the Byzantine Empire, Boris sought to establish an alliance with Louis the German against Ratislav of Moravia. Through this alliance, Louis promised to supply Boris with missionaries, which would have effectively brought the Bulgars under the Roman Church.  However, late in 863, the Byzantine Empire under Emperor Michael III declared war on Boris and the Bulgars during a period of famine and natural disasters.  Taken by surprise, Boris was forced to make peace with the Byzantines, promising to convert to Christianity according to the eastern rites, in exchange for peace and territorial concessions in Thrace (he regained the region of Zagora recently recovered by the Byzantines).  At the beginning of 864, Boris was secretly baptized at Pliska by an embassy of Byzantine clergymen, together with his family and select members of the Bulgarian nobility.  With Emperor Michael III as his godfather, Boris also adopted the Christian name Michael.Separate from diplomatic concerns, Boris was interested in converting himself and the Bulgarians to Christianity to resolve the disunity within the Bulgarian society. When he ascended to the throne, the Bulgars and Slavs were separate elements within Boris' kingdom, the minority Bulgars constituting a military aristocracy. Richard Spence compares it to the relationship between the Normans and Saxons in England. Religious plurality further contributed to divisions within the society. The Slavs had their own polytheistic belief system while the Bulgar elite believed in Tangra, the Sky God, or God of Heaven.
The arrival of Methodius and his followers introduced the Cyrillic alphabet, freeing the Bulgarians from dependence on Greek as a written and liturgical language. A Slavic Christian culture developed that helped unify the realm.

Baptism of the Bulgarians and the establishment of the Bulgarian Church
After his baptism, the first major task that Boris undertook was the baptism of his subjects and for this task he appealed to Byzantine priests between 864 and 866. At the same time Boris sought further instruction on how to lead a Christian lifestyle and society and how to set up an autocephalous church from the Byzantine Patriarch Photios.  Photios' answer proved less than satisfactory, and Boris sought to gain a more favorable settlement from the Papacy.  Boris dispatched emissaries led by the kavhan Peter with a long list of questions to Pope Nicholas I at Rome in August 866, and obtained 106 detailed answers, detailing the essence of religion, law, politics, customs and personal faith.  Stemming from his concerns with the baptism of the Bulgarians, Boris also complained to Nicholas about the abuses perpetrated by the Byzantine priests responsible for baptizing the Bulgarians and how he could go about correcting the consequences resulting from these abuses. The pope temporarily glossed over the controversial question of the autocephalous status desired by Boris for his church and sent a large group of missionaries to continue the conversion of Bulgaria in accordance with the western rite. Bulgaria's shift towards the Papacy infuriated Patriarch Photios, who wrote an encyclical to the eastern clergy in 867 in which he denounced the practices associated with the western rite and Rome's ecclesiastical intervention in Bulgaria. This occasioned the Photian Schism, which was a major step in the rift between the eastern and western churches.
To deliver his response to Boris’ questions, Pope Nicholas I sent two bishops to Bulgaria: Paul of Populonia and Formosus of Porto. The Pope expected that these priests would execute their episcopal responsibilities to address Boris’ concerns, but did not intend for them to be elevated to the positions that they assumed in the Bulgar hierarchy. In Bulgaria, the activities of Bishop Formosus (later Pope Formosus) met with success, until the pope rejected Boris' request to nominate Formosus as archbishop of Bulgaria. Nicholas justified the rejection of the request by arguing that it was “uncanonical to transfer an already established bishop from one see to another”. The new Pope Adrian II refused Boris' request for a similar nomination of either Formosus or Deacon Marinus (later Pope Marinus I), after which Bulgaria began to shift towards Constantinople once again.  At the Fourth Council of Constantinople in 870 the position of the Bulgarian church was reopened by Bulgarian envoys, and the eastern patriarchs adjudicated in favor of Constantinople.  This determined the future of the Bulgarian Orthodox Church, which was granted the status of an autocephalous archbishopric by the Patriarchate of Constantinople and an archbishop of its own. Later in the 870s, the Patriarch of Constantinople surrendered Bulgaria to the Papacy, but this concession was purely nominal, as it did not affect the actual position of Bulgaria's autocephalous church.The Christianization of the Bulgarians as a result of Boris’ actions had profound effects not only on the religious belief system of the Bulgarians but also the structure of the Bulgarian government. Upon embracing Christianity, Boris took on the title of Tsar and joined the community of nations that embraced Christ, to the great delight of the Eastern Roman Empire, which was later given the name Byzantium by historians.Toward the end of his reign, Boris began to increase the number of native Bulgarian clergy. Consequently, Boris began to send Bulgarians to Constantinople to obtain a monastic education and some of these Bulgarians returned to their homeland to serve as clergymen. In 885, Boris was presented with a new opportunity to establish a native clergy when Slavic-speaking disciples of St. Cyril and St. Methodius were forced to flee from Moravia after a German-inspired reaction to the death of the apostle.

Changes to Bulgarian culture brought on by Clement and Naum
In 886 Boris' governor of Belgrade welcomed the disciples of Saint Cyril and Saint Methodius, who were exiled from Great Moravia into Bulgaria and sent them on to Boris in Pliska. Boris happily greeted two of these disciples, Clement of Ohrid and Naum of Preslav, who were of noble Bulgarian Slavic origin. To utilize the disciple's talents, Boris commissioned Clement to be a “teacher” in the province of Kutmichevitsa.
Both Clement and Naum were instrumental in furthering the cultural, linguistic and spiritual works of Cyril and Methodius. They set up educational centers in Pliska and in Ohrid to further the development of Slavonic letters and liturgy. Clement later trained thousands of Slavonic-speaking priests who replaced the Greek-speaking clergy from Constantinople still present in Bulgaria. The script that was originally developed by Cyril and Methodius is known as the Glagolitic alphabet.
In Bulgaria, Clement of Ohrid and Naum of Preslav created (or rather compiled) the new Bulgarian script, later called Cyrillic that was declared the official alphabet in  893. Old Bulgarian was declared as the official language in the same year. In the following centuries this script was adopted by other Slavic peoples and states. The introduction of Slavic liturgy paralleled Boris' continued development of churches and monasteries throughout his realm.

Reactions to religious conversion
Conversion to Christianity met great opposition among the Bulgarian elite. Some refused to become Christians while others apostatized after baptism and started a rebellion against Boris for forcing them to be baptized. Some people did not object necessarily to the Christian religion but to the fact that it was brought by foreign priests, which, as a result, established external foreign policy. By breaking the power of the old cults, Boris reduced the influence of the boyars, who resisted the khan's authority. In the summer of 865 a group of Bulgar aristocrats (boyars) started an open revolt. Boris ruthlessly suppressed it and executed 52 boyars together with their entire families. Thus the Christianization continued.

End of Boris' reign
In 889 Boris abdicated the throne and became a monk. His son and successor Vladimir attempted a pagan reaction, which brought Boris out of retirement in 893. Vladimir was defeated and Boris had him blinded, his wife shaved and sent to a monastery. Boris gathered the Council of Preslav placing his third son, Tsar Simeon I of Bulgaria, on the throne, threatening him with the same fate if he too apostatized. Boris returned to his monastery, emerging once again in c. 895 to help Simeon fight the Magyars, who had invaded Bulgaria in alliance with the Byzantines. After the passing of this crisis, Boris resumed monastic life and died in 907. The location of his retreat, where perhaps he was interred, is not certain; it may be near Preslav, or Pliska, or in a monastery near Varna or Ravda.

Legacy
St. Boris Peak on Livingston Island in the South Shetland Islands, Antarctica is named for Boris I of Bulgaria.
Boris I's life is featured in the 1985 film "Boris I" (Борис Първи), with Stefan Danailov in the title role.

See also
Christianization of Bulgaria
Cyril and Methodius
Glagolitic alphabet

Footnotes
Passage 8:
Maria (wife of Boris I of Bulgaria)
Maria (Bulgarian: Мария) was a Bulgarian royal consort as the wife of the Knyaz Boris I of Bulgaria. Her parents are unknown. She is mentioned in one charter from 850/96, together with her family members.
These are the children of Boris and Maria:

Vladimir of Bulgaria
Gavriil (Gabriel)
Simeon I of Bulgaria
Jacob
Anna

Footnotes

== External links ==
Passage 9:
Place of birth
The place of birth (POB) or birthplace is the place where a person was born. This place is often used in legal documents, together with name and date of birth, to uniquely identify a person. Practice regarding whether this place should be a country, a territory or a city/town/locality differs in different countries, but often city or territory is used for native-born citizen passports and countries for foreign-born ones.
As a general rule with respect to passports, if the place of birth is to be a country, it's determined to be the country that currently has sovereignty over the actual place of birth, regardless of when the birth actually occurred. The place of birth is not necessarily the place where the parents of the new baby live. If the baby is born in a hospital in another place, that place is the place of birth. In many countries, this also means that the government requires that the birth of the new baby is registered in the place of birth.
Some countries place less or no importance on the place of birth, instead using alternative geographical characteristics for the purpose of identity documents. For example, Sweden has used the concept of födelsehemort ("domicile of birth") since 1947. This means that the domicile of the baby's mother is the registered place of birth. The location of the maternity ward or other physical birthplace is considered unimportant.
Similarly, Switzerland uses the concept of place of origin. A child born to Swiss parents is automatically assigned the place of origin of the parent with the same last name, so the child either gets their mother's or father's place of origin. A child born to one Swiss parent and one foreign parent acquires the place of origin of their Swiss parent. In a Swiss passport and identity card, the holder's place of origin is stated, not their place of birth. In Japan, the registered domicile is a similar concept.
In some countries (primarily in the Americas), the place of birth automatically determines the nationality of the baby, a practice often referred to by the Latin phrase jus soli. Almost all countries outside the Americas instead attribute nationality based on the nationality(-ies) of the baby's parents (referred to as jus sanguinis).
There can be some confusion regarding the place of birth if the birth takes place in an unusual way: when babies are born on an airplane or at sea, difficulties can arise. The place of birth of such a person depends on the law of the countries involved, which include the nationality of the plane or ship, the nationality(-ies) of the parents and/or the location of the plane or ship (if the birth occurs in the territorial waters or airspace of a country).
Some administrative forms may request the applicant's "country of birth". It is important to determine from the requester whether the information requested refers to the applicant's "place of birth" or "nationality at birth". For example, US citizens born abroad who acquire US citizenship at the time of birth, the nationality at birth will be USA (American), while the place of birth would be the country in which the actual birth takes place.

Reference list
8 FAM 403.4 Place of Birth
Passage 10:
Motherland (disambiguation)
Motherland is the place of one's birth, the place of one's ancestors, or the place of origin of an ethnic group.
Motherland may also refer to:

Music
"Motherland" (anthem), the national anthem of Mauritius
National Song (Montserrat), also called "Motherland"
Motherland (Natalie Merchant album), 2001
Motherland (Arsonists Get All the Girls album), 2011
Motherland (Daedalus album), 2011
"Motherland" (Crystal Kay song), 2004

Film and television
Motherland (1927 film), a 1927 British silent war film
Motherland (2010 film), a 2010 documentary film
Motherland (2015 film), a 2015 Turkish drama
Motherland (2022 film), a 2022 documentary film about the Second Nagorno-Karabakh War
Motherland (TV series), a 2016 British television series
Motherland: Fort Salem, a 2020 American science fiction drama series

Other uses
Motherland Party (disambiguation), the name of several political groups
Personifications of Russia, including a list of monuments called Motherland

See also
All pages with titles containing Motherland
Mother Country (disambiguation)

Answer the question based on the given passages. Only give me the answer and do not output any other words.

Question: Where was the place of death of Maria (Wife Of Boris I Of Bulgaria)'s husband?
Answer:


Prompt:
Please complete the code given below.
src/main/java/uw/task/util/LocalRateLimiter.java
public class LocalRateLimiter {

    private ConcurrentHashMap<String, RateLimiter> map = new ConcurrentHashMap<>();

    /**
     * 尝试获得限制允许状态。
     *
     * @param name
     * @return
     */
    public boolean tryAcquire(String name, int requests, int seconds, long waitTime, int permits) {
        if (requests == 0 || seconds == 0) {
            return true;
        }
        final double rate = (double) requests / (double) seconds;
        RateLimiter limiter = map.computeIfAbsent(name, key -> RateLimiter.create(rate));
        if (limiter != null) {
            //检查并修改
            if (limiter.getRate() != rate) {
                limiter.setRate(rate);
            }
            return limiter.tryAcquire(permits, waitTime, TimeUnit.SECONDS);
        } else {
            return true;
        }
    }

}
src/main/java/uw/task/TaskFactory.java
public class TaskFactory {

    private static final Logger log = LoggerFactory.getLogger(TaskFactory.class);

    /**
     * rabbitTemplate模板.
     */
    private RabbitTemplate rabbitTemplate;

    /**
     * 全局sequence序列，主要用于taskLog日志。
     */
    private GlobalSequenceManager globalSequenceManager;

    /**
     * 用于本地执行任务的taskConsumer。
     */
    private TaskRunnerContainer taskRunnerContainer;

    /**
     * rpc异步调用线程池
     */
    private ExecutorService taskRpcService = null;

    /**
     * 最大重试次数。
     */
    private static final int MAX_RETRY_TIMES = 10;

    public TaskFactory(TaskProperties taskProperties, RabbitTemplate rabbitTemplate,
                       TaskRunnerContainer taskRunnerContainer, GlobalSequenceManager globalSequenceManager) {
        this.rabbitTemplate = rabbitTemplate;
        this.taskRunnerContainer = taskRunnerContainer;
        this.globalSequenceManager = globalSequenceManager;
        taskRpcService = new ThreadPoolExecutor(taskProperties.getTaskRpcMinThreadNum(),
                taskProperties.getTaskRpcMaxThreadNum(), 20L, TimeUnit.SECONDS, new SynchronousQueue<>(),
                new ThreadFactoryBuilder().setDaemon(true).setNameFormat("TaskRpc-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy());

    }

    /**
     * 把任务发送到队列中
     *
     * @param taskData 任务数据
     */
    public void sendToQueue(final TaskData<?, ?> taskData) {
        Message message = buildTaskQueueMessage(taskData);
        String queue = message.getMessageProperties().getConsumerQueue();
        //此处可能出现The channelMax limit is reached.报错，所以进行重试。
        for (int i = 0; i < MAX_RETRY_TIMES; i++) {
            try {
                if (i > 0) {
                    Thread.sleep(i * 500);
                }
                rabbitTemplate.send(queue, queue, message);
                return;
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        throw new TaskRuntimeException("The channelMax limit is reached!");
    }

    /**
     * 构造Task消息对象，此方法用于提前构造TaskData。
     *
     * @param taskData
     * @return
     */
    private Message buildTaskQueueMessage(final TaskData taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());
        taskData.setRunType(TaskData.RUN_TYPE_GLOBAL);
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setConsumerQueue(TaskMetaInfoManager.getFitQueue(taskData));
        Message msg = rabbitTemplate.getMessageConverter().toMessage(taskData, messageProperties);
        return msg;
    }

    /**
     * 同步执行任务，可能会导致阻塞。
     * 在调用的时候，尤其要注意，taskData对象不可改变！
     *
     * @param taskData 任务数据
     * @return
     */
    @SuppressWarnings("unchecked")
    public <TP, RD> TaskData<TP, RD> runTask(final TaskData<TP, RD> taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());
        // 当自动RPC，并且本地有runner，而且target匹配的时候，运行在本地模式下。
        if (taskData.getRunType() == TaskData.RUN_TYPE_AUTO_RPC && TaskMetaInfoManager.checkRunnerRunLocal(taskData)) {
            // 启动本地运行模式。
            taskData.setRunType(TaskData.RUN_TYPE_LOCAL);
        }
        if (taskData.getRunType() == TaskData.RUN_TYPE_LOCAL) {
            taskRunnerContainer.process(taskData);
            return taskData;
        } else {
            taskData.setRunType(TaskData.RUN_TYPE_GLOBAL_RPC);
            //加入优先级信息。
            MessageProperties messageProperties = new MessageProperties();
            messageProperties.setPriority(10);
            messageProperties.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
            messageProperties.setExpiration("180000");
            Message message = rabbitTemplate.getMessageConverter().toMessage(taskData, messageProperties);
            // 全局运行模式
            String queue = TaskMetaInfoManager.getFitQueue(taskData);
            //此处可能出现The channelMax limit is reached.报错，所以进行重试。
            for (int i = 0; i < MAX_RETRY_TIMES; i++) {
                try {
                    if (i > 0) {
                        Thread.sleep(i * 500);
                    }
                    Message retMessage = rabbitTemplate.sendAndReceive(queue, queue, message);
                    return (TaskData<TP, RD>) rabbitTemplate.getMessageConverter().fromMessage(retMessage);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            throw new TaskRuntimeException("The channelMax limit is reached!");
        }
    }

    /**
     * 同步执行任务，可能会导致阻塞。
     * 在调用的时候，尤其要注意，taskData对象不可改变！
     *
     * @param taskData 任务数据
     * @return
     */
    @SuppressWarnings("unchecked")
    public <TP, RD> TaskData<TP, RD> runTaskLocal(final TaskData<TP, RD> taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());
        // 当自动RPC，并且本地有runner，而且target匹配的时候，运行在本地模式下。
        if (taskData.getRunType() == TaskData.RUN_TYPE_AUTO_RPC && TaskMetaInfoManager.checkRunnerRunLocal(taskData)) {
            // 启动本地运行模式。
            taskData.setRunType(TaskData.RUN_TYPE_LOCAL);
        }
        if (taskData.getRunType() == TaskData.RUN_TYPE_LOCAL) {
            taskRunnerContainer.process(taskData);
            return taskData;
        } else {
            throw new TaskRuntimeException(taskData.getClass().getName() + " is not a local task! ");
        }
    }

    /**
     * 远程运行任务，并返回future<TaskData<?,?>>。 如果需要获得数据，可以使用futrue.get()来获得。
     * 此方法要谨慎使用，因为task存在限速，大并发下可能会导致线程数超。
     * 在调用的时候，尤其要注意，taskData对象不可改变！
     *
     * @param taskData 任务数据
     * @return
     */
    @SuppressWarnings("unchecked")
    public <TP, RD> Future<TaskData<TP, RD>> runTaskAsync(final TaskData<TP, RD> taskData) {
        taskData.setId(globalSequenceManager.nextId("task_runner_log"));
        taskData.setQueueDate(new Date());

        // 当自动RPC，并且本地有runner，而且target匹配的时候，运行在本地模式下。
        if (taskData.getRunType() == TaskData.RUN_TYPE_AUTO_RPC && TaskMetaInfoManager.checkRunnerRunLocal(taskData)) {
            // 启动本地运行模式。
            taskData.setRunType(TaskData.RUN_TYPE_LOCAL);
        }
        if (taskData.getRunType() == TaskData.RUN_TYPE_LOCAL) {
            // 启动本地运行模式。
            return taskRpcService.submit(() -> {
                taskRunnerContainer.process(taskData);
                return taskData;
            });
        } else {
            // 全局运行模式
            taskData.setRunType(TaskData.RUN_TYPE_GLOBAL_RPC);
            //加入优先级信息。
            MessageProperties messageProperties = new MessageProperties();
            messageProperties.setPriority(10);
            messageProperties.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
            messageProperties.setExpiration("180000");
            Message message = rabbitTemplate.getMessageConverter().toMessage(taskData, messageProperties);
            String queue = TaskMetaInfoManager.getFitQueue(taskData);
            return taskRpcService.submit(() -> {
                //此处可能出现The channelMax limit is reached.报错，所以进行重试。
                for (int i = 0; i < MAX_RETRY_TIMES; i++) {
                    try {
                        if (i > 0) {
                            Thread.sleep(i * 500);
                        }
                        Message retMessage = rabbitTemplate.sendAndReceive(queue, queue, message);
                        return (TaskData<TP, RD>) rabbitTemplate.getMessageConverter().fromMessage(retMessage);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                }
                throw new TaskRuntimeException("The channelMax limit is reached!");
            });
        }
    }

    /**
     * 获得队列信息。
     *
     * @param queueName
     * @return 0 是消息数量 1 是消费者数量
     */
    public int[] getQueueInfo(String queueName) {
        AMQP.Queue.DeclareOk declareOk = this.rabbitTemplate.execute(new ChannelCallback<AMQP.Queue.DeclareOk>() {
            public AMQP.Queue.DeclareOk doInRabbit(Channel channel) throws Exception {
                return channel.queueDeclarePassive(queueName);
            }
        });
        return new int[]{declareOk.getMessageCount(), declareOk.getConsumerCount()};
    }

    /**
     * 清除队列。
     *
     * @param queueName
     * @return 被清除的队列数
     */
    public int purgeQueue(String queueName) {
        return this.rabbitTemplate.execute(channel -> {
            AMQP.Queue.PurgeOk queuePurged = channel.queuePurge(queueName);
            return queuePurged.getMessageCount();
        });
    }

}
src/main/java/uw/task/listener/RunnerTaskListener.java
public interface RunnerTaskListener {

    /**
     * 执行前的监听器。
     *
     * @param data
     */
    public void onPreExecute(TaskData data);

    /**
     * 执行后的监听器。
     *
     * @param data
     */
    public void onPostExecute(TaskData data);

}
src/main/java/uw/task/util/GlobalRateLimiter.java
public class GlobalRateLimiter {

    private static final Logger log = LoggerFactory.getLogger(GlobalRateLimiter.class);

    private static final String REDIS_PREFIX = "TaskRateLimit:";

    private final RedisTemplate<String, Long> redisTemplate;

    /**
     * LUA脚本。
     * 返回值为：可用请求数,等待毫秒数。
     */
    private static final RedisScript<Long> LUA_RATE_LIMIT = RedisScript.of(
            "local key = KEYS[1];\n" +
                    "local requests = tonumber(ARGV[1]);\n" +
                    "local millis = tonumber(ARGV[2])*1000;\n" +
                    "local permits = tonumber(ARGV[3]);\n" +
                    "local remainRequests=0;\n" +
                    "local waitMillis=0;\n" +
                    "local nowRate= redis.call('INCRBY', key,permits);\n" +
                    "if (nowRate==permits) then \n" +//如果是第一次执行，设置有效期保护。
                    "    redis.call('PEXPIRE',key,millis);\n" +
                    "end\n" +
                    "remainRequests = requests-nowRate;\n" +
                    "if (remainRequests<1) then \n" +//请求数超过限制
                    "    waitMillis = redis.call('PTTL',key);\n" +
                    "    if (waitMillis == -1) then \n" +
                    "        redis.call('PEXPIRE',key,millis);\n" +
                    "        waitMillis = millis;\n" +
                    "    end\n" +
                    "end \n" +
                    "return waitMillis", Long.class);

    public GlobalRateLimiter(final RedisConnectionFactory redisConnectionFactory) {
        redisTemplate = new RedisTemplate<String, Long>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericToStringSerializer<Long>(Long.class));
        redisTemplate.setExposeConnection(true);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();
    }

    /**
     * 尝试可否获得授权。
     *
     * @param permits       申请访问次数
     * @return 如果未超限则返回0，-1为不确定时间，其他为需要等待的毫秒数
     */
    public long tryAcquire(String name, int requests, int seconds, int permits) {
        if (requests == 0 || seconds == 0) {
            return 0;
        }
        Long waitLimit = redisTemplate.execute(LUA_RATE_LIMIT, Collections.singletonList(REDIS_PREFIX + name), requests,seconds, permits);
        if (waitLimit==null)
            return 0;
        else
            return waitLimit;
    }

}
src/main/java/uw/task/exception/TaskPartnerException.java
public class TaskPartnerException extends Exception {

    /**
     * serialVersionUID 的注释
     */
    private static final long serialVersionUID = 8713460933603499992L;

    public TaskPartnerException() {
        super();
    }

    public TaskPartnerException(String msg) {
        super(msg);
    }

    public TaskPartnerException(Throwable nestedThrowable) {
        super(nestedThrowable);
    }

    public TaskPartnerException(String msg, Throwable nestedThrowable) {
        super(msg, nestedThrowable);
    }

}
src/main/java/uw/task/TaskData.java
public class TaskData<TP, RD> implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1333167065535557828L;

    /**
     * 任务状态:未设置
     */
    public static final int STATE_UNKNOWN = 0;

    /**
     * 任务状态:成功
     */
    public static final int STATE_SUCCESS = 1;

    /**
     * 任务状态:程序错误
     */
    public static final int STATE_FAIL_PROGRAM = 2;

    /**
     * 任务状态:配置错误，如超过流量限制
     */
    public static final int STATE_FAIL_CONFIG = 3;

    /**
     * 任务状态:第三方接口错误
     */
    public static final int STATE_FAIL_PARTNER = 4;

    /**
     * 任务状态:数据错误
     */
    public static final int STATE_FAIL_DATA = 5;

    /**
     * 运行模式：本地运行
     */
    public static final int RUN_TYPE_LOCAL = 1;

    /**
     * 运行模式：全局运行
     */
    public static final int RUN_TYPE_GLOBAL = 3;

    /**
     * 运行模式：全局运行RPC返回结果
     */
    public static final int RUN_TYPE_GLOBAL_RPC = 5;

    /**
     * 运行模式：自动运行RPC返回结果，使用此模式，会自动选择本地还远程运行模式。
     */
    public static final int RUN_TYPE_AUTO_RPC = 6;

    /**
     * 自动重试[为了兼容,默认开启重试]
     */
    public static final int RETRY_TYPE_AUTO = 0;

    /**
     * 用户手工重试
     */
    public static final int RETRY_TYPE_MANUAL = 1;

    /**
     * id，此序列值由框架自动生成，无需手工设置。
     */
    private long id;

    /**
     * 关联TAG，由调用方设定，用于第三方统计信息。
     */
    private String refTag;

    /**
     * 关联id，由调用方根据需要设置，用于第三方统计信息。
     */
    private long refId;

    /**
     * 关联子id，由调用方根据需要设置，用于第三方统计信息。
     */
    private long refSubId;

    /**
     * 关联对象，此对象不存入数据库，但可以通过Listener来访问。
     */
    @JsonIgnore
    private Object refObject;

    /**
     * 流量限制TAG。
     */
    private String rateLimitTag;

    /**
     * 需要执行的类名，此数值必须由调用方设置。
     */
    private String taskClass = "";

    /**
     * 任务标签，用于细分任务队列，支持多实例运行。
     */
    private String taskTag = "";

    /**
     * 任务延迟毫秒数。一般这个时间不宜太长，大多数情况下不要超过60秒。
     */
    private long taskDelay;

    /**
     * 执行参数，此数值必须有调用方设置。
     */
    private TP taskParam;

    /**
     * 任务运行类型，默认为自动RPC，根据情况选择本地还是远程运行。
     */
    private int runType = RUN_TYPE_AUTO_RPC;

    /**
     * 重试类型
     */
    private int retryType;

    /**
     * 指定运行目标。
     */
    private String runTarget = "";

    /**
     * 任务运行时主机IP，此信息由框架自动设置。
     */
    private String hostIp;

    /**
     * 任务运行时主机ID（可能为docker的ContainerID），此信息由框架自动设置。
     */
    private String hostId;

    /**
     * 进入队列时间，此信息由框架自动设置。
     */
    private Date queueDate;

    /**
     * 开始消费时间，此信息由框架自动设置。
     */
    private Date consumeDate;

    /**
     * 开始运行时间，此信息由框架自动设置。
     */
    private Date runDate;

    /**
     * 运行结束日期，此信息由框架自动设置。
     */
    private Date finishDate;

    /**
     * 执行信息，用于存储框架自动设置。
     */
    private RD resultData;

    /**
     * 出错信息
     */
    private String errorInfo;

    /**
     * 已经执行的次数，此信息由框架自动设置。
     */
    private int ranTimes;

    /**
     * 执行状态，此信息由框架根据异常自动设置。
     */
    private int state;

    /**
     * @return the id
     */
    public long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * @return the refId
     */
    public long getRefId() {
        return refId;
    }

    /**
     * @param refId the refId to set
     */
    public void setRefId(long refId) {
        this.refId = refId;
    }

    /**
	 * @return the refSubId
	 */
	public long getRefSubId() {
		return refSubId;
	}

	/**
	 * @param refSubId the refSubId to set
	 */
	public void setRefSubId(long refSubId) {
		this.refSubId = refSubId;
	}

	/**
	 * @return the refTag
	 */
	public String getRefTag() {
		return refTag;
	}

	/**
	 * @param refTag the refTag to set
	 */
	public void setRefTag(String refTag) {
		this.refTag = refTag;
	}

	/**
	 * @return the rateLimitTag
	 */
	public String getRateLimitTag() {
		return rateLimitTag;
	}

	/**
	 * @param rateLimitTag the rateLimitTag to set
	 */
	public void setRateLimitTag(String rateLimitTag) {
		this.rateLimitTag = rateLimitTag;
	}

	/**
	 * @return the refObject
	 */
	public Object getRefObject() {
		return refObject;
	}

    /**
     * @param refObject the refObject to set
     */
    public void setRefObject(Object refObject) {
        this.refObject = refObject;
    }

    /**
     * @return the taskClass
     */
    public String getTaskClass() {
        return taskClass;
    }

    /**
     * @param taskClass the taskClass to set
     */
    public void setTaskClass(String taskClass) {
        this.taskClass = taskClass;
    }

    /**
	 * @return the taskTag
	 */
	public String getTaskTag() {
		return taskTag;
	}

	public long getTaskDelay() {
		return taskDelay;
	}

	public void setTaskDelay(long taskDelay) {
		this.taskDelay = taskDelay;
	}

	/**
	 * @param taskTag the taskTag to set
	 */
	public void setTaskTag(String taskTag) {
		this.taskTag = taskTag;
	}

	/**
     * @return the taskParam
     */
    public TP getTaskParam() {
        return taskParam;
    }

    /**
     * @param taskParam the taskParam to set
     */
    public void setTaskParam(TP taskParam) {
        this.taskParam = taskParam;
    }

    /**
     * @return the runType
     */
    public int getRunType() {
        return runType;
    }

    /**
     * @param runType the runType to set
     */
    public void setRunType(int runType) {
        this.runType = runType;
    }

    public int getRetryType() {
        return retryType;
    }

    public void setRetryType(int retryType) {
        this.retryType = retryType;
    }

    /**
     * @return the runTarget
     */
    public String getRunTarget() {
        return runTarget;
    }

    /**
     * @param runTarget the runTarget to set
     */
    public void setRunTarget(String runTarget) {
        this.runTarget = runTarget;
    }

    /**
     * @return the hostIp
     */
    public String getHostIp() {
        return hostIp;
    }

    /**
     * @param hostIp the hostIp to set
     */
    public void setHostIp(String hostIp) {
        this.hostIp = hostIp;
    }

    /**
     * @return the hostId
     */
    public String getHostId() {
        return hostId;
    }

    /**
     * @param hostId the hostId to set
     */
    public void setHostId(String hostId) {
        this.hostId = hostId;
    }

    /**
     * @return the queueDate
     */
    public Date getQueueDate() {
        return queueDate;
    }

    /**
     * @param queueDate the queueDate to set
     */
    public void setQueueDate(Date queueDate) {
        this.queueDate = queueDate;
    }

    /**
     * @return the consumeDate
     */
    public Date getConsumeDate() {
        return consumeDate;
    }

    /**
     * @param consumeDate the consumeDate to set
     */
    public void setConsumeDate(Date consumeDate) {
        this.consumeDate = consumeDate;
    }

    /**
     * @return the runDate
     */
    public Date getRunDate() {
        return runDate;
    }

    /**
     * @param runDate the runDate to set
     */
    public void setRunDate(Date runDate) {
        this.runDate = runDate;
    }

    /**
     * @return the finishDate
     */
    public Date getFinishDate() {
        return finishDate;
    }

    /**
     * @param finishDate the finishDate to set
     */
    public void setFinishDate(Date finishDate) {
        this.finishDate = finishDate;
    }

    /**
     * @return the resultData
     */
    public RD getResultData() {
        return resultData;
    }

    /**
     * @param resultData the resultData to set
     */
    public void setResultData(RD resultData) {
        this.resultData = resultData;
    }

    /**
     * @return the errorInfo
     */
    public String getErrorInfo() {
        return errorInfo;
    }

    /**
     * @param errorInfo the errorInfo to set
     */
    public void setErrorInfo(String errorInfo) {
        this.errorInfo = errorInfo;
    }

    /**
     * @return the ranTimes
     */
    public int getRanTimes() {
        return ranTimes;
    }

    /**
     * @param ranTimes the ranTimes to set
     */
    public void setRanTimes(int ranTimes) {
        this.ranTimes = ranTimes;
    }

    /**
     * @return the status
     */
    public int getState() {
        return state;
    }

    /**
     * @param status the status to set
     */
    public void setState(int status) {
        this.state = status;
    }

}
src/main/java/uw/task/TaskRunner.java
public abstract class TaskRunner<TP, RD> {

    /**
     * 执行任务。
     * 业务层面的异常请根据实际情况手动Throw TaskException:
     * 目前支持的异常:
     * 1. TaskDataException 任务数据异常
     * 2. TaskPartnerException 任务合作方异常
     *
     * @param taskData 数据
     * @throws Exception 异常
     * @return 指定的返回对象
     */
    public abstract RD runTask(TaskData<TP, RD> taskData) throws Exception;

    /**
     * 初始化配置信息
     *
     * @return TaskRunnerConfig配置
     */
    public abstract TaskRunnerConfig initConfig();

    /**
     * 初始化联系人信息
     *
     * @return TaskContact联系人信息
     */
    public abstract TaskContact initContact();
}
src/main/java/uw/task/conf/TaskMetaInfoManager.java
public class TaskMetaInfoManager {

	/**
	 * 运行主机配置
	 */
	static List<String> targetConfig = null;

	/**
	 * Runner任务实例缓存。
	 */
	@SuppressWarnings("rawtypes")
	static Map<String, TaskRunner> runnerMap = new HashMap<>();

	/**
	 * Cron任务实例缓存。
	 */
	static Map<String, TaskCroner> cronerMap = new HashMap<>();

	/**
	 * Runner任务配置缓存
	 */
	static ConcurrentHashMap<String, TaskRunnerConfig> runnerConfigMap = new ConcurrentHashMap<>();

	/**
	 * Cron任务配置缓存。
	 */
	static ConcurrentHashMap<String, TaskCronerConfig> cronerConfigMap = new ConcurrentHashMap<>();

	/**
	 * 获得任务运行实例。
	 *
	 * @param taskClass
	 * @return
	 */
	public static TaskRunner<?, ?> getRunner(String taskClass) {
		return runnerMap.get(taskClass);
	}

	/**
	 * 检查一个runner是否可以在本地运行。
	 *
	 * @param taskData
	 * @return
	 */
	public static boolean checkRunnerRunLocal(TaskData<?, ?> taskData) {
		return runnerMap.containsKey(taskData.getTaskClass());
	}

	/**
	 * 根据服务器端Queue列表，返回合适的key。
	 *
	 * @return
	 */
	public static String getFitQueue(TaskData<?, ?> data) {
		StringBuilder sb = new StringBuilder(100);
		sb.append(data.getTaskClass()).append("#");
		if (data.getTaskTag() != null && data.getTaskTag().length() > 0) {
			sb.append(data.getTaskTag());
		}
		sb.append("$");
		if (data.getRunTarget() != null && data.getRunTarget().length() > 0) {
			sb.append(data.getRunTarget());
		}
		String all = sb.toString();
		if (runnerConfigMap.containsKey(all)) {
			return all;
		}
        // 检测去除TAG的情况
        if (!all.contains("#$")) {
            String test = all.substring(0, all.indexOf('#') + 1) + all.substring(all.lastIndexOf('$'), all.length());
            if (runnerConfigMap.containsKey(test)) {
                return test;
            }
        }
		// 检测去除目标的情况
		if (!all.endsWith("$")) {
			String test = all.substring(0, all.lastIndexOf('$') + 1);
			if (runnerConfigMap.containsKey(test)) {
				return test;
			}
		}
		// 两个都去除的情况
		if (!all.endsWith("#$")) {
			String test = data.getTaskClass() + "#$";
			if (runnerConfigMap.containsKey(test)) {
				return test;
			}
		}
		// 最后都没匹配到，返回原始数据
		return all;
	}

	/**
	 * 获得任务配置
	 *
	 * @param data
	 * @return
	 */
	public static TaskRunnerConfig getRunnerConfig(TaskData<?, ?> data) {
		TaskRunnerConfig config = null;
		StringBuilder sb = new StringBuilder(100);
		sb.append(data.getTaskClass()).append("#");
		if (data.getTaskTag() != null && data.getTaskTag().length() > 0) {
			sb.append(data.getTaskTag());
		}
		sb.append("$");
		if (data.getRunTarget() != null && data.getRunTarget().length() > 0) {
			sb.append(data.getRunTarget());
		}
		String all = sb.toString();
		config = runnerConfigMap.get(all);
		if (config != null) {
			return config;
		}
        // 检测去除TAG的情况
        if (!all.contains("#$")) {
            String test = all.substring(0, all.indexOf('#') + 1) + all.substring(all.lastIndexOf('$'), all.length());
            config = runnerConfigMap.get(test);
            if (config != null) {
                return config;
            }
        }
		// 检测去除目标的情况
		if (!all.endsWith("$")) {
			String test = all.substring(0, all.lastIndexOf('$') + 1);
			config = runnerConfigMap.get(test);
			if (config != null) {
				return config;
			}
		}
		// 两个都去除的情况
		if (!all.endsWith("#$")) {
			String test = data.getTaskClass() + "#$";
			config = runnerConfigMap.get(test);
			if (config != null) {
				return config;
			}
		}
		throw new RuntimeException("找不到任务配置: taskClass = " + data.getTaskClass());
	}

	/**
	 * 更新系统队列表。
	 *
	 * @param config
	 */
	static void updateSysQueue(final TaskRunnerConfig config) {
		String key = getRunnerConfigKey(config);
		// 检测是否老的TaskRunnerConfig是否是本地的完整配置，如果是，则不管。
		TaskRunnerConfig old = runnerConfigMap.get(key);
		if (old == null || (old != null && old.getCreateDate() == null)) {
			if (config.getState() < 1) {
				runnerConfigMap.remove(key);
			} else {
				runnerConfigMap.put(key, config);
			}
		}
	}

	/**
	 * 获得croner配置键。 使用taskClass#Id$target来配置
	 *
	 * @return
	 */
	public static String getCronerConfigKey(TaskCronerConfig config) {
		StringBuilder sb = new StringBuilder(100);
		sb.append(config.getTaskClass()).append("#");
		if (config.getTaskParam() != null && config.getTaskParam().length() > 0) {
			sb.append(config.getId());
		}
		sb.append("$");
		if (config.getRunTarget() != null && config.getRunTarget().length() > 0) {
			sb.append(config.getRunTarget());
		}
		return sb.toString();
	}

	/**
	 * 获得Runner配置结合Host。
	 *
	 * @return
	 */
	public static String getRunnerConfigKey(TaskRunnerConfig config) {
		StringBuilder sb = new StringBuilder(100);
		sb.append(config.getTaskClass()).append("#");
		if (config.getTaskTag() != null && config.getTaskTag().length() > 0) {
			sb.append(config.getTaskTag());
		}
		sb.append("$");
		if (config.getRunTarget() != null && config.getRunTarget().length() > 0) {
			sb.append(config.getRunTarget());
		}
		return sb.toString();
	}

    /**
     * 获得RunnerLog配置KEY
     *
     * @return
     */
    public static String getRunnerLogKey(TaskData<?,?> log) {
        StringBuilder sb = new StringBuilder(100);
        sb.append(log.getTaskClass()).append("#");
        if (log.getTaskTag() != null && log.getTaskTag().length() > 0) {
            sb.append(log.getTaskTag());
        }
        sb.append("$");
        if (log.getRunTarget() != null && log.getRunTarget().length() > 0) {
            sb.append(log.getRunTarget());
        }
        return sb.toString();
    }

    /**
     * 获得CronerLog配置KEY
     *
     * @return
     */
    public static String getCronerLogKey(TaskCronerLog log) {
        StringBuilder sb = new StringBuilder(100);
        sb.append(log.getTaskClass()).append("#");
        if (log.getTaskParam() != null && log.getTaskParam().length()>0){
            sb.append(log.getTaskParam());
        }
        sb.append("$");
        if (log.getRunTarget() != null && log.getRunTarget().length() > 0) {
            sb.append(log.getRunTarget());
        }
        return sb.toString();
    }
}
src/main/java/uw/task/api/TaskAPI.java
public class TaskAPI {

    private static final Logger log = LoggerFactory.getLogger(TaskAPI.class);

    /**
     * Task配置文件
     */
    private TaskProperties taskProperties;

    /**
     * Rest模板类
     */
    private RestTemplate restTemplate;

    /**
     * 日志客户端。
     */
    private LogClient logClient = null;

    /**
     * 本机的外网IP
     */
    private String hostIp = "";

    public TaskAPI(final TaskProperties taskProperties, final RestTemplate restTemplate,
                   final LogClient logClient) {
        this.taskProperties = taskProperties;
        this.restTemplate = restTemplate;
        this.logClient = logClient;
    }

    /**
     * @return the hostIp
     */
    public String getHostIp() {
        return hostIp;
    }

    /**
     * 更新当前主机目标配置。
     *
     * @return
     */
    public List<String> getServerTargetConfig() {
        List<String> targetConfig = null;
        // 判断是否是私有模式。
        boolean privacyMode = taskProperties.isPrivacyMode();
        try {
            String[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost() + "/taskapi/target/config?targetType={targetType}", String[].class,
                    privacyMode ? 1 : 0);
            targetConfig = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getHostConfig()服务端Target配置拉取异常:{}", e.getMessage());
        }
        if (targetConfig == null || targetConfig.size() == 0) {
            if (log.isWarnEnabled()) {
                log.warn("获得主机Target服务端配置失败，启用默认配置项!");
            }
            targetConfig = new ArrayList<>();
            if (!privacyMode) {
                targetConfig.add("");
            }
        }
        return targetConfig;
    }

    /**
     * 更新当前主机状态，返回主机IP地址。
     *
     * @return 主机IP地址
     */
    public String updateHostStatus() {
        String ip = "";
        TaskHostStatus taskHostStatus = new TaskHostStatus();
        taskHostStatus.setHostId(taskProperties.getHostId());
        taskHostStatus.setTaskProject(taskProperties.getProject());
        try {
            ip = restTemplate.postForObject(taskProperties.getTaskCenterHost() + "/taskapi/host/status", taskHostStatus,
                    String.class);
            hostIp = ip;
        } catch (Exception e) {
            log.error("TaskAPI.updateHostStatus()服务端主机状态更新异常:{}", e.getMessage());
        }
        return ip;
    }

    /**
     * 初始化CronerConfig。
     *
     * @param config
     */
    public TaskCronerConfig initTaskCronerConfig(TaskCronerConfig config) {
        try {
            config = restTemplate.postForObject(taskProperties.getTaskCenterHost() + "/taskapi/croner/config", config,
                    TaskCronerConfig.class);
        } catch (Exception e) {
            log.error("TaskAPI.initTaskCronerConfig上传Croner配置到服务端异常:{}", e.getMessage());
        }
        return config;
    }

    /**
     * 初始化RunnerConfig
     *
     * @param config
     */
    public TaskRunnerConfig initTaskRunnerConfig(TaskRunnerConfig config) {
        try {
            config = restTemplate.postForObject(taskProperties.getTaskCenterHost() + "/taskapi/runner/config", config,
                    TaskRunnerConfig.class);
        } catch (Exception e) {
            log.error("TaskAPI.initTaskRunnerConfig上传Runner配置到服务端异常:{}", e.getMessage());
        }
        return config;

    }

    /**
     * 初始化联系人信息。
     *
     * @param contact
     */
    public void initTaskContact(TaskContact contact) {
        try {
            restTemplate.postForLocation(taskProperties.getTaskCenterHost() + "/taskapi/contact", contact);
        } catch (Exception e) {
            log.error("TaskAPI.initTaskContact上传联系人信息到服务端异常:{}", e.getMessage());
        }
    }

    /**
     * 根据更新时间获得变化的TaskRunner队列列表。
     *
     * @param lastUpdateTime 最后更新时间
     * @return
     */
    public List<TaskRunnerConfig> getTaskRunnerQueueList(long lastUpdateTime) {
        List<TaskRunnerConfig> list = null;
        try {
            TaskRunnerConfig[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost() + "/taskapi/runner/queue?lastUpdateTime={lastUpdateTime}",
                    TaskRunnerConfig[].class, lastUpdateTime);
            list = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getTaskRunnerQueueList()服务端主机状态更新异常:{}", e.getMessage());
        }

        return list;
    }

    /**
     * 根据包名前缀获得TaskRunner配置列表。
     *
     * @param taskPackage
     * @param lastUpdateTime 最后更新时间
     * @return
     */
    public List<TaskRunnerConfig> getTaskRunnerConfigList(String taskPackage, long lastUpdateTime) {
        List<TaskRunnerConfig> list = null;
        try {
            TaskRunnerConfig[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost()
                            + "/taskapi/runner/config?taskPackage={taskPackage}&lastUpdateTime={lastUpdateTime}",
                    TaskRunnerConfig[].class, taskPackage, lastUpdateTime);
            list = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getTaskRunnerConfigList()服务端主机状态更新异常:{}", e.getMessage());
        }

        return list;
    }

    /**
     * 根据包名前缀获得TaskCroner配置列表。
     *
     * @param taskPackage
     * @param lastUpdateTime 最后更新时间
     * @return
     */
    public List<TaskCronerConfig> getTaskCronerConfigList(String taskPackage, long lastUpdateTime) {
        List<TaskCronerConfig> list = null;
        try {
            TaskCronerConfig[] data = restTemplate.getForObject(
                    taskProperties.getTaskCenterHost()
                            + "/taskapi/croner/config?taskPackage={taskPackage}&lastUpdateTime={lastUpdateTime}",
                    TaskCronerConfig[].class, taskPackage, lastUpdateTime);
            list = Arrays.asList(data);
        } catch (Exception e) {
            log.error("TaskAPI.getTaskCronerConfigList()服务端主机状态更新异常:{}", e.getMessage());
        }

        return list;
    }

    /**
     * 发送Runner任务日志。
     *
     * @param log
     */
    public void sendTaskRunnerLog(TaskRunnerLog log) {
        logClient.log(log);
    }

    /**
     * 发送CronLog日志
     *
     * @param configId      配置Id,方便更新下一次执行时间
     * @param taskCronerLog 日志对象
     */
    public void sendTaskCronerLog(long configId, TaskCronerLog taskCronerLog) {
        try {
            restTemplate.getForObject(
                    taskProperties.getTaskCenterHost()
                            + "/taskapi/croner/tick?id={id}&nextDate={nextDate}",
                    Integer.class, configId, taskCronerLog.getNextDate().getTime());
        } catch (Exception e) {
            log.error("TaskAPI.cornerTick()服务端主机状态更新异常: " + e.getMessage(), e);
        }

        int logLevel = taskCronerLog.getLogLevel();
        int logLimitSize = taskCronerLog.getLogLimitSize();
        if (logLevel > TaskCronerConfig.TASK_LOG_TYPE_NONE) {
            switch (logLevel) {
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD: {
                    taskCronerLog.setTaskParam(null);
                    taskCronerLog.setResultData(null);
                }
                break;
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD_TASK_PARAM: {
                    String taskParam = taskCronerLog.getTaskParam();
                    if (logLimitSize > 0 && StringUtils.isNotBlank(taskParam) && taskParam.length() > logLimitSize) {
                        taskCronerLog.setTaskParam(taskParam.substring(0, logLimitSize));
                    }
                    taskCronerLog.setResultData(null);
                }
                break;
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD_RESULT_DATA: {
                    String resultData = taskCronerLog.getResultData();
                    if (logLimitSize > 0 && StringUtils.isNotBlank(resultData) && resultData.length() > logLimitSize) {
                        taskCronerLog.setResultData(resultData.substring(0, logLimitSize));
                    }
                    taskCronerLog.setTaskParam(null);
                }
                break;
                case TaskCronerConfig.TASK_LOG_TYPE_RECORD_ALL: {
                    if (logLimitSize > 0) {
                        String taskParam = taskCronerLog.getTaskParam();
                        String resultData = taskCronerLog.getResultData();
                        if (StringUtils.isNotBlank(taskParam) && taskParam.length() > logLimitSize) {
                            taskCronerLog.setTaskParam(taskParam.substring(0, logLimitSize));
                        }
                        if (StringUtils.isNotBlank(resultData) && resultData.length() > logLimitSize) {
                            taskCronerLog.setResultData(resultData.substring(0, logLimitSize));
                        }
                    }
                }
                break;
            }
            logClient.log(taskCronerLog);
        }
    }
}
src/main/java/uw/task/exception/TaskDataException.java
public class TaskDataException extends Exception {

    /**
     * serialVersionUID 的注释
     */
    private static final long serialVersionUID = 8713460933603499992L;

    public TaskDataException() {
        super();
    }

    public TaskDataException(String msg) {
        super(msg);
    }

    public TaskDataException(Throwable nestedThrowable) {
        super(nestedThrowable);
    }

    public TaskDataException(String msg, Throwable nestedThrowable) {
        super(msg, nestedThrowable);
    }

}
src/main/java/uw/task/entity/TaskRunnerConfig.java
public class TaskRunnerConfig implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 限速类型：不限速
     */
    public static final int RATE_LIMIT_NONE = 0;

    /**
     * 限速类型：本地进程限速
     */
    public static final int RATE_LIMIT_LOCAL = 1;

    /**
     * 限速类型：本地TASK限速
     */
    public static final int RATE_LIMIT_LOCAL_TASK = 2;

    /**
     * 限速类型：本地TASK+TAG限速
     */
    public static final int RATE_LIMIT_LOCAL_TASK_TAG = 3;

    /**
     * 限速类型：全局主机HOST限速
     */
    public static final int RATE_LIMIT_GLOBAL_HOST = 4;

    /**
     * 限速类型：全局TAG限速
     */
    public static final int RATE_LIMIT_GLOBAL_TAG = 5;

    /**
     * 限速类型：全局TASK限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK = 6;

    /**
     * 限速类型：全局TAG+HOST限速
     */
    public static final int RATE_LIMIT_GLOBAL_TAG_HOST = 7;

    /**
     * 限速类型：全局TASK+IP限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK_HOST = 8;

    /**
     * 限速类型：全局TASK+TAG限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK_TAG = 9;

    /**
     * 限速类型：全局TASK+TAG+IP限速
     */
    public static final int RATE_LIMIT_GLOBAL_TASK_TAG_HOST = 10;

    /**
     * 什么都不记录
     */
    public static final int TASK_LOG_TYPE_NONE = -1;

    /**
     * 记录日志
     */
    public static final int TASK_LOG_TYPE_RECORD = 0;

    /**
     * 记录日志,含请求参数
     */
    public static final int TASK_LOG_TYPE_RECORD_TASK_PARAM = 1;

    /**
     * 记录日志,含返回参数
     */
    public static final int TASK_LOG_TYPE_RECORD_RESULT_DATA = 2;

    /**
     * 记录全部日志
     */
    public static final int TASK_LOG_TYPE_RECORD_ALL = 3;

    private long id;

    /**
     * 任务名称
     */
    private String taskName;

    /**
     * 任务描述
     */
    private String taskDesc;

    /**
     * 执行类信息
     */
    private String taskClass;

    /**
     * 执行类TAG，可能用于区分子任务
     */
    private String taskTag;

    /**
     * 消费者的数量
     */
    private int consumerNum = 1;

    /**
     * 预取任务数。
     */
    private int prefetchNum = 1;

    /**
     * 详见流量限制类型说明。
     */
    private int rateLimitType = RATE_LIMIT_NONE;

    /**
     * 流量限定数值，默认为10次
     */
    private int rateLimitValue = 10;

    /**
     * 流量限定时间(S)，默认为1秒
     */
    private int rateLimitTime = 1;

    /**
     * 当发生流量限制时，等待的秒数，默认300秒
     */
    private int rateLimitWait = 30;

    /**
     * 超过流量限制重试次数，默认不在重试，放弃任务。
     */
    private int retryTimesByOverrated = 0;

    /**
     * 对方接口错误重试次数，默认不再重试，放弃任务。
     */
    private int retryTimesByPartner = 0;

    /**
     * 运行目标，默认不指定
     */
    private String runTarget = "";

    /**
     * 失败率
     */
    private int failRate;

    /**
     * 接口失败率
     */
    private int failPartnerRate;

    /**
     * 程序失败率
     */
    private int failProgramRate;

    /**
     * 配置失败率
     */
    private int failConfigRate;

    /**
     * 数据失败率
     */
    private int failDataRate;

    /**
     * 队列等待超时
     */
    private int queueTimeout;

    /**
     * 等待超时
     */
    private int waitTimeout;

    /**
     * 运行超时
     */
    private int runTimeout;

    /**
     * 创建日期。
     */
    private Date createDate;

    /**
     * 修改日期。
     */
    private Date modifyDate;

    /**
     * 状态值
     */
    private int state = 1;

    /**
     * 详见日志类型说明
     */
    private int logLevel = TASK_LOG_TYPE_RECORD;

    /**
     * 日志字符串字段大小限制: 0 表示无限制
     */
    private int logLimitSize = 0;

    public TaskRunnerConfig() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }

    public String getTaskDesc() {
        return taskDesc;
    }

    public void setTaskDesc(String taskDesc) {
        this.taskDesc = taskDesc;
    }

    public String getTaskClass() {
        return taskClass;
    }

    public void setTaskClass(String taskClass) {
        this.taskClass = taskClass;
    }

    public String getTaskTag() {
        return taskTag;
    }

    public void setTaskTag(String taskTag) {
        this.taskTag = taskTag;
    }

    public int getConsumerNum() {
        return consumerNum;
    }

    public void setConsumerNum(int consumerNum) {
        this.consumerNum = consumerNum;
    }

    public int getPrefetchNum() {
        return prefetchNum;
    }

    public void setPrefetchNum(int prefetchNum) {
        this.prefetchNum = prefetchNum;
    }

    public int getRateLimitType() {
        return rateLimitType;
    }

    public void setRateLimitType(int rateLimitType) {
        this.rateLimitType = rateLimitType;
    }

    public int getRateLimitValue() {
        return rateLimitValue;
    }

    public void setRateLimitValue(int rateLimitValue) {
        this.rateLimitValue = rateLimitValue;
    }

    public int getRateLimitTime() {
        return rateLimitTime;
    }

    public void setRateLimitTime(int rateLimitTime) {
        this.rateLimitTime = rateLimitTime;
    }

    public int getRateLimitWait() {
        return rateLimitWait;
    }

    public void setRateLimitWait(int rateLimitWait) {
        this.rateLimitWait = rateLimitWait;
    }

    public int getRetryTimesByOverrated() {
        return retryTimesByOverrated;
    }

    public void setRetryTimesByOverrated(int retryTimesByOverrated) {
        this.retryTimesByOverrated = retryTimesByOverrated;
    }

    public int getRetryTimesByPartner() {
        return retryTimesByPartner;
    }

    public void setRetryTimesByPartner(int retryTimesByPartner) {
        this.retryTimesByPartner = retryTimesByPartner;
    }

    public String getRunTarget() {
        return runTarget;
    }

    public void setRunTarget(String runTarget) {
        this.runTarget = runTarget;
    }

    public int getFailRate() {
        return failRate;
    }

    public void setFailRate(int failRate) {
        this.failRate = failRate;
    }

    public int getFailPartnerRate() {
        return failPartnerRate;
    }

    public void setFailPartnerRate(int failPartnerRate) {
        this.failPartnerRate = failPartnerRate;
    }

    public int getFailProgramRate() {
        return failProgramRate;
    }

    public void setFailProgramRate(int failProgramRate) {
        this.failProgramRate = failProgramRate;
    }

    public int getFailConfigRate() {
        return failConfigRate;
    }

    public void setFailConfigRate(int failConfigRate) {
        this.failConfigRate = failConfigRate;
    }

    public int getFailDataRate() {
        return failDataRate;
    }

    public void setFailDataRate(int failDataRate) {
        this.failDataRate = failDataRate;
    }

    public int getQueueTimeout() {
        return queueTimeout;
    }

    public void setQueueTimeout(int queueTimeout) {
        this.queueTimeout = queueTimeout;
    }

    public int getWaitTimeout() {
        return waitTimeout;
    }

    public void setWaitTimeout(int waitTimeout) {
        this.waitTimeout = waitTimeout;
    }

    public int getRunTimeout() {
        return runTimeout;
    }

    public void setRunTimeout(int runTimeout) {
        this.runTimeout = runTimeout;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public Date getModifyDate() {
        return modifyDate;
    }

    public void setModifyDate(Date modifyDate) {
        this.modifyDate = modifyDate;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public int getLogLevel() {
        return logLevel;
    }

    public void setLogLevel(int logLevel) {
        this.logLevel = logLevel;
    }

    public int getLogLimitSize() {
        return logLimitSize;
    }

    public void setLogLimitSize(int logLimitSize) {
        this.logLimitSize = logLimitSize;
    }
}
src/main/java/uw/task/util/MiscUtils.java
public class MiscUtils {

    /**
     * taskData的copy器。
     */
    private static BeanCopier beanCopier = BeanCopier.create(TaskData.class, TaskData.class, false);

    /**
     * copy taskData对象。
     *
     * @param srcData
     * @param dstData
     */
    public static void copyTaskData(TaskData srcData, TaskData dstData) {
        beanCopier.copy(srcData, dstData, null);
    }

    /**
     * 打印异常信息，屏蔽掉spring自己的堆栈输出。
     *
     * @param e 需要打印的异常信息
     * @return
     */
    public static String exceptionToString(Throwable e) {
        StringBuilder sb = new StringBuilder();
        sb.append(e.toString()).append("\n");

        StackTraceElement[] trace = e.getStackTrace();
        for (StackTraceElement traceElement : trace) {
            if (traceElement.getClassName().startsWith("org.spring")) {
                continue;
            }
            if (traceElement.getClassName().startsWith("sun.")) {
                continue;
            }
            sb.append("\tat ").append(traceElement).append("\n");
        }
        Throwable ourCause = e.getCause();
        if (ourCause != null) {
            sb.append("CAUSE BY").append(ourCause.toString()).append("\n");
            trace = ourCause.getStackTrace();
            for (StackTraceElement traceElement : trace) {
                if (traceElement.getClassName().startsWith("org.spring")) {
                    continue;
                }
                if (traceElement.getClassName().startsWith("sun.")) {
                    continue;
                }
                sb.append("\tat ").append(traceElement).append("\n");
            }
        }
        return sb.toString();
    }

}
src/main/java/uw/task/TaskListenerManager.java
public class TaskListenerManager {

	/**
	 * runner监听器列表。
	 */
    private ArrayList<RunnerTaskListener> runnerListenerList = new ArrayList<>();

    /**
     * croner监听器列表。
     */
    private ArrayList<CronerTaskListener> cronerListenerList = new ArrayList<>();

    /**
     * 加入一个RunnerListener。
     *
     * @param listener
     */
    public void addRunnerListener(RunnerTaskListener listener) {
        runnerListenerList.add(listener);
    }

    /**
     * 加入一个RunnerListener.
     *
     * @param listener
     */
    public void addCronerListener(CronerTaskListener listener) {
        cronerListenerList.add(listener);
    }

    /**
     * 清除RunnerListener列表
     */
    public void clearRunnerListener() {
        runnerListenerList.clear();
    }

    /**
     * 清除RunnerListener列表
     */
    public void clearCronerListener() {
        cronerListenerList.clear();
    }

    /**
     * 获得Runner Listener列表。
     *
     * @return
     */
    public ArrayList<RunnerTaskListener> getRunnerListenerList() {
        return runnerListenerList;
    }

    /**
     * 获得Croner Listener列表。
     *
     * @return
     */
    public ArrayList<CronerTaskListener> getCronerListenerList() {
        return cronerListenerList;
    }

}
src/main/java/uw/task/entity/TaskRunnerLog.java
@JsonIgnoreProperties({"taskData"})
public class TaskRunnerLog extends LogBaseVo {

    private static final Logger logger = LoggerFactory.getLogger(TaskRunnerLog.class);

    private TaskData taskData;

    /**
     * logLimitSize。
     */
    private int logLimitSize;

    public TaskRunnerLog(TaskData taskData) {
        this.taskData = taskData;
    }

    public TaskData getTaskData() {
        return taskData;
    }

    /**
     * @return the id
     */
    public long getId() {
        return taskData.getId();
    }

    /**
     * @return the refId
     */
    public long getRefId() {
        return taskData.getRefId();
    }

    /**
     * @return the refSubId
     */
    public long getRefSubId() {
        return taskData.getRefSubId();
    }

    /**
     * @return the refTag
     */
    public String getRefTag() {
        return taskData.getRefTag();
    }

    /**
     * @return the rateLimitTag
     */
    public String getRateLimitTag() {
        return taskData.getRateLimitTag();
    }

    /**
     * @return the taskClass
     */
    public String getTaskClass() {
        return taskData.getTaskClass();
    }

    /**
     * @return the taskTag
     */
    public String getTaskTag() {
        return taskData.getTaskTag();
    }

    public long getTaskDelay() {
        return taskData.getTaskDelay();
    }

    /**
     * @return the taskParam
     */
    public String getTaskParam() {
        Object value = taskData.getTaskParam();
        if (value != null) {
            // 报错了
            if (taskData.getState() != TaskData.STATE_SUCCESS || logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_ALL ||
                    logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_TASK_PARAM) {
                String data = null;
                try {
                    data = JsonMapper.MAPPER.writeValueAsString(value);
                } catch (Exception e) {
                    data = e.getMessage();
                    logger.error(e.getMessage(), e);
                }
                if (data != null) {
                    if (logLimitSize > 0 && data.length() > logLimitSize) {
                        data = data.substring(0, logLimitSize);
                    }
                    return data;
                }
            }
        }
        return null;
    }

    /**
     * @return the runType
     */
    public int getRunType() {
        return taskData.getRunType();
    }

    /**
     * @return the retryType
     */
    public int getRetryType() {
        return taskData.getRetryType();
    }

    /**
     * @return the runTarget
     */
    public String getRunTarget() {
        return taskData.getRunTarget();
    }

    /**
     * @return the hostIp
     */
    public String getHostIp() {
        return taskData.getHostIp();
    }

    /**
     * @return the hostId
     */
    public String getHostId() {
        return taskData.getHostId();
    }

    /**
     * @return the queueDate
     */
    public Date getQueueDate() {
        return taskData.getQueueDate();
    }

    /**
     * @return the consumeDate
     */
    public Date getConsumeDate() {
        return taskData.getConsumeDate();
    }

    /**
     * @return the runDate
     */
    public Date getRunDate() {
        return taskData.getRunDate();
    }

    /**
     * @return the finishDate
     */
    public Date getFinishDate() {
        return taskData.getFinishDate();
    }

    /**
     * @return the resultData
     */
    public String getResultData() {
        Object value = taskData.getResultData();
        if (value != null) {
            // 报错了
            if (taskData.getState() != TaskData.STATE_SUCCESS || logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_ALL ||
                    logLevel == TaskRunnerConfig.TASK_LOG_TYPE_RECORD_RESULT_DATA) {
                String data = null;
                try {
                    data = JsonMapper.MAPPER.writeValueAsString(value);
                } catch (Exception e) {
                    data = e.getMessage();
                    logger.error(e.getMessage(), e);
                }
                if (data != null) {
                    if (logLimitSize > 0 && data.length() > logLimitSize) {
                        data = data.substring(0, logLimitSize);
                    }
                    return data;
                }
            }
        }
        return null;
    }

    /**
     * @return the errorInfo
     */
    public String getErrorInfo() {
        return taskData.getErrorInfo();
    }

    /**
     * @return the ranTimes
     */
    public int getRanTimes() {
        return taskData.getRanTimes();
    }

    /**
     * @return the status
     */
    public int getState() {
        return taskData.getState();
    }

    public int getLogLimitSize() {
        return logLimitSize;
    }

    public void setLogLimitSize(int logLimitSize) {
        this.logLimitSize = logLimitSize;
    }
}
src/main/java/uw/task/conf/TaskProperties.java
@ConfigurationProperties(prefix = "uw.task")
public class TaskProperties {

    /**
     * 是否启用uw-task服务注册和主机注册，默认不启用。
     *
     */
    private boolean enableTaskRegistry = false;
    /**
     * 任务名，必须设置为基础包名。
     */
    private String project;

    /**
     * 私有模式。不运行全局target任务。
     */
    private boolean privacyMode = false;

    /**
     * croner线程数，默认在3个，建议按照实际croner任务数量*70%。
     */
    private int cronerThreadNum = 5;

    /**
     * RPC最小线程数,用于执行RPC调用，如不使用rpc，建议设置为1，否则按照最大并发量*10%设置。
     */
    private int taskRpcMinThreadNum = 1;

    /**
     * RPC最大线程数,用于执行RPC调用，超过此线程数，将会导致阻塞。
     */
    private int taskRpcMaxThreadNum = 100;

    /**
     * 队列任务重试延时毫秒数，默认2秒
     */
    private long taskQueueRetryDelay = 2000;

    /**
     *  rpc任务重试延时毫秒数，默认100毫秒
     */
    private long taskRpcRetryDelay = 100;

    /**
     * 运行主机ID
     */
    private String hostId = ManagementFactory.getRuntimeMXBean().getName();

    /**
     * 任务服务器
     */
    private String taskCenterHost = "127.0.0.1";

    /**
     * Redis配置
     */
    private RedisProperties redis = new RedisProperties();

    /**
     * Rabbit MQ配置
     */
    private RabbitProperties rabbitmq = new RabbitProperties();

    public static class RedisProperties extends org.springframework.boot.autoconfigure.data.redis.RedisProperties {

    }

    public static class RabbitProperties extends org.springframework.boot.autoconfigure.amqp.RabbitProperties {

    }

    public boolean isEnableTaskRegistry() {
        return enableTaskRegistry;
    }

    public void setEnableTaskRegistry(boolean enableTaskRegistry) {
        this.enableTaskRegistry = enableTaskRegistry;
    }

    /**
	 * @return the privacyMode
	 */
	public boolean isPrivacyMode() {
		return privacyMode;
	}

	/**
	 * @param privacyMode the privacyMode to set
	 */
	public void setPrivacyMode(boolean privacyMode) {
		this.privacyMode = privacyMode;
	}

	public int getTaskRpcMinThreadNum() {
		return taskRpcMinThreadNum;
	}

	public void setTaskRpcMinThreadNum(int taskRpcMinThreadNum) {
		this.taskRpcMinThreadNum = taskRpcMinThreadNum;
	}

	public int getTaskRpcMaxThreadNum() {
		return taskRpcMaxThreadNum;
	}

	public void setTaskRpcMaxThreadNum(int taskRpcMaxThreadNum) {
		this.taskRpcMaxThreadNum = taskRpcMaxThreadNum;
	}

	/**
     * @return the project
     */
    public String getProject() {
        return project;
    }

    /**
     * @param project the project to set
     */
    public void setProject(String project) {
        this.project = project;
    }

    /**
     * @return the hostId
     */
    public String getHostId() {
        return hostId;
    }

    /**
     * @param hostId the hostId to set
     */
    public void setHostId(String hostId) {
        this.hostId = hostId;
    }

    /**
	 * @return the cronerThreadNum
	 */
	public int getCronerThreadNum() {
		return cronerThreadNum;
	}

	/**
	 * @param cronerThreadNum the cronerThreadNum to set
	 */
	public void setCronerThreadNum(int cronerThreadNum) {
		this.cronerThreadNum = cronerThreadNum;
	}

	/**
     * @return the taskCenterHost
     */
    public String getTaskCenterHost() {
        return taskCenterHost;
    }

    /**
     * @param taskCenterHost the taskCenterHost to set
     */
    public void setTaskCenterHost(String taskCenterHost) {
        this.taskCenterHost = taskCenterHost;
    }

    public RedisProperties getRedis() {
        return redis;
    }

    public void setRedis(RedisProperties redis) {
        this.redis = redis;
    }

    public RabbitProperties getRabbitmq() {
        return rabbitmq;
    }

    public void setRabbitmq(RabbitProperties rabbitmq) {
        this.rabbitmq = rabbitmq;
    }

    public long getTaskQueueRetryDelay() {
        return taskQueueRetryDelay;
    }

    public void setTaskQueueRetryDelay(long taskQueueRetryDelay) {
        this.taskQueueRetryDelay = taskQueueRetryDelay;
    }

    public long getTaskRpcRetryDelay() {
        return taskRpcRetryDelay;
    }

    public void setTaskRpcRetryDelay(long taskRpcRetryDelay) {
        this.taskRpcRetryDelay = taskRpcRetryDelay;
    }
}
package uw.task.container;
import java.util.ArrayList;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uw.task.TaskData;
import uw.task.TaskFactory;
import uw.task.TaskListenerManager;
import uw.task.TaskRunner;
import uw.task.api.TaskAPI;
import uw.task.conf.TaskMetaInfoManager;
import uw.task.conf.TaskProperties;
import uw.task.entity.TaskRunnerConfig;
import uw.task.entity.TaskRunnerLog;
import uw.task.exception.TaskDataException;
import uw.task.exception.TaskPartnerException;
import uw.task.listener.RunnerTaskListener;
import uw.task.util.GlobalRateLimiter;
import uw.task.util.LocalRateLimiter;
import uw.task.util.MiscUtils;

/**
 * 在此处接受MQ信息，并进行处理。
 *
 * @author axeon
 */
public class TaskRunnerContainer {

    private static final Logger log = LoggerFactory.getLogger(TaskRunnerContainer.class);

    /**
     * TaskFactory
     */
    private TaskFactory taskFactory;

    /**
     * 服务端任务API
     */
    private TaskAPI taskAPI;

    /**
     * 全局流量限制服务
     */
    private GlobalRateLimiter globalRateLimiter;

    /**
     * 本地流量限制服务
     */Next line of code: