—-USING CODEX—
pip install openai
import openai
# Set up your OpenAI API key
openai.api_key = 'your-api-key-here'
# Define a prompt for Codex
prompt = "Write a Python function to calculate the factorial of a number."
# Make a request to Codex
response = openai.ChatCompletion.create(
model="code-davinci-002", # or another Codex model
messages=[
{"role": "user", "content": prompt}
],
max_tokens=150
)
# Print the generated code
generated_code = response['choices'][0]['message']['content']
print(generated_code)
# or
import openai
openai.api_key = 'your-api-key'
response = openai.Completion.create(
engine="code-davinci-002", # Codex engine
prompt="Write a Python function to calculate the factorial of a number.",
max_tokens=100,
temperature=0.5
)
print(response.choices[0].text.strip())
Set Up Environment
Using the OpenAI API: 1. Get Key
pip install openai
GitHub Copilot Setup: 1. I can install GitHub
Copilot directly in Visual Studio Code. 2. After logging in with my
GitHub account, I’ll configure Copilot to assist as I code.
Making API Calls to Codex
Here’s how I can interact with Codex through API calls:
import openai
# Set up OpenAI API key
openai.api_key = 'your-api-key'
# Define my prompt for Codex
prompt = "Write a Python function to calculate the factorial of a number."
# Make a request to Codex
response = openai.Completion.create(
engine="code-davinci-002", # Codex engine
prompt=prompt,
max_tokens=100,
temperature=0.5
)
# Print the generated code
print(response.choices[0].text.strip())
Key Parameters: - Prompt: Describes
the task or question I have. - Max Tokens: Limits the
response length. - Temperature: Controls output
randomness (lower values yield more deterministic code).
Using GitHub Copilot in My IDE
With Copilot in Visual Studio Code: 1. I start typing code or add
comments, and Copilot suggests completions. 2. To accept, I press
Tab
. I can also explore alternatives with
Ctrl + ]
. 3. Writing clear comments in natural language
helps Copilot understand what I’m trying to achieve.
Experimenting with Prompts
Prompt engineering can help me get the most from Codex. I can ask
Codex to: - Generate entire functions or classes. - Explain code
snippets. - Debug existing code by providing some context.
Fine-Tuning for Specialized Tasks
If needed, I can fine-tune Codex on specific data (when accessible)
for more tailored code generation.
Best Practices
- Iterate on Prompts: Rephrasing prompts or adding
context improves Codex’s output.
- Review and Test: I always review generated code to
ensure it’s correct and secure.
- Use in Combination: Codex can supplement my coding
but isn’t a replacement; I’ll combine it with my own expertise.
1. Defining My Objectives
- Purpose: I’ll determine the specific task I want my
BERT model to perform (e.g., text classification, named entity
recognition, question answering).
- Dataset: I’ll select the appropriate dataset for
training and evaluating my model.
2. Data Collection and Preprocessing
- Dataset: I’ll gather a large text corpus relevant
to my chosen task. Potential sources include Wikipedia, BookCorpus, or a
domain-specific dataset.
- Preprocessing:
- Tokenization: I’ll use a BERT-compatible tokenizer,
likely from the Hugging Face Transformers library, to break down the
text into tokens.
- Input Formatting: I’ll format the input data as
required by BERT, including Input IDs, Attention Masks, and Token Type
IDs.
3. Choosing a Framework
- Libraries: I’ll use either Hugging Face
Transformers or TensorFlow to implement BERT, leaning towards Hugging
Face for its ease of use with pre-trained models.
4. Model Architecture
- Pre-trained BERT: I’ll likely start with a
pre-trained BERT model and fine-tune it for my task to save time and
resources.
- Loading Pre-trained Model: I’ll use code like this
to load the pre-trained model and tokenizer:
from transformers import BertTokenizer, BertForSequenceClassification
import torch
# Load pre-trained BERT tokenizer and model
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2) # I'll adjust num_labels as needed
5. Training the Model
- Training Loop: I’ll set up a training loop to
fine-tune the model using my prepared dataset. This will involve
selecting an optimizer (e.g., AdamW) and a loss function (e.g.,
CrossEntropyLoss).
- Example Training Code: I’ll adapt the following
code:
from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir='./results',
num_train_epochs=3,
per_device_train_batch_size=16,
per_device_eval_batch_size=64,
warmup_steps=500,
weight_decay=0.01,
logging_dir='./logs',
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset, # My training dataset
eval_dataset=eval_dataset, # My evaluation dataset
)
trainer.train()
6. Evaluation
- Metrics: I’ll choose appropriate metrics (e.g.,
accuracy, F1 score) to evaluate the model’s performance on my task.
- Testing: I’ll test the model on a held-out test set
to get an unbiased assessment of its performance.
7. Deployment
- Model Saving: I’ll save the trained model and
tokenizer for later use:
model.save_pretrained('./my_bert_model')
tokenizer.save_pretrained('./my_bert_model')
- Inference: I’ll load the saved model to make
predictions on new, unseen data.
8. Continuous Improvement
- Fine-tuning: I’ll continue to fine-tune the model
with more data or adjust hyperparameters as needed to improve
performance.
- Feedback Loop: I’ll incorporate user feedback to
iteratively refine the model.
Use pre-trained models and the Hugging Face Transformers library to
help streamline. See my doc on Hugging Face on my io wesbite.
JTML
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmVkaXRvcl9vcHRpb25zOiANCiAgbWFya2Rvd246IA0KICAgIHdyYXA6IDcyDQotLS0NCg0KLS0tLVVTSU5HIENPREVYLS0tDQoNCmBgYHtweXRob259DQpwaXAgaW5zdGFsbCBvcGVuYWkNCg0KaW1wb3J0IG9wZW5haSAgDQoNCiMgU2V0IHVwIHlvdXIgT3BlbkFJIEFQSSBrZXkgIA0Kb3BlbmFpLmFwaV9rZXkgPSAneW91ci1hcGkta2V5LWhlcmUnICANCg0KIyBEZWZpbmUgYSBwcm9tcHQgZm9yIENvZGV4ICANCnByb21wdCA9ICJXcml0ZSBhIFB5dGhvbiBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGZhY3RvcmlhbCBvZiBhIG51bWJlci4iICANCg0KIyBNYWtlIGEgcmVxdWVzdCB0byBDb2RleCAgDQpyZXNwb25zZSA9IG9wZW5haS5DaGF0Q29tcGxldGlvbi5jcmVhdGUoICANCiAgICBtb2RlbD0iY29kZS1kYXZpbmNpLTAwMiIsICAjIG9yIGFub3RoZXIgQ29kZXggbW9kZWwgIA0KICAgIG1lc3NhZ2VzPVsgIA0KICAgICAgICB7InJvbGUiOiAidXNlciIsICJjb250ZW50IjogcHJvbXB0fSAgDQogICAgXSwgIA0KICAgIG1heF90b2tlbnM9MTUwICANCikgIA0KDQojIFByaW50IHRoZSBnZW5lcmF0ZWQgY29kZSAgDQpnZW5lcmF0ZWRfY29kZSA9IHJlc3BvbnNlWydjaG9pY2VzJ11bMF1bJ21lc3NhZ2UnXVsnY29udGVudCddICANCnByaW50KGdlbmVyYXRlZF9jb2RlKQ0KDQojIG9yDQoNCmltcG9ydCBvcGVuYWkgIA0KDQpvcGVuYWkuYXBpX2tleSA9ICd5b3VyLWFwaS1rZXknICANCg0KcmVzcG9uc2UgPSBvcGVuYWkuQ29tcGxldGlvbi5jcmVhdGUoICANCiAgZW5naW5lPSJjb2RlLWRhdmluY2ktMDAyIiwgICMgQ29kZXggZW5naW5lICANCiAgcHJvbXB0PSJXcml0ZSBhIFB5dGhvbiBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGZhY3RvcmlhbCBvZiBhIG51bWJlci4iLCAgDQogIG1heF90b2tlbnM9MTAwLCAgDQogIHRlbXBlcmF0dXJlPTAuNSAgDQopICANCg0KcHJpbnQocmVzcG9uc2UuY2hvaWNlc1swXS50ZXh0LnN0cmlwKCkpDQoNCmBgYA0KDQojIyMgU2V0IFVwIEVudmlyb25tZW50DQoNCioqVXNpbmcgdGhlIE9wZW5BSSBBUEkqKjogMS4gR2V0IEtleQ0KDQpgYGAgYmFzaA0KcGlwIGluc3RhbGwgb3BlbmFpDQpgYGANCg0KKipHaXRIdWIgQ29waWxvdCBTZXR1cCoqOiAxLiBJIGNhbiBpbnN0YWxsIEdpdEh1YiBDb3BpbG90IGRpcmVjdGx5IGluDQpWaXN1YWwgU3R1ZGlvIENvZGUuIDIuIEFmdGVyIGxvZ2dpbmcgaW4gd2l0aCBteSBHaXRIdWIgYWNjb3VudCwgSeKAmWxsDQpjb25maWd1cmUgQ29waWxvdCB0byBhc3Npc3QgYXMgSSBjb2RlLg0KDQojIyMgTWFraW5nIEFQSSBDYWxscyB0byBDb2RleA0KDQpIZXJl4oCZcyBob3cgSSBjYW4gaW50ZXJhY3Qgd2l0aCBDb2RleCB0aHJvdWdoIEFQSSBjYWxsczoNCg0KYGBgIHB5dGhvbg0KaW1wb3J0IG9wZW5haQ0KDQojIFNldCB1cCBPcGVuQUkgQVBJIGtleQ0Kb3BlbmFpLmFwaV9rZXkgPSAneW91ci1hcGkta2V5Jw0KDQojIERlZmluZSBteSBwcm9tcHQgZm9yIENvZGV4DQpwcm9tcHQgPSAiV3JpdGUgYSBQeXRob24gZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBmYWN0b3JpYWwgb2YgYSBudW1iZXIuIg0KDQojIE1ha2UgYSByZXF1ZXN0IHRvIENvZGV4DQpyZXNwb25zZSA9IG9wZW5haS5Db21wbGV0aW9uLmNyZWF0ZSgNCiAgICBlbmdpbmU9ImNvZGUtZGF2aW5jaS0wMDIiLCAgIyBDb2RleCBlbmdpbmUNCiAgICBwcm9tcHQ9cHJvbXB0LA0KICAgIG1heF90b2tlbnM9MTAwLA0KICAgIHRlbXBlcmF0dXJlPTAuNQ0KKQ0KDQojIFByaW50IHRoZSBnZW5lcmF0ZWQgY29kZQ0KcHJpbnQocmVzcG9uc2UuY2hvaWNlc1swXS50ZXh0LnN0cmlwKCkpDQpgYGANCg0KKipLZXkgUGFyYW1ldGVycyoqOiAtICoqUHJvbXB0Kio6IERlc2NyaWJlcyB0aGUgdGFzayBvciBxdWVzdGlvbiBJDQpoYXZlLiAtICoqTWF4IFRva2VucyoqOiBMaW1pdHMgdGhlIHJlc3BvbnNlIGxlbmd0aC4gLSAqKlRlbXBlcmF0dXJlKio6DQpDb250cm9scyBvdXRwdXQgcmFuZG9tbmVzcyAobG93ZXIgdmFsdWVzIHlpZWxkIG1vcmUgZGV0ZXJtaW5pc3RpYyBjb2RlKS4NCg0KIyMjIFVzaW5nIEdpdEh1YiBDb3BpbG90IGluIE15IElERQ0KDQpXaXRoIENvcGlsb3QgaW4gVmlzdWFsIFN0dWRpbyBDb2RlOiAxLiBJIHN0YXJ0IHR5cGluZyBjb2RlIG9yIGFkZA0KY29tbWVudHMsIGFuZCBDb3BpbG90IHN1Z2dlc3RzIGNvbXBsZXRpb25zLiAyLiBUbyBhY2NlcHQsIEkgcHJlc3MgYFRhYmAuDQpJIGNhbiBhbHNvIGV4cGxvcmUgYWx0ZXJuYXRpdmVzIHdpdGggYEN0cmwgKyBdYC4gMy4gV3JpdGluZyBjbGVhcg0KY29tbWVudHMgaW4gbmF0dXJhbCBsYW5ndWFnZSBoZWxwcyBDb3BpbG90IHVuZGVyc3RhbmQgd2hhdCBJ4oCZbSB0cnlpbmcgdG8NCmFjaGlldmUuDQoNCiMjIyBFeHBlcmltZW50aW5nIHdpdGggUHJvbXB0cw0KDQpQcm9tcHQgZW5naW5lZXJpbmcgY2FuIGhlbHAgbWUgZ2V0IHRoZSBtb3N0IGZyb20gQ29kZXguIEkgY2FuIGFzayBDb2RleA0KdG86IC0gR2VuZXJhdGUgZW50aXJlIGZ1bmN0aW9ucyBvciBjbGFzc2VzLiAtIEV4cGxhaW4gY29kZSBzbmlwcGV0cy4gLQ0KRGVidWcgZXhpc3RpbmcgY29kZSBieSBwcm92aWRpbmcgc29tZSBjb250ZXh0Lg0KDQojIyMgRmluZS1UdW5pbmcgZm9yIFNwZWNpYWxpemVkIFRhc2tzDQoNCklmIG5lZWRlZCwgSSBjYW4gZmluZS10dW5lIENvZGV4IG9uIHNwZWNpZmljIGRhdGEgKHdoZW4gYWNjZXNzaWJsZSkgZm9yDQptb3JlIHRhaWxvcmVkIGNvZGUgZ2VuZXJhdGlvbi4NCg0KIyMjIEJlc3QgUHJhY3RpY2VzDQoNCi0gICAqKkl0ZXJhdGUgb24gUHJvbXB0cyoqOiBSZXBocmFzaW5nIHByb21wdHMgb3IgYWRkaW5nIGNvbnRleHQNCiAgICBpbXByb3ZlcyBDb2RleOKAmXMgb3V0cHV0Lg0KLSAgICoqUmV2aWV3IGFuZCBUZXN0Kio6IEkgYWx3YXlzIHJldmlldyBnZW5lcmF0ZWQgY29kZSB0byBlbnN1cmUgaXTigJlzDQogICAgY29ycmVjdCBhbmQgc2VjdXJlLg0KLSAgICoqVXNlIGluIENvbWJpbmF0aW9uKio6IENvZGV4IGNhbiBzdXBwbGVtZW50IG15IGNvZGluZyBidXQgaXNu4oCZdCBhDQogICAgcmVwbGFjZW1lbnQ7IEnigJlsbCBjb21iaW5lIGl0IHdpdGggbXkgb3duIGV4cGVydGlzZS4NCg0KIyMjIC0tRXhhbWluZSBjb2RlIGZyb20gY29kZXggdXNpbmcgZGV2IHRvb2xzIGFuZCByZXZlcnNlIGVuZ2luZWVyaW5nIHRvIHNlZSBob3cgbWVjaGFuaXNtIHdvcmtzDQoNCi0tSW5pdGlhbCBTdGVwcyB0byBjcmVhdGUgYSBiZXJ0ICJKYmVydCIgdGhhdCBoYXMgYWNjdXJhY3kgb2YgYmVydCB3aXRoDQpDYXN1YWwgTG5hZ3VhZ2UgTW9kZWxpbmcgYW5kIFRleHQgR2VuZXJhdGluZyAoYnV0IGJldHRlcikgYXMgYSBHcHQuDQoNClRvIGJ1aWxkIG15IG93biBCRVJUIG1vZGVsLCBJJ2xsIGZvbGxvdyB0aGVzZSBzdGVwczoNCg0KIyMjIDEuIERlZmluaW5nIE15IE9iamVjdGl2ZXMNCg0KLSAgICoqUHVycG9zZSoqOiBJJ2xsIGRldGVybWluZSB0aGUgc3BlY2lmaWMgdGFzayBJIHdhbnQgbXkgQkVSVCBtb2RlbA0KICAgIHRvIHBlcmZvcm0gKGUuZy4sIHRleHQgY2xhc3NpZmljYXRpb24sIG5hbWVkIGVudGl0eSByZWNvZ25pdGlvbiwNCiAgICBxdWVzdGlvbiBhbnN3ZXJpbmcpLg0KLSAgICoqRGF0YXNldCoqOiBJJ2xsIHNlbGVjdCB0aGUgYXBwcm9wcmlhdGUgZGF0YXNldCBmb3IgdHJhaW5pbmcgYW5kDQogICAgZXZhbHVhdGluZyBteSBtb2RlbC4NCg0KIyMjIDIuIERhdGEgQ29sbGVjdGlvbiBhbmQgUHJlcHJvY2Vzc2luZw0KDQotICAgKipEYXRhc2V0Kio6IEknbGwgZ2F0aGVyIGEgbGFyZ2UgdGV4dCBjb3JwdXMgcmVsZXZhbnQgdG8gbXkgY2hvc2VuDQogICAgdGFzay4gUG90ZW50aWFsIHNvdXJjZXMgaW5jbHVkZSBXaWtpcGVkaWEsIEJvb2tDb3JwdXMsIG9yIGENCiAgICBkb21haW4tc3BlY2lmaWMgZGF0YXNldC4NCi0gICAqKlByZXByb2Nlc3NpbmcqKjoNCiAgICAtICAgKipUb2tlbml6YXRpb24qKjogSSdsbCB1c2UgYSBCRVJULWNvbXBhdGlibGUgdG9rZW5pemVyLCBsaWtlbHkNCiAgICAgICAgZnJvbSB0aGUgSHVnZ2luZyBGYWNlIFRyYW5zZm9ybWVycyBsaWJyYXJ5LCB0byBicmVhayBkb3duIHRoZQ0KICAgICAgICB0ZXh0IGludG8gdG9rZW5zLg0KICAgIC0gICAqKklucHV0IEZvcm1hdHRpbmcqKjogSSdsbCBmb3JtYXQgdGhlIGlucHV0IGRhdGEgYXMgcmVxdWlyZWQgYnkNCiAgICAgICAgQkVSVCwgaW5jbHVkaW5nIElucHV0IElEcywgQXR0ZW50aW9uIE1hc2tzLCBhbmQgVG9rZW4gVHlwZSBJRHMuDQoNCiMjIyAzLiBDaG9vc2luZyBhIEZyYW1ld29yaw0KDQotICAgKipMaWJyYXJpZXMqKjogSSdsbCB1c2UgZWl0aGVyIEh1Z2dpbmcgRmFjZSBUcmFuc2Zvcm1lcnMgb3INCiAgICBUZW5zb3JGbG93IHRvIGltcGxlbWVudCBCRVJULCBsZWFuaW5nIHRvd2FyZHMgSHVnZ2luZyBGYWNlIGZvciBpdHMNCiAgICBlYXNlIG9mIHVzZSB3aXRoIHByZS10cmFpbmVkIG1vZGVscy4NCg0KIyMjIDQuIE1vZGVsIEFyY2hpdGVjdHVyZQ0KDQotICAgKipQcmUtdHJhaW5lZCBCRVJUKio6IEknbGwgbGlrZWx5IHN0YXJ0IHdpdGggYSBwcmUtdHJhaW5lZCBCRVJUDQogICAgbW9kZWwgYW5kIGZpbmUtdHVuZSBpdCBmb3IgbXkgdGFzayB0byBzYXZlIHRpbWUgYW5kIHJlc291cmNlcy4NCi0gICAqKkxvYWRpbmcgUHJlLXRyYWluZWQgTW9kZWwqKjogSSdsbCB1c2UgY29kZSBsaWtlIHRoaXMgdG8gbG9hZCB0aGUNCiAgICBwcmUtdHJhaW5lZCBtb2RlbCBhbmQgdG9rZW5pemVyOg0KDQpgYGAgcHl0aG9uDQpmcm9tIHRyYW5zZm9ybWVycyBpbXBvcnQgQmVydFRva2VuaXplciwgQmVydEZvclNlcXVlbmNlQ2xhc3NpZmljYXRpb24NCmltcG9ydCB0b3JjaA0KDQojIExvYWQgcHJlLXRyYWluZWQgQkVSVCB0b2tlbml6ZXIgYW5kIG1vZGVsDQp0b2tlbml6ZXIgPSBCZXJ0VG9rZW5pemVyLmZyb21fcHJldHJhaW5lZCgnYmVydC1iYXNlLXVuY2FzZWQnKQ0KbW9kZWwgPSBCZXJ0Rm9yU2VxdWVuY2VDbGFzc2lmaWNhdGlvbi5mcm9tX3ByZXRyYWluZWQoJ2JlcnQtYmFzZS11bmNhc2VkJywgbnVtX2xhYmVscz0yKSAgIyBJJ2xsIGFkanVzdCBudW1fbGFiZWxzIGFzIG5lZWRlZA0KYGBgDQoNCiMjIyA1LiBUcmFpbmluZyB0aGUgTW9kZWwNCg0KLSAgICoqVHJhaW5pbmcgTG9vcCoqOiBJJ2xsIHNldCB1cCBhIHRyYWluaW5nIGxvb3AgdG8gZmluZS10dW5lIHRoZQ0KICAgIG1vZGVsIHVzaW5nIG15IHByZXBhcmVkIGRhdGFzZXQuIFRoaXMgd2lsbCBpbnZvbHZlIHNlbGVjdGluZyBhbg0KICAgIG9wdGltaXplciAoZS5nLiwgQWRhbVcpIGFuZCBhIGxvc3MgZnVuY3Rpb24gKGUuZy4sDQogICAgQ3Jvc3NFbnRyb3B5TG9zcykuDQotICAgKipFeGFtcGxlIFRyYWluaW5nIENvZGUqKjogSSdsbCBhZGFwdCB0aGUgZm9sbG93aW5nIGNvZGU6DQoNCmBgYCBweXRob24NCmZyb20gdHJhbnNmb3JtZXJzIGltcG9ydCBUcmFpbmVyLCBUcmFpbmluZ0FyZ3VtZW50cw0KDQp0cmFpbmluZ19hcmdzID0gVHJhaW5pbmdBcmd1bWVudHMoDQogICAgb3V0cHV0X2Rpcj0nLi9yZXN1bHRzJywNCiAgICBudW1fdHJhaW5fZXBvY2hzPTMsDQogICAgcGVyX2RldmljZV90cmFpbl9iYXRjaF9zaXplPTE2LA0KICAgIHBlcl9kZXZpY2VfZXZhbF9iYXRjaF9zaXplPTY0LA0KICAgIHdhcm11cF9zdGVwcz01MDAsDQogICAgd2VpZ2h0X2RlY2F5PTAuMDEsDQogICAgbG9nZ2luZ19kaXI9Jy4vbG9ncycsDQopDQoNCnRyYWluZXIgPSBUcmFpbmVyKA0KICAgIG1vZGVsPW1vZGVsLA0KICAgIGFyZ3M9dHJhaW5pbmdfYXJncywNCiAgICB0cmFpbl9kYXRhc2V0PXRyYWluX2RhdGFzZXQsICAjIE15IHRyYWluaW5nIGRhdGFzZXQNCiAgICBldmFsX2RhdGFzZXQ9ZXZhbF9kYXRhc2V0LCAgICAgIyBNeSBldmFsdWF0aW9uIGRhdGFzZXQNCikNCg0KdHJhaW5lci50cmFpbigpDQpgYGANCg0KIyMjIDYuIEV2YWx1YXRpb24NCg0KLSAgICoqTWV0cmljcyoqOiBJJ2xsIGNob29zZSBhcHByb3ByaWF0ZSBtZXRyaWNzIChlLmcuLCBhY2N1cmFjeSwgRjENCiAgICBzY29yZSkgdG8gZXZhbHVhdGUgdGhlIG1vZGVsJ3MgcGVyZm9ybWFuY2Ugb24gbXkgdGFzay4NCi0gICAqKlRlc3RpbmcqKjogSSdsbCB0ZXN0IHRoZSBtb2RlbCBvbiBhIGhlbGQtb3V0IHRlc3Qgc2V0IHRvIGdldCBhbg0KICAgIHVuYmlhc2VkIGFzc2Vzc21lbnQgb2YgaXRzIHBlcmZvcm1hbmNlLg0KDQojIyMgNy4gRGVwbG95bWVudA0KDQotICAgKipNb2RlbCBTYXZpbmcqKjogSSdsbCBzYXZlIHRoZSB0cmFpbmVkIG1vZGVsIGFuZCB0b2tlbml6ZXIgZm9yDQogICAgbGF0ZXIgdXNlOg0KDQpgYGAgcHl0aG9uDQptb2RlbC5zYXZlX3ByZXRyYWluZWQoJy4vbXlfYmVydF9tb2RlbCcpDQp0b2tlbml6ZXIuc2F2ZV9wcmV0cmFpbmVkKCcuL215X2JlcnRfbW9kZWwnKQ0KYGBgDQoNCi0gICAqKkluZmVyZW5jZSoqOiBJJ2xsIGxvYWQgdGhlIHNhdmVkIG1vZGVsIHRvIG1ha2UgcHJlZGljdGlvbnMgb24gbmV3LA0KICAgIHVuc2VlbiBkYXRhLg0KDQojIyMgOC4gQ29udGludW91cyBJbXByb3ZlbWVudA0KDQotICAgKipGaW5lLXR1bmluZyoqOiBJJ2xsIGNvbnRpbnVlIHRvIGZpbmUtdHVuZSB0aGUgbW9kZWwgd2l0aCBtb3JlIGRhdGENCiAgICBvciBhZGp1c3QgaHlwZXJwYXJhbWV0ZXJzIGFzIG5lZWRlZCB0byBpbXByb3ZlIHBlcmZvcm1hbmNlLg0KLSAgICoqRmVlZGJhY2sgTG9vcCoqOiBJJ2xsIGluY29ycG9yYXRlIHVzZXIgZmVlZGJhY2sgdG8gaXRlcmF0aXZlbHkNCiAgICByZWZpbmUgdGhlIG1vZGVsLg0KDQpVc2UgcHJlLXRyYWluZWQgbW9kZWxzIGFuZCB0aGUgSHVnZ2luZyBGYWNlIFRyYW5zZm9ybWVycyBsaWJyYXJ5IHRvIGhlbHANCnN0cmVhbWxpbmUuIFNlZSBteSBkb2Mgb24gSHVnZ2luZyBGYWNlIG9uIG15IGlvIHdlc2JpdGUuDQoNCltKVE1MXShodHRwczovL2NoYXRncHQuY29tL2cvZy1oWjhQZ2FhQTItamVzc2kvYy82NzJjMmNlMi03M2E0LTgwMGQtYjMzYy03ZjljYWY4MzYyMzgpDQo=