Articles

5.1: Introduction to functions


5.1: Introduction to functions

Lesson 5.1: Introduction to Serverless Architecture in Azure

In the last few years, the concept of serverless computing has become much more prominent, but what does that actually mean? There are clearly servers in the cloud running code to implement our web application or service. But with serverless cloud implementations, we free developers from infrastructure management and allow the cloud providers to manage and scale the service depending on its traffic.

In an article on MartinFowler.com, they provide this definition:

Serverless architectures are application designs that incorporate third-party “Backend as a Service” (BaaS) services, and/or that include custom code run in managed, ephemeral containers on a “Functions as a Service” (FaaS) platform. By using these ideas, and related ones like single-page applications, such architectures remove much of the need for a traditional always-on server component. Serverless architectures may benefit from significantly reduced operational cost, complexity, and engineering lead time, at a cost of increased reliance on vendor dependencies and comparatively immature supporting services.

In Azure, the term serverless has two distinct but related meanings:

  • Backend as a service (BaaS). Back-end cloud services, such as databases and storage, provide APIs that enable client applications to connect directly to these services. But they do not need to manage the configuration or running of those systems.
  • Functions as a service (FaaS). In this model, a “function” is a piece of code that is deployed to the cloud and runs inside a hosting environment that completely abstracts the servers that run the code.

Both definitions have in common the idea that developers and DevOps personnel don’t need to deploy, configure, manage, or scale servers on a regular basis. Some additional important characteristics are:

  1. Compute resources are allocated dynamically as needed by the platform.
  2. Consumption-based pricing: You are charged only for the compute resources used to execute your code.
  3. The compute resources scale on demand based on traffic, without the developer needing to do any configuration.

The cost benefits of this serverless architecture is that we only pay for resources that we use. We do not reserve servers (in the form of IaaS virtual machines) or capacity (like in Cloud Service AppPlans) based on what we estimate we will need.

In server-based architectures, developers need to be very aware of the server infrastructure and need to plan and manage scaling of those servers. By requiring a minimum capacity, there are cycles wasted when all of the resources aren’t being used. As a matter of fact, may developers plan for higher capacity than they actually have to give room for growth, so they are spending more than is required for their Azure hosting costs. However, IaaS and PaaS are more familiar programming models for most developers.

For our game client, the Blazor and game logic actually runs on the client so it’s using the device’s computing power. And Azure Functions charges for the time and memory required to process each request. So we never run into a case where we are wasting compute resources that we do not use.

This makes for a cost-effective deployment and management environment.


5.2 Python Function Syntax

Python functions are referred to by name (technically they are values like any other variable). As in many programming languages, we call a function by writing the name of the function followed immediately (no space) by parentheses () . Inside the parentheses, we put the arguments (inputs) to the function separated by commas. Thus computer functions look just like mathematical functions, but with names longer than f() .

  • Note: To keep functions and variables distinct, we try to always include empty parentheses () when referring to a function name. This does not mean that the function takes no arguments it is just a useful shorthand for indicating that something is a function rather than a variable.

Some functions (such as min() or print() ) can be passed as many arguments as you wish: min() will find the minimum of all the arguments, and print() will print all the arguments (in order), separated by spaces:

Besides ordered positional arguments, functions may also take keyword arguments, which are arguments for specific function inputs. These are written like variable assignments (using the = , though without spaces around it), but within the function parameter list:

Keyword arguments are always optional (they have “default” values, like how the separator for print() defaults to a single space ' ' ). The default values are specified in the function documentation (e.g., for print() ).

If you call any of these functions interactively (e.g., in an interactive shell or a Jupyter notebook), Python will display the returned value. However, the computer is not able to “read” what is written to the console or an output cell—that’s for humans to view! If we want the computer to be able to use a returned value, we will need to give that value a name so that the computer can refer to it. That is, we need to store the returned value in a variable:

5.2.1 Object Methods

In Python, all data values are objects, which are groups of data (called attributes) and behaviors—that is, information about the values and the functions that can be applied to that data. For example, a Person object may have a name (e.g., "Ada" ) and some behavior it can do to that data (e.g., say_name() ). Functions that are applied to an object’s data are also known as methods. We say that a method is called on that object.

While we’ll discuss objects in more much detail later, for now you just need to understand that some functions are called on particular values. This is done using dot notation: you write the name of the variable you wish to call the method on (i.e., apply the function to), followed by a period (dot) . , followed by the method name and arguments:

This is a common way of utilizing built-in Python functions.

  • Note that dot notation is also used to access the attributes or properties of an object. So if a Person object has a name attribute, you would refer to that as the_person.name . In this sense, you can think of the dot operator as being like the possessive 's in English: the_person.name refers so “ the_person ’s name”, and the_person.say_name() would refer to “ the_person ’s say_name() action”.

Mathematical Functions

MATLAB has all of the usual mathematical functions found on a scientific calculator including square root, logarithm, and sine.

returns the number 3.1416. To find the sine of pi, type in

The arguments in trigonometric functions are in radians. Multiply degrees by pi/180 to get radians. For example, to calculate sin(90), type in

returns the natural logarithm of the value. To find the ln of 10, type in log(10) and press enter, (ans = 2.3026).

Practice the following examples to familiarize yourself with the common mathematical functions. Be sure to read the relevant help and doc pages for functions that are not self explanatory.

Calculate the following quantities:

MATLAB inputs and outputs are as follows:

1. (frac<2^<3>><3^<2>-1>) is entered by typing 2^3/(3^2-1) (ans = 1)

2. (5^<0.5>-1) is entered by typing sqrt(5)-1 (ans = 1.2361)

3. (frac <4>d^<2>) for (d=2) is entered by typing pi/4*2^2 (ans = 3.1416)

Calculate the following exponential and logarithmic quantities:

MATLAB inputs and outputs are as follows:

Calculate the following trigonometric quantities:

MATLAB inputs and outputs are as follows:


JavaScript

We always (Yes, always&mdashlaziness breeds poor security in our world) want to take a look at anything a user gives us before we interact with it. This is for two reasons: first, the user may have made a mistake. Maybe they mistyped an email address, or left a required field blank. Or, perhaps, the user is a malicious person or script attempting to do something other than what we intend with access to our site. It might be using our forms to spam others, gain access to our data, or make unsolicited changes to our site. We already discussed this under PHP but we can attack the problem with JavaScript too.

Taking this into account, before we use anything a user gave us, we need to make sure (as much as possible) that it is safe data to interact with. Usually we want to do as much of this as possible on the user (or client) side, so they do not need to click submit and wait for a response from the server to find out something is not quite right. To do this, we can use client-side scripting like JavaScript to make sure things are OK as we progress. As fields are changed, JavaScript can look at the content and make sure addresses are formatted correctly, required fields are filled in, etc. Coloring, highlighting, or providing messages to the user when problems occur. We can achieve this easily by tapping into jQuery&rsquos validation library:

  1. <script src="/lib/js/jquery.validate.js"></script>
  2. <script>
  3. $(document).ready(function() <$("#commentForm").validate(
  4. cname :
  5. )>
  6. )
  7. </script>

This example would execute the validation once the form is loaded, showing that the cname field is required and the minimum length is two characters. Not only can jQuery help us display these requirements on the form itself, we can call the validator as fields are changed and/or when the form is submitted before leaving the page to enforce the rules we provided.

In terms of user experience, this is typically done in real time. As soon as a user leaves a field, the script makes sure it is OK, and provides confirmation of the fact (typically a green highlighting or &ldquoOK!&rdquo type of marker) or by not marking the field as bad (typically red, or prompting the user to re-enter the field).

Once the form is completed, JavaScript should ensure that the user&rsquos submission will be good on the first try (at least content-wise&mdashwe cannot confirm things like a username and password without talking to the server). This accounts for our number one concern: mistakes from the user. Even though we checked the submission, we want to repeat this process on the server-side in more depth. If the user is malicious they may be circumventing our page, or the user may have JavaScript disabled.

The server-side script should take into account the nefarious user. If someone tried to subvert our form, JavaScript probably caught it. If, however, we are using GET or they use a script to send data directly to our action page from our form (which they can easily find in our page source) then they can get around our JavaScript.


19.5 Function arguments

The arguments to a function typically fall into two broad sets: one set supplies the data to compute on, and the other supplies arguments that control the details of the computation. For example:

In log() , the data is x , and the detail is the base of the logarithm.

In mean() , the data is x , and the details are how much data to trim from the ends ( trim ) and how to handle missing values ( na.rm ).

In t.test() , the data are x and y , and the details of the test are alternative , mu , paired , var.equal , and conf.level .

In str_c() you can supply any number of strings to . , and the details of the concatenation are controlled by sep and collapse .

Generally, data arguments should come first. Detail arguments should go on the end, and usually should have default values. You specify a default value in the same way you call a function with a named argument:

The default value should almost always be the most common value. The few exceptions to this rule are to do with safety. For example, it makes sense for na.rm to default to FALSE because missing values are important. Even though na.rm = TRUE is what you usually put in your code, it’s a bad idea to silently ignore missing values by default.

When you call a function, you typically omit the names of the data arguments, because they are used so commonly. If you override the default value of a detail argument, you should use the full name:

You can refer to an argument by its unique prefix (e.g. mean(x, n = TRUE) ), but this is generally best avoided given the possibilities for confusion.

Notice that when you call a function, you should place a space around = in function calls, and always put a space after a comma, not before (just like in regular English). Using whitespace makes it easier to skim the function for the important components.

19.5.1 Choosing names

The names of the arguments are also important. R doesn’t care, but the readers of your code (including future-you!) will. Generally you should prefer longer, more descriptive names, but there are a handful of very common, very short names. It’s worth memorising these:

  • x , y , z : vectors.
  • w : a vector of weights.
  • df : a data frame.
  • i , j : numeric indices (typically rows and columns).
  • n : length, or number of rows.
  • p : number of columns.

Otherwise, consider matching names of arguments in existing R functions. For example, use na.rm to determine if missing values should be removed.

19.5.2 Checking values

As you start to write more functions, you’ll eventually get to the point where you don’t remember exactly how your function works. At this point it’s easy to call your function with invalid inputs. To avoid this problem, it’s often useful to make constraints explicit. For example, imagine you’ve written some functions for computing weighted summary statistics:

What happens if x and w are not the same length?

In this case, because of R’s vector recycling rules, we don’t get an error.

It’s good practice to check important preconditions, and throw an error (with stop() ), if they are not true:

Be careful not to take this too far. There’s a tradeoff between how much time you spend making your function robust, versus how long you spend writing it. For example, if you also added a na.rm argument, I probably wouldn’t check it carefully:

This is a lot of extra work for little additional gain. A useful compromise is the built-in stopifnot() : it checks that each argument is TRUE , and produces a generic error message if not.

Note that when using stopifnot() you assert what should be true rather than checking for what might be wrong.

19.5.3 Dot-dot-dot (…)

Many functions in R take an arbitrary number of inputs:

How do these functions work? They rely on a special argument: . (pronounced dot-dot-dot). This special argument captures any number of arguments that aren’t otherwise matched.

It’s useful because you can then send those . on to another function. This is a useful catch-all if your function primarily wraps another function. For example, I commonly create these helper functions that wrap around str_c() :

Here . lets me forward on any arguments that I don’t want to deal with to str_c() . It’s a very convenient technique. But it does come at a price: any misspelled arguments will not raise an error. This makes it easy for typos to go unnoticed:

If you just want to capture the values of the . , use list(. ) .

19.5.4 Lazy evaluation

Arguments in R are lazily evaluated: they’re not computed until they’re needed. That means if they’re never used, they’re never called. This is an important property of R as a programming language, but is generally not important when you’re writing your own functions for data analysis. You can read more about lazy evaluation at http://adv-r.had.co.nz/Functions.html#lazy-evaluation.

19.5.5 Exercises

What does commas(letters, collapse = "-") do? Why?

It’d be nice if you could supply multiple characters to the pad argument, e.g. rule("Title", pad = "-+") . Why doesn’t this currently work? How could you fix it?

What does the trim argument to mean() do? When might you use it?

The default value for the method argument to cor() is c("pearson", "kendall", "spearman") . What does that mean? What value is used by default?


Introducing CloudFront Functions – Run Your Code at the Edge with Low Latency at Any Scale

With Amazon CloudFront, you can securely deliver data, videos, applications, and APIs to your customers globally with low latency and high transfer speeds. To offer a customized experience and the lowest possible latency, many modern applications execute some form of logic at the edge. The use cases for applying logic at the edge can be grouped together in two main categories:

  • First are the complex, compute-heavy operations that are executed when objects are not in the cache. We [email protected] in 2017 to offer a fully programmable, serverless edge computing environment for implementing a wide variety of complex customizations. [email protected] functions are executed in a regional edge cache (usually in the AWS region closest to the CloudFront edge location reached by the client). For example, when you’re streaming video or audio, you can use [email protected] to create and serve the right segments on-the-fly reducing the need for origin scalability. Another common use case is to use [email protected] and Amazon DynamoDB to translate shortened, user-friendly URLs to full URL landing pages.
  • The second category of use cases are simple HTTP(s) request/response manipulations that can be executed by very short-lived functions. For these use cases, you need a flexible programming experience with the performance, scale, and cost-effectiveness that enable you to execute them on every request.

To help you with this second category of use cases, I am happy to announce the availability of CloudFront Functions, a new serverless scripting platform that allows you to run lightweight JavaScript code at the 218+ CloudFront edge locations at approximately 1/6th the price of [email protected]

CloudFront Functions are ideal for lightweight processing of web requests, for example:

  • Cache-key manipulations and normalization: Transform HTTP request attributes (such as URL, headers, cookies, and query strings) to construct the cache-key, which is the unique identifier for objects in cache and is used to determine whether an object is already cached. For example, you could cache based on a header that contains the end user’s device type, creating two different versions of the content for mobile and desktop users. By transforming the request attributes, you can also normalize multiple requests to a single cache-key entry and significantly improve your cache-hit ratio.
  • URL rewrites and redirects: Generate a response to redirect requests to a different URL. For example, redirect a non-authenticated user from a restricted page to a login form. URL rewrites can also be used for A/B testing.
  • HTTP header manipulation: View, add, modify, or delete any of the request/response headers. For instance, add HTTP Strict Transport Security (HSTS) headers to your response, or copy the client IP address into a new HTTP header so that it is forwarded to the origin with the request.
  • Access authorization: Implement access control and authorization for the content delivered through CloudFront by creating and validating user-generated tokens, such as HMAC tokens or JSON web tokens (JWT), to allow/deny requests.

To give you the performance and scale that modern applications require, CloudFront Functions uses a new process-based isolation model instead of virtual machine (VM)-based isolation as used by AWS Lambda and [email protected] To do that, we had to enforce some restrictions, such as avoiding network and file system access. Also, functions run for less than one millisecond. In this way, they can handle millions of requests per second while giving you great performance on every function execution. Functions add almost no perceptible impact to overall content delivery network (CDN) performance.

Similar to [email protected], CloudFront Functions runs your code in response to events generated by CloudFront. More specifically, CloudFront Functions can be triggered after CloudFront receives a request from a viewer (viewer request) and before CloudFront forwards the response to the viewer (viewer response).

[email protected] can also be triggered before CloudFront forwards the request to the origin (origin request) and after CloudFront receives the response from the origin (origin response). You can use CloudFront Functions and [email protected] together, depending on whether you need to manipulate content before, or after, being cached.

If you need some of the capabilities of [email protected] that are not available with CloudFront Functions, such as network access or a longer execution time, you can still use [email protected] before and after content is cached by CloudFront.

To help you understand the difference between CloudFront Functions and [email protected], here’s a quick comparison:

CloudFront Functions [email protected]
Runtime support JavaScript
(ECMAScript 5.1 compliant)
Node.js, Python
Execution location 218+ CloudFront
Edge Locations
13 CloudFront
Regional Edge Caches
CloudFront triggers supported Viewer request
Viewer response
Viewer request
Viewer response
Origin request
Origin response
Maximum execution time Less than 1 millisecond 5 seconds (viewer triggers)
30 seconds (origin triggers)
Maximum memory 2MB 128MB (viewer triggers)
10GB (origin triggers)
Total package size 10 KB 1 MB (viewer triggers)
50 MB (origin triggers)
Network access No Yes
File system access No Yes
Access to the request body No Yes
Pricing Free tier available
charged per request
No free tier charged per request
and function duration

Let’s see how this works in practice.

Using CloudFront Functions From the Console
I want to customize the content of my website depending on the country of origin of the viewers. To do so, I use a CloudFront distribution that I created using an S3 bucket as origin. Then, I create a cache policy to include the CloudFront-Viewer-Country header (that contains the two-letter country code of the viewer’s country) in the cache key. CloudFront Functions can see CloudFront-generated headers (like the CloudFront geolocation or device detection headers) only if they are included in an origin policy or cache key policy.

In the CloudFront console, I select Functions on the left bar and then Create function. I give the function a name and Continue.

From here, I can follow the lifecycle of my function with these steps:

  1. Build the function by providing the code.
  2. Test the function with a sample payload.
  3. Publish the function from the development stage to the live stage.
  4. Associate the function with one or more CloudFront distributions.

1. In the Build tab, I can access two stages for each function: a Development stage for tests, and a Live stage that can be used by one or more CloudFront distributions. With the development stage selected, I type the code of my function and Save:

The function looks at the content of the CloudFront-Viewer-Country header set by CloudFront. If it contains one of the supported countries, and the URL does not already contain a country prefix, it adds the country at the beginning of the URL path. Otherwise, it lets the request pass through without changes.

2. In the Test tab, I select the event type (Viewer Request), the Stage (Development, for now) and a sample event.

Below, I can customize the Input event by selecting the HTTP method, and then editing the path of the URL, and optionally the client IP to use. I can also add custom headers, cookies, or query strings. In my case, I leave all the default values and add the CloudFront-Viewer-Country header with the value of FR (for France). Optionally, instead of using the visual editor, I can customize the input event by editing the JSON payload that is passed to the function.

I click on the Test button and look at the Output. As expected, the request is being redirected (HTTP status code 302 ). In the Response headers, I see that the location where the request is being redirected starts with /fr/ to provide custom content for viewers based in France. If something doesn’t go as expected in my tests, I can look at the Function Logs. I can also use console.log() in my code to add more debugging information.

In the Output, just above the HTTP status, I see the Compute utilization for this execution. Compute utilization is a number between 0 and 100 that indicates the amount of time that the function took to run as a percentage of the maximum allowed time. In my case, a compute utilization of 21 means that the function completed in 21% of the maximum allowed time.

3. I run more tests using different configurations of URL and headers, then I move to the Publish tab to copy the function from the development stage to the live stage. Now, the function is ready to be associated with an existing distribution.

4. In the Associate tab, I select the Distribution, the Event type (Viewer Request or Viewer Response) and the Cache behavior (I only have the Default (*) cache behavior for my distribution). I click Add association and confirm in the dialog.

Now, I see the function association at the bottom of the Associate tab.

To test this configuration from two different locations, I start two Amazon Elastic Compute Cloud (Amazon EC2) instances, one in the US East (N. Virginia) Region and one in the Europe (Paris) Region. I connect using SSH and use cURL to get an object from the CloudFront distribution. Previously, I have uploaded two objects to the S3 bucket that is used as the origin for the distribution: one, for customers based in France, using the fr/ prefix, and one, for customers not in a supported country, using the en/ prefix.

I list the two objects using the AWS Command Line Interface (CLI):

In the EC2 instance in the US East (N. Virginia) Region, I run this command to download the object:

Then I run the same command in the Europe (Paris) Region:

As expected, I am getting different results from the same URL. I am using the -L option so that cURL is following the redirect it receives. In this way, each command is executing two HTTP requests: the first request receives the HTTP redirect from the CloudFront function, the second request follows the redirect and is not modified by the function because it contains a custom path in the URL ( /en/ or /fr/ ).

To see the actual location of the redirect and all HTTP response headers, I use cURL with the -i option. These are the response headers for the EC2 instance running in the US the function is executed at an edge location in Virginia:

And these are the response headers for the EC2 instance running in France this time, the function is executed in an edge location near Paris:

Availability and Pricing
CloudFront Functions is available today and you can use it with new and existing distributions. You can use CloudFront Functions with the AWS Management Console, AWS Command Line Interface (CLI), AWS SDKs, and AWS CloudFormation. With CloudFront Functions, you pay by the number of invocations. You can get started with CloudFront Functions for free as part of the AWS Free Usage Tier. For more information, please see the CloudFront pricing page.

AWS for the Edge
Amazon CloudFront and AWS edge networking capabilities are part of the AWS for the Edge portfolio. AWS edge services improve performance by moving compute, data processing, and storage closer to end-user devices. This includes deploying AWS managed services, APIs, and tools to locations outside AWS data centers, and even onto customer-owned infrastructure and devices.

AWS offers you a consistent experience and portfolio of capabilities from the edge to the cloud. Using AWS, you have access to the broadest and deepest capabilities for edge use cases, like edge networking, hybrid architectures, connected devices, 5G, and multi-access edge computing.

Danilo Poccia

Danilo works with startups and companies of any size to support their innovation. In his role as Chief Evangelist (EMEA) at Amazon Web Services, he leverages his experience to help people bring their ideas to life, focusing on serverless architectures and event-driven programming, and on the technical and business impact of machine learning and edge computing. He is the author of AWS Lambda in Action from Manning.


PAC Functions

A browser supporting PAC provides access to a list of functions as defined in the original Netscape Specification.

Each browser implements PAC in a sandbox, allowing access to only those JavaScript functions required to operate and nothing more. As an example, it isn’t possible to access the browser user agent string in a PAC file, a string available to a normal web page.

The functions supported and allowed by the sandbox environment are documented on this page.

The Functions

Click the name of a function in order to view a description and code example(s).

DnsDomainIs

ShExpMatch

Will attempt to match hostname or URL to a specified shell expression, and returns true if matched.

IsInNet

This function evaluates the IP address of a hostname, and if within a specified subnet returns true. If a hostname is passed the function will resolve the hostname to an IP address.

MyIpAddress

Returns the IP address of the host machine.

DnsResolve

Resolves hostnames to an IP address. This function can be used to reduce the number of DNS lookups, e.g. below example.

IsPlainHostName

LocalHostOrDomainIs

Evaluates hostname and only returns true if exact hostname match is found.

IsResolvable

Attempts to resolve a hostname to an IP address and returns true if successful. WARNING – This may cause a browser to temporarily hang if a domain isn’t resolvable.

DnsDomainLevels

This function returns the number of DNS domain levels (number of dots) in the hostname. Can be used to exception internal websites which use short DNS names, e.g. http://intranet

WeekdayRange

Allows rules to be time based, e.g. only return a proxy during specific days.

DateRange

Allows rules to be time based, e.g. only return a proxy during specific months.

TimeRange

Allows rules to be time based, e.g. only return a proxy during specific hours.

Alert

The alert() function is not specified in the original PAC specification, although support was previously supported in several browsers, useful for outputting the value of a variable or result of a function in a manner that is viewable by the end-user and leveraged for troubleshooting PAC file rule issues.

This function is now considered unsupported and non-functional in PAC files.


Scenarios

In many cases, a function integrates with an array of cloud services to provide feature-rich implementations.

The following are a common, but by no means exhaustive, set of scenarios for Azure Functions.

If you want to. then.
Build a web API Implement an endpoint for your web applications using the HTTP trigger
Process file uploads Run code when a file is uploaded or changed in blob storage
Build a serverless workflow Chain a series of functions together using durable functions
Respond to database changes Run custom logic when a document is created or updated in Cosmos DB
Run scheduled tasks Execute code at set times
Create reliable message queue systems Process message queues using Queue Storage, Service Bus, or Event Hubs
Analyze IoT data streams Collect and process data from IoT devices
Process data in real time Use Functions and SignalR to respond to data in the moment

As you build your functions, you have the following options and resources available:

Use your preferred language: Write functions in C#, Java, JavaScript, PowerShell, or Python, or use a custom handler to use virtually any other language.

Automate deployment: From a tools-based approach to using external pipelines, there's a myriad of deployment options available.

Troubleshoot a function: Use monitoring tools and testing strategies to gain insights into your apps.

Flexible pricing options: With the Consumption plan, you only pay while your functions are running, while the Premium and App Service plans offer features for specialized needs.


5.1 Linear Equations and Functions - PowerPoint PPT Presentation

PowerShow.com is a leading presentation/slideshow sharing website. Whether your application is business, how-to, education, medicine, school, church, sales, marketing, online training or just for fun, PowerShow.com is a great resource. And, best of all, most of its cool features are free and easy to use.

You can use PowerShow.com to find and download example online PowerPoint ppt presentations on just about any topic you can imagine so you can learn how to improve your own slides and presentations for free. Or use it to find and download high-quality how-to PowerPoint ppt presentations with illustrated or animated slides that will teach you how to do something new, also for free. Or use it to upload your own PowerPoint slides so you can share them with your teachers, class, students, bosses, employees, customers, potential investors or the world. Or use it to create really cool photo slideshows - with 2D and 3D transitions, animation, and your choice of music - that you can share with your Facebook friends or Google+ circles. That's all free as well!

For a small fee you can get the industry's best online privacy or publicly promote your presentations and slide shows with top rankings. But aside from that it's free. We'll even convert your presentations and slide shows into the universal Flash format with all their original multimedia glory, including animation, 2D and 3D transition effects, embedded music or other audio, or even video embedded in slides. All for free. Most of the presentations and slideshows on PowerShow.com are free to view, many are even free to download. (You can choose whether to allow people to download your original PowerPoint presentations and photo slideshows for a fee or free or not at all.) Check out PowerShow.com today - for FREE. There is truly something for everyone!

presentations for free. Or use it to find and download high-quality how-to PowerPoint ppt presentations with illustrated or animated slides that will teach you how to do something new, also for free. Or use it to upload your own PowerPoint slides so you can share them with your teachers, class, students, bosses, employees, customers, potential investors or the world. Or use it to create really cool photo slideshows - with 2D and 3D transitions, animation, and your choice of music - that you can share with your Facebook friends or Google+ circles. That's all free as well!


Watch the video: BBL1303 Introduction to Christology (December 2021).