├── .gitignore ├── bin └── 7za.exe ├── assets ├── drop.ico ├── null.bmp ├── drop_banner.bmp └── screenshot.png ├── sign.bat ├── src ├── ErlangInstall.iss ├── ElixirInstall.iss ├── TErlangData.iss ├── TElixirRelease.iss ├── Path.iss └── Util.iss ├── README.md ├── Elixir.iss ├── ElixirWeb.iss └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /elixir 2 | /Output 3 | -------------------------------------------------------------------------------- /bin/7za.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elixir-lang/elixir-windows-setup/HEAD/bin/7za.exe -------------------------------------------------------------------------------- /assets/drop.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elixir-lang/elixir-windows-setup/HEAD/assets/drop.ico -------------------------------------------------------------------------------- /assets/null.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elixir-lang/elixir-windows-setup/HEAD/assets/null.bmp -------------------------------------------------------------------------------- /assets/drop_banner.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elixir-lang/elixir-windows-setup/HEAD/assets/drop_banner.bmp -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elixir-lang/elixir-windows-setup/HEAD/assets/screenshot.png -------------------------------------------------------------------------------- /sign.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | "C:\Program Files (x86)\Windows Kits\10\bin\x64\signtool.exe" sign /debug /sha1 5D61459775F965DA92630DEEAD3946EF5F9EA02C Output\elixir-websetup.exe 3 | pause 4 | -------------------------------------------------------------------------------- /src/ErlangInstall.iss: -------------------------------------------------------------------------------- 1 | // ErlangInstall.iss - Functions relating to existing installations of Erlang 2 | // Copyright (c) Chris Hyndman 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | [Code] 17 | 18 | // Given a Boolean where true -> 64bit and false -> 32bit, returns 19 | // the path of the latest Erlang installation of that architecture 20 | function GetLatestErlangPathOfArch(Of64Bit: Boolean): String; 21 | var 22 | ERTSVersions: TArrayOfString; 23 | SubKeyName: String; 24 | begin 25 | Result := ''; 26 | 27 | if Of64Bit then begin 28 | SubKeyName := 'SOFTWARE\Wow6432Node\Ericsson\Erlang'; 29 | end else begin 30 | SubKeyName := 'SOFTWARE\Ericsson\Erlang'; 31 | end; 32 | 33 | if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, SubKeyName, ERTSVersions) then begin 34 | if GetArrayLength(ERTSVersions) <> 0 then 35 | RegQueryStringValue(HKEY_LOCAL_MACHINE, SubKeyName + '\' + GetLatestVersion(ERTSVersions), '', Result); 36 | end; 37 | end; 38 | 39 | // Returns the path of the latest Erlang installation, preferring 40 | // 64-bit over 32-bit 41 | function GetLatestErlangPath: String; 42 | begin 43 | Result := ''; 44 | if IsWin64 then 45 | Result := GetLatestErlangPathOfArch(True); 46 | if Result = '' then 47 | Result := GetLatestErlangPathOfArch(False); 48 | end; 49 | -------------------------------------------------------------------------------- /src/ElixirInstall.iss: -------------------------------------------------------------------------------- 1 | // ElixirInstall.iss - Functions relating to existing installations of Elixir 2 | // Copyright (c) Chris Hyndman 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | [Code] 17 | 18 | function GetPreviousUninsExe: String; 19 | var 20 | UninsPath: String; 21 | begin 22 | UninsPath := ''; 23 | Result := ''; 24 | if RegQueryStringValue(HKLM, 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Elixir_is1', 'UninstallString', UninsPath) then begin 25 | Result := RemoveQuotes(UninsPath); 26 | end else if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Elixir_is1', 'UninstallString', UninsPath) then begin 27 | Result := RemoveQuotes(UninsPath); 28 | end else if RegQueryStringValue(HKCU, 'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Elixir_is1', 'UninstallString', UninsPath) then begin 29 | Result := RemoveQuotes(UninsPath); 30 | end else if RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\Elixir_is1', 'UninstallString', UninsPath) then begin 31 | Result := RemoveQuotes(UninsPath); 32 | end; 33 | end; 34 | 35 | function GetPreviousAppPath: String; 36 | begin 37 | Result := RemoveBackslashUnlessRoot(ExtractFilePath(GetPreviousUninsExe)); 38 | end; 39 | 40 | function CheckPreviousVersionExists: Boolean; 41 | begin 42 | Result := (GetPreviousUninsExe <> ''); 43 | end; 44 | -------------------------------------------------------------------------------- /src/TErlangData.iss: -------------------------------------------------------------------------------- 1 | // TErlangData.iss - TErlangData and related functions 2 | // Copyright (c) Chris Hyndman 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | [Code] 17 | 18 | type 19 | TErlangData = record 20 | OTPVersion: String; 21 | ERTSVersion: String; 22 | URL32: String; 23 | URL64: String; 24 | Exe32: String; 25 | Exe64: String; 26 | Name32: String; 27 | Name64: String; 28 | end; 29 | 30 | // Given a filename to an erlang.csv file, returns the latest OTP release in 31 | // the file as a TErlangData record 32 | function CSVToErlangData(Filename: String): TErlangData; 33 | var 34 | Rows: TArrayOfString; 35 | RowValues: TStrings; 36 | begin 37 | if LoadStringsFromFile(Filename, Rows) then begin 38 | RowValues := SplitString(Rows[1], ','); 39 | 40 | with Result do begin 41 | OTPVersion := RowValues[0]; 42 | ERTSVersion := RowValues[1]; 43 | URL32 := RowValues[2]; 44 | URL64 := RowValues[3]; 45 | 46 | Exe32 := GetURLFilePart(URL32); 47 | Exe64 := GetURLFilePart(URL64); 48 | Name32 := 'OTP ' + OTPVersion + ' (32-bit)'; 49 | Name64 := 'OTP ' + OTPVersion + ' (64-bit)'; 50 | end; 51 | end else begin 52 | with Result do begin 53 | OTPVersion := ''; 54 | ERTSVersion := ''; 55 | URL32 := ''; 56 | URL64 := ''; 57 | 58 | Exe32 := ''; 59 | Exe64 := ''; 60 | Name32 := ''; 61 | Name64 := ''; 62 | end; 63 | end; 64 | end; 65 | -------------------------------------------------------------------------------- /src/TElixirRelease.iss: -------------------------------------------------------------------------------- 1 | // TElixirRelease.iss - TElixirRelease and related functions 2 | // Copyright (c) Chris Hyndman 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | [Code] 17 | 18 | type 19 | TElixirRelease = record 20 | Version: String; 21 | URL: String; 22 | ReleaseType: String; 23 | end; 24 | 25 | // Given a filename to an elixir.csv file, return an array of Elixir releases corresponding to 26 | // the data in the csv file. 27 | function CSVToElixirReleases(Filename: String): array of TElixirRelease; 28 | var 29 | Rows: TArrayOfString; 30 | RowValues: TStrings; 31 | i: Integer; 32 | begin 33 | // Read the file at Filename and store the lines in Rows 34 | if LoadStringsFromFile(Filename, Rows) then begin 35 | // Match length of return array to number of rows 36 | SetArrayLength(Result, GetArrayLength(Rows) - 1); 37 | 38 | for i := 1 to GetArrayLength(Rows) - 1 do begin 39 | // Separate values at commas 40 | RowValues := SplitString(Rows[i], ','); 41 | 42 | with Result[i - 1] do begin 43 | // Store first and second values as the Version and URL respectively 44 | Version := RowValues[0]; 45 | URL := RowValues[1]; 46 | 47 | // Store release type unless incompatible with installer 48 | if StrToInt(RowValues[3]) = {#COMPAT_MASK} then begin 49 | ReleaseType := RowValues[2]; 50 | end else begin 51 | ReleaseType := 'incompatible'; 52 | end; 53 | end; 54 | end; 55 | end else begin 56 | SetArrayLength(Result, 0); 57 | end; 58 | end; 59 | -------------------------------------------------------------------------------- /src/Path.iss: -------------------------------------------------------------------------------- 1 | // Path.iss - Manipulate the PATH variable 2 | // Copyright (c) Chris Hyndman 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | [Code] 17 | 18 | const 19 | PathVarRegRoot = HKEY_LOCAL_MACHINE; 20 | PathVarRegPath = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; 21 | 22 | function ContainsPath(Dir: String): Boolean; 23 | var 24 | RegValue: String; 25 | begin 26 | Result := False; 27 | if Dir <> '' then begin 28 | RegQueryStringValue(PathVarRegRoot, PathVarRegPath, 'Path', RegValue); 29 | if Pos(Dir, RegValue) <> 0 then 30 | Result := True; 31 | end; 32 | end; 33 | 34 | // Given a directory path, appends the directory to the system's Path environment variable, 35 | // if it doesn't already exist 36 | procedure AppendPath(Dir: String); 37 | var 38 | RegValue: String; 39 | begin 40 | if Dir <> '' then begin 41 | RegQueryStringValue(PathVarRegRoot, PathVarRegPath, 'Path', RegValue); 42 | if Pos(Dir, RegValue) = 0 then begin 43 | RegWriteStringValue(PathVarRegRoot, PathVarRegPath, 'Path', RegValue + ';' + Dir); 44 | end; 45 | end; 46 | end; 47 | 48 | // Given a directory path, deletes the directory from the system's Path environment variable, 49 | // if it exists 50 | procedure DeletePath(Dir: String); 51 | var 52 | RegValue: String; 53 | DirIdx: Integer; 54 | begin 55 | if Dir <> '' then begin 56 | RegQueryStringValue(PathVarRegRoot, PathVarRegPath, 'Path', RegValue); 57 | DirIdx := Pos(Dir, RegValue); 58 | if DirIdx <> 0 then begin 59 | if DirIdx = 1 then begin 60 | Delete(RegValue, 1, Length(Dir) + 1); 61 | end else begin 62 | Delete(RegValue, DirIdx - 1, Length(Dir) + 1); 63 | end; 64 | RegWriteStringValue(PathVarRegRoot, PathVarRegPath, 'Path', RegValue); 65 | end; 66 | end; 67 | end; 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elixir-windows-setup 2 | 3 | > From version v1.15, Elixir now provides pre-compiled and offline installers for Windows per Erlang/OTP version. See [the official website](https://elixir-lang.org/) for all up to date install instructions. 4 | 5 | ![elixir-websetup](assets/screenshot.png) 6 | 7 | ## Features 8 | 9 | * Downloads and installs the latest Elixir version, or another version the user selects 10 | * Offers to install Erlang and add the Erlang directory to the system's Path variable 11 | * Adds Elixir to the system's Path variable 12 | * Creates Start Menu shortcuts 13 | 14 | ## Structure 15 | 16 | The **offline installer** ([Elixir.iss](Elixir.iss)) packages a specific Elixir release to install, and also can append the system's Path variable appropriately. This kind of installer is currently not distributed in binary form. 17 | 18 | The **web installer** ([ElixirWeb.iss](ElixirWeb.iss)) is what's currently distributed (see [Releases](https://github.com/chyndman/elixir-windows-setup/releases)). The **web installer** itself does not install Elixir. It packages the files necessary to download, compile, and run the **offline installer** for the selected Elixir release. It also handles installing Erlang and adding it to the system's Path variable. 19 | 20 | ### Offline Installation 21 | 22 | If you need to install Elixir on a system without internet access, follow these steps: 23 | 24 | 1. Install Erlang on to the system. 25 | 2. On another system with internet access, run `elixir-websetup.exe`. 26 | 3. When prompted, check the box for "Defer installation (advanced)" and uncheck all other options. 27 | 4. Proceed with the installation wizard. Once complete, `elixir-vX.Y.Z-setup.exe` will be placed in the same folder as `elixir-websetup.exe`. 28 | 5. Use `elixir-vX.Y.Z-setup.exe` to install Elixir on to the system. (Note: You may wish to uninstall previous versions of Elixir before doing this.) 29 | 30 | ## Build Instructions 31 | 32 | First, download the Unicode version of Inno Setup (`isetup-X.Y.Z-unicode.exe` from [jrsoftware.org](http://www.jrsoftware.org/isdl.php#stable)) and install it, making sure to keep the "Install Inno Setup Preprocessor" checkbox checked when asked. Then, clone this repo (`elixir-windows-setup`) to your system. 33 | 34 | To build the **web installer**, open `elixir-windows-setup\ElixirWeb.iss` in the Inno Setup Compiler and click "Compile" to build an installer in `elixir-windows-setup\Output`. 35 | 36 | To build the **offline installer** follow these steps: 37 | 38 | 1. Extract Precompiled.zip of the desired [Elixir Release](https://github.com/elixir-lang/elixir/releases/) into `elixir-windows-setup\elixir` 39 | 2. Open `elixir-windows-setup\Elixir.iss` in the Inno Setup Compiler. 40 | 3. Click "Compile" to build an installer in `elixir-windows-setup\Output`. 41 | 42 | ## Acknowledgements 43 | 44 | #### [Inno Setup](http://www.jrsoftware.org/isinfo.php) 45 | Copyright (C) 1997-2013 Jordan Russell. All rights reserved. 46 | Portions Copyright (C) 2000-2013 Martijn Laan. All rights reserved. 47 | 48 | #### [7-Zip](http://www.7-zip.org/) 49 | Copyright (C) 1999-2010 Igor Pavlov 50 | 51 | #### [Elixir](http://elixir-lang.org/) 52 | "Elixir" and the Elixir logo are copyright (c) 2012 Plataformatec. 53 | -------------------------------------------------------------------------------- /src/Util.iss: -------------------------------------------------------------------------------- 1 | // Util.iss - Useful helper functions 2 | // Copyright (c) Chris Hyndman 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | [Code] 17 | 18 | // Wrapper function for returning a path relative to {tmp} 19 | function Tmp(Path: String): String; 20 | begin 21 | Result := ExpandConstant('{tmp}\') + Path; 22 | end; 23 | 24 | // Recursive function called by SplitString 25 | function SplitStringRec(Str: String; Delim: String; StrList: TStringList): TStringList; 26 | var 27 | StrHead: String; 28 | StrTail: String; 29 | DelimPos: Integer; 30 | begin 31 | DelimPos := Pos(Delim, Str); 32 | if DelimPos = 0 then begin 33 | StrList.Add(Str); 34 | Result := StrList; 35 | end else begin 36 | StrHead := Str; 37 | StrTail := Str; 38 | 39 | Delete(StrHead, DelimPos, Length(StrTail)); 40 | Delete(StrTail, 1, DelimPos); 41 | 42 | StrList.Add(StrHead); 43 | Result := SplitStringRec(StrTail, Delim, StrList); 44 | end; 45 | end; 46 | 47 | // Given a string and a delimiter, returns the strings separated by the delimiter 48 | // as a TStringList object 49 | function SplitString(Str: String; Delim: String): TStringList; 50 | begin 51 | Result := SplitStringRec(Str, Delim, TStringList.Create); 52 | end; 53 | 54 | // Recursive function called by GetURLFilePart 55 | function GetURLFilePartRec(URL: String): String; 56 | var 57 | SlashPos: Integer; 58 | begin 59 | SlashPos := Pos('/', URL); 60 | if SlashPos = 0 then begin 61 | Result := URL; 62 | end else begin; 63 | Delete(URL, 1, SlashPos); 64 | Result := GetURLFilePartRec(URL); 65 | end; 66 | end; 67 | 68 | // Given a URL to a file, returns the filename portion of the URL 69 | function GetURLFilePart(URL: String): String; 70 | begin 71 | Delete(URL, 1, Pos('://', URL) + 2); 72 | Result := GetURLFilePartRec(URL); 73 | end; 74 | 75 | // Given two software version strings (ex. '1.5.0'), returns: 76 | // 1 if the second version is later than the first 77 | // -1 if the second version is earlier than the first 78 | // 0 if equivalent 79 | function CompareVersions(VerL, VerR: String): Integer; 80 | var 81 | VerLExplode: TStrings; 82 | VerRExplode: TStrings; 83 | i: Integer; 84 | MinCount: Integer; 85 | begin 86 | Result := 0; 87 | VerLExplode := SplitString(VerL, '.'); 88 | VerRExplode := SplitString(VerR, '.'); 89 | 90 | if VerLExplode.Count < VerRExplode.Count then begin 91 | MinCount := VerLExplode.Count; 92 | end else begin 93 | MinCount := VerRExplode.Count; 94 | end; 95 | 96 | for i := 0 to MinCount - 1 do begin 97 | if StrToIntDef(VerLExplode[i], 0) < StrToIntDef(VerRExplode[i], 0) then begin 98 | Result := 1; 99 | exit; 100 | end else if StrToIntDef(VerLExplode[i], 0) > StrToIntDef(VerLExplode[i], 0) then begin 101 | Result := -1; 102 | exit; 103 | end; 104 | end; 105 | end; 106 | 107 | // Given an array of strings representing software versions, returns 108 | // the latest of those versions 109 | function GetLatestVersion(Versions: TArrayOfString): String; 110 | var 111 | i: Integer; 112 | begin 113 | Result := Versions[0]; 114 | for i := 0 to GetArrayLength(Versions) - 1 do begin 115 | if CompareVersions(Result, Versions[i]) = 1 then 116 | Result := Versions[i]; 117 | end; 118 | end; 119 | -------------------------------------------------------------------------------- /Elixir.iss: -------------------------------------------------------------------------------- 1 | ; Elixir.iss - Elixir "Offline" Installer 2 | ; Copyright (c) Chris Hyndman 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | ; "Elixir" and the Elixir logo are copyright (c) 2012 Plataformatec. 17 | 18 | ; Determine version of Elixir from elixir\VERSION 19 | #ifndef ElixirVersion 20 | #if FileExists('elixir\VERSION') 21 | #define VersionFileHandle = FileOpen('elixir\VERSION') 22 | #define ElixirVersion = FileRead(VersionFileHandle) 23 | #expr FileClose(VersionFileHandle) 24 | #else 25 | #error elixir\VERSION not found 26 | #endif 27 | #endif 28 | 29 | #define ELIXIR_PATH '{app}\bin' 30 | #define ESCRIPT_PATH '%USERPROFILE%\.mix\escripts' 31 | 32 | [Setup] 33 | AppName=Elixir 34 | AppPublisherURL=http://elixir-lang.org/ 35 | AppVersion={#ElixirVersion} 36 | ChangesEnvironment=yes 37 | DefaultDirName={pf}\Elixir 38 | DefaultGroupName=Elixir 39 | OutputBaseFilename=elixir-v{#ElixirVersion}-setup 40 | AllowNoIcons=yes 41 | 42 | #ifdef SkipWelcome 43 | DisableWelcomePage=yes 44 | #else 45 | DisableWelcomePage=no 46 | #endif 47 | 48 | ; Web installer: no need to compress, since the installer is built directly on the machine 49 | #ifdef NoCompression 50 | Compression=none 51 | #endif 52 | 53 | ; Visual 54 | SetupIconFile=assets\drop.ico 55 | WizardImageFile=assets\drop_banner.bmp 56 | WizardSmallImageFile=assets\null.bmp 57 | UninstallDisplayIcon={app}\drop.ico 58 | 59 | [Files] 60 | Source: "assets\drop.ico"; DestDir: "{app}" 61 | Source: "elixir\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs 62 | 63 | [Icons] 64 | Name: "{group}\Elixir"; Filename: "{code:GetScriptString|ErlangBinPath}\werl.exe"; WorkingDir: "%userprofile%"; IconFilename: "{app}\drop.ico"; IconIndex: 0; Parameters: "-env ERL_LIBS ""{app}\lib"" -user Elixir.IEx.CLI -extra --no-halt" 65 | 66 | [Tasks] 67 | Name: erlangpath; Description: "Append {code:GetScriptString|ErlangBinPath} to system PATH"; Check: CheckToAppendErlangPath 68 | Name: elixirpath; Description: "Append {#ELIXIR_PATH} to system PATH"; Check: CheckToAppendElixirPath 69 | Name: escriptpath; Description: "Append {#ESCRIPT_PATH} to system PATH"; Check: CheckToAppendEscriptPath 70 | 71 | [Code] 72 | #include "src\Util.iss" 73 | #include "src\Path.iss" 74 | #include "src\ErlangInstall.iss" 75 | 76 | var 77 | GlobalPageErlangDir: TInputDirWizardPage; 78 | 79 | function GetScriptString(Param: String): String; 80 | begin 81 | Result := ''; 82 | if Param = 'ErlangBinPath' then 83 | Result := GlobalPageErlangDir.Values[0] + '\bin'; 84 | end; 85 | 86 | procedure CurStepChanged(CurStep: TSetupStep); 87 | begin 88 | if CurStep = ssPostInstall then begin 89 | if IsTaskSelected('erlangpath') then 90 | AppendPath(GetScriptString('ErlangBinPath')); 91 | if IsTaskSelected('elixirpath') then 92 | AppendPath(ExpandConstant('{#ELIXIR_PATH}')); 93 | if IsTaskSelected('escriptpath') then 94 | AppendPath(ExpandConstant('{#ESCRIPT_PATH}')); 95 | end; 96 | end; 97 | 98 | procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); 99 | var 100 | SelTaskString: String; 101 | begin 102 | if CurUninstallStep = usUninstall then begin 103 | SelTaskString := ''; 104 | RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\Elixir_is1', 'Inno Setup: Selected Tasks', SelTaskString); 105 | 106 | if Pos('elixirpath', SelTaskString) <> 0 then 107 | DeletePath(ExpandConstant('{#ELIXIR_PATH}')); 108 | 109 | if Pos('escriptpath', SelTaskString) <> 0 then 110 | DeletePath(ExpandConstant('{#ESCRIPT_PATH}')); 111 | end; 112 | end; 113 | 114 | procedure InitializeWizard(); 115 | begin 116 | GlobalPageErlangDir := CreateInputDirPage( 117 | wpWelcome, 118 | 'Confirm Erlang Directory', 119 | 'Confirm the location of your Erlang installation, then click Next.', 120 | 'Setup will configure Elixir to use the following Erlang installation path.', 121 | False, '' 122 | ); 123 | 124 | GlobalPageErlangDir.Add(''); 125 | GlobalPageErlangDir.Values[0] := GetLatestErlangPath(); 126 | end; 127 | 128 | function CheckToAppendErlangPath: Boolean; begin 129 | Result := not ContainsPath(GetScriptString('ErlangBinPath')); end; 130 | 131 | function CheckToAppendElixirPath: Boolean; begin 132 | Result := not ContainsPath(ExpandConstant('{#ELIXIR_PATH}')); end; 133 | 134 | function CheckToAppendEscriptPath: Boolean; begin 135 | Result := not ContainsPath(ExpandConstant('{#ESCRIPT_PATH}')); end; 136 | -------------------------------------------------------------------------------- /ElixirWeb.iss: -------------------------------------------------------------------------------- 1 | ; ElixirWeb.iss - Elixir Web Installer 2 | ; Copyright (c) Chris Hyndman 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | ; "Elixir" and the Elixir logo are copyright (c) 2012 Plataformatec. 17 | 18 | #define COMPAT_MASK 1 19 | #define ELIXIR_CSV_URL 'https://elixir-lang.org/elixir.csv' 20 | #define ERLANG_CSV_URL 'https://elixir-lang.org/erlang.csv' 21 | 22 | [Setup] 23 | AppName=Elixir 24 | AppVersion=2.4 25 | OutputBaseFilename=elixir-websetup 26 | SolidCompression=yes 27 | 28 | ; This installer doesn't install anything itself, it just runs other installers 29 | CreateAppDir=no 30 | Uninstallable=no 31 | 32 | ; The user will see the offline installer's finished page instead 33 | DisableFinishedPage=yes 34 | 35 | ; Visual 36 | SetupIconFile=assets\drop.ico 37 | WizardImageFile=assets\drop_banner.bmp 38 | WizardSmallImageFile=assets\null.bmp 39 | DisableWelcomePage=no 40 | 41 | [CustomMessages] 42 | ; The version string shouldn't show the version of this installer (AppVersion) 43 | NameAndVersion=%1 44 | 45 | [Files] 46 | ; Offline installer files 47 | Source: "Elixir.iss"; DestDir: "{tmp}"; Flags: deleteafterinstall 48 | Source: "assets\drop.ico"; DestDir: "{tmp}\assets"; Flags: deleteafterinstall 49 | Source: "assets\drop_banner.bmp"; DestDir: "{tmp}\assets"; Flags: deleteafterinstall 50 | Source: "assets\null.bmp"; DestDir: "{tmp}\assets"; Flags: deleteafterinstall 51 | Source: "src\Util.iss"; DestDir: "{tmp}\src"; Flags: deleteafterinstall 52 | Source: "src\Path.iss"; DestDir: "{tmp}\src"; Flags: deleteafterinstall 53 | Source: "src\ErlangInstall.iss"; DestDir: "{tmp}\src"; Flags: deleteafterinstall 54 | ; 7-Zip portable extractor 55 | Source: "bin\7za.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall 56 | ; Compiler files 57 | Source: "compiler:Default.isl"; DestDir: "{tmp}"; Flags: deleteafterinstall 58 | Source: "compiler:ISCC.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall 59 | Source: "compiler:ISCmplr.dll"; DestDir: "{tmp}"; Flags: deleteafterinstall 60 | Source: "compiler:islzma.dll"; DestDir: "{tmp}"; Flags: deleteafterinstall 61 | Source: "compiler:ISPP.dll"; DestDir: "{tmp}"; Flags: deleteafterinstall 62 | Source: "compiler:ISPPBuiltins.iss"; DestDir: "{tmp}"; Flags: deleteafterinstall 63 | Source: "compiler:Setup.e32"; DestDir: "{tmp}"; Flags: deleteafterinstall 64 | Source: "compiler:SetupLdr.e32"; DestDir: "{tmp}"; Flags: deleteafterinstall 65 | 66 | [Run] 67 | ; Run the Erlang installer if task is selected 68 | Filename: "{tmp}\{code:GetScriptString|ErlangExe32}"; Flags: hidewizard; StatusMsg: "Installing {code:GetScriptString|ErlangName32}..."; Tasks: erlang\32 69 | Filename: "{tmp}\{code:GetScriptString|ErlangExe64}"; Flags: hidewizard; StatusMsg: "Installing {code:GetScriptString|ErlangName64}..."; Tasks: erlang\64 70 | ; Extract the downloaded Precompiled.zip archive 71 | Filename: "{tmp}\7za.exe"; Parameters: "x -oelixir Precompiled.zip"; WorkingDir: "{tmp}"; StatusMsg: "Extracting Precompiled.zip archive..." 72 | ; Compile the offline installer 73 | Filename: "{tmp}\ISCC.exe"; Parameters: "/dSkipWelcome /dNoCompression Elixir.iss"; WorkingDir: "{tmp}"; StatusMsg: "Compiling Elixir installer..."; Tasks: not defer 74 | ; Use standard options for deferred install 75 | Filename: "{tmp}\ISCC.exe"; Parameters: "Elixir.iss"; WorkingDir: "{tmp}"; StatusMsg: "Compiling Elixir installer..."; Tasks: defer 76 | ; Run the offline installer 77 | Filename: "{tmp}\Output\elixir-v{code:GetScriptString|ElixirVersion}-setup.exe"; Flags: nowait postinstall; StatusMsg: "Starting Elixir installer..."; Tasks: not defer 78 | ; Or copy offline installer to same folder as web installer 79 | Filename: "Robocopy.exe"; Parameters: "{tmp}\Output {src} elixir-v{code:GetScriptString|ElixirVersion}-setup.exe /IS"; Tasks: defer 80 | 81 | [Tasks] 82 | Name: "unins_previous"; Description: "Uninstall previous version at {code:GetScriptString|ElixirPreviousPath} (Recommended)"; Check: CheckPreviousVersionExists 83 | Name: "erlang"; Description: "Install Erlang"; Flags: unchecked 84 | Name: "erlang\32"; Description: "{code:GetScriptString|ErlangName32}"; Flags: exclusive unchecked 85 | Name: "erlang\64"; Description: "{code:GetScriptString|ErlangName64}"; Flags: exclusive unchecked; Check: IsWin64 86 | Name: "defer"; Description: "Defer installation (advanced)"; Flags: unchecked 87 | 88 | [Code] 89 | #include "src\Util.iss" 90 | #include "src\Path.iss" 91 | #include "src\TErlangData.iss" 92 | #include "src\TElixirRelease.iss" 93 | #include "src\ErlangInstall.iss" 94 | #include "src\ElixirInstall.iss" 95 | 96 | var 97 | GlobalPageSelRelease: TInputOptionWizardPage; 98 | GlobalPageDownload: TDownloadWizardPage; 99 | 100 | GlobalElixirReleases: array of TElixirRelease; 101 | GlobalErlangData: TErlangData; 102 | 103 | GlobalElixirCSVFilePath: String; 104 | GlobalErlangCSVFilePath: String; 105 | 106 | CacheSelectedRelease: TElixirRelease; 107 | 108 | function GetScriptString(Param: String): String; 109 | begin 110 | Result := ''; 111 | 112 | case (Param) of 113 | 'ErlangExe32': Result := GlobalErlangData.Exe32; 114 | 'ErlangExe64': Result := GlobalErlangData.Exe64; 115 | 'ErlangName32': Result := GlobalErlangData.Name32; 116 | 'ErlangName64': Result := GlobalErlangData.Name64; 117 | 'ElixirVersion': Result := CacheSelectedRelease.Version; 118 | 'ElixirPreviousPath': Result := GetPreviousAppPath(); 119 | end; 120 | end; 121 | 122 | procedure CurPageChanged(CurPageID: Integer); 123 | var 124 | _int: Integer; 125 | begin 126 | if CurPageID = wpPreparing then begin 127 | // We're on the page after the "Ready To Install" page but before [Files] and [Run] are processed 128 | if WizardIsTaskSelected('unins_previous') then 129 | ExecAsOriginalUser(GetPreviousUninsExe, '/SILENT', '', SW_SHOW, ewWaitUntilTerminated, _int); 130 | end else if CurPageID = wpSelectTasks then begin 131 | if GetLatestErlangPath = '' then begin 132 | WizardSelectTasks('erlang'); 133 | if IsWin64 then begin 134 | WizardSelectTasks('erlang\64'); 135 | end; 136 | end; 137 | end; 138 | end; 139 | 140 | function NextButtonClick(CurPageID: Integer): Boolean; 141 | var 142 | i: Integer; 143 | begin 144 | Result := True; 145 | 146 | if CurPageID = GlobalPageSelRelease.ID then begin 147 | // Search for the selected release 148 | for i := 0 to GlobalPageSelRelease.CheckListBox.Items.Count - 1 do begin 149 | if GlobalPageSelRelease.CheckListBox.Checked[i] then begin 150 | CacheSelectedRelease := GlobalElixirReleases[i]; 151 | break; 152 | end; 153 | end; 154 | end else if CurPageID = wpReady then begin 155 | GlobalPageDownload.Clear; 156 | with GlobalErlangData do begin 157 | if WizardIsTaskSelected('erlang\32') then 158 | // 32-bit OTP needs to be downloaded before it's installed 159 | GlobalPageDownload.Add(URL32, Exe32, ''); 160 | if WizardIsTaskSelected('erlang\64') then 161 | // 64-bit OTP needs to be downloaded before it's installed 162 | GlobalPageDownload.Add(URL64, Exe64, ''); 163 | end; 164 | 165 | // Download the Precompiled.zip archive for the selected release 166 | GlobalPageDownload.Add(CacheSelectedRelease.URL, 'Precompiled.zip', ''); 167 | 168 | // Run page 169 | GlobalPageDownload.Show; 170 | try 171 | try 172 | GlobalPageDownload.Download; 173 | except 174 | MsgBox(GetExceptionMessage, mbCriticalError, MB_OK); 175 | Result := False; 176 | end 177 | finally 178 | GlobalPageDownload.Hide; 179 | end; 180 | end; 181 | end; 182 | 183 | procedure InitializeWizard(); 184 | var 185 | latest: Boolean; 186 | i: Integer; 187 | begin 188 | // Define the custom release selection page 189 | GlobalPageSelRelease := CreateInputOptionPage( 190 | wpWelcome, 191 | 'Select Elixir release', 192 | 'Setup will download and install the Elixir release you select.', 193 | 'All releases available to install are listed below, from newest to oldest.', 194 | True, True // (Use Radio Buttons), (Put them in a scrollable list box) 195 | ); 196 | 197 | latest := True; 198 | 199 | // Use the global Elixir release array to populate the custom Elixir release list box 200 | for i := 0 to GetArrayLength(GlobalElixirReleases) - 1 do begin 201 | with GlobalElixirReleases[i] do begin 202 | GlobalPageSelRelease.CheckListBox.AddRadioButton( 203 | 'Elixir version ' + Version, // Label next to radio button 204 | ReleaseType, // Label right-justified in list box 205 | 0, // All choices on the same level 206 | (latest) and (ReleaseType = 'release'), // Radio button selected by default if it's the latest release 207 | (ReleaseType <> 'incompatible'), // Incompatible releases can't be selected 208 | Nil 209 | ); 210 | 211 | if ReleaseType = 'release' then 212 | latest := False; 213 | end 214 | end; 215 | 216 | GlobalPageDownload := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), Nil); 217 | end; 218 | 219 | function InitializeSetup(): Boolean; 220 | begin 221 | Result := True; 222 | 223 | // Store the paths to elixir.csv, erlang.csv in global variables 224 | GlobalElixirCSVFilePath := Tmp(GetURLFilePart('{#ELIXIR_CSV_URL}')); 225 | GlobalErlangCSVFilePath := Tmp(GetURLFilePart('{#ERLANG_CSV_URL}')); 226 | 227 | // Download elixir.csv; show an error message and exit the installer if downloading fails 228 | try 229 | DownloadTemporaryFile('{#ELIXIR_CSV_URL}', GetURLFilePart('{#ELIXIR_CSV_URL}'), '', Nil); 230 | except 231 | MsgBox('{#ELIXIR_CSV_URL} - ' + GetExceptionMessage + '. Setup cannot continue.', mbInformation, MB_OK); 232 | Result := False; 233 | exit; 234 | end; 235 | // Download erlang.csv; show an error message and exit the installer if downloading fails 236 | try 237 | DownloadTemporaryFile('{#ERLANG_CSV_URL}', GetURLFilePart('{#ERLANG_CSV_URL}'), '', Nil); 238 | except 239 | MsgBox('{#ERLANG_CSV_URL} - ' + GetExceptionMessage + '. Setup cannot continue.', mbInformation, MB_OK); 240 | Result := False; 241 | exit; 242 | end; 243 | 244 | // Create an array of TElixirRelease records from elixir.csv and store them in a global variable 245 | GlobalElixirReleases := CSVToElixirReleases(GlobalElixirCSVFilePath); 246 | 247 | // Check if above didn't work 248 | if GetArrayLength(GlobalElixirReleases) = 0 then begin 249 | MsgBox('Error: Parsing {#ELIXIR_CSV_URL} failed. Setup cannot continue.', mbInformation, MB_OK); 250 | Result := False; 251 | exit; 252 | end; 253 | 254 | // Create an TErlangData from erlang.csv record and store it in a global variable 255 | GlobalErlangData := CSVToErlangData(GlobalErlangCSVFilePath); 256 | 257 | // Check if above didn't work 258 | if GlobalErlangData.OTPVersion = '' then begin 259 | MsgBox('Error: Parsing {#ERLANG_CSV_URL} failed. Setup cannot continue.', mbInformation, MB_OK); 260 | Result := False; 261 | exit; 262 | end; 263 | end; 264 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. --------------------------------------------------------------------------------